Merge in binpatch and use launcher

This commit is contained in:
Christian 2013-06-14 17:21:49 -04:00
parent 21240df8bc
commit 07a5efe612
23 changed files with 414 additions and 1103 deletions

View file

@ -15,8 +15,8 @@
<arg value="${mcp.home}" />
</exec>
<propertyfile file="fmlversion.properties">
<entry key="fmlbuild.build.number" type="int" value="${version.build}"/>
<entry key="fmlbuild.deobfuscation.hash" type="string" value="${deobf.checksum}"/>
<entry key="fmlbuild.build.number" type="int" value="${version.build}" />
<entry key="fmlbuild.deobfuscation.hash" type="string" value="${deobf.checksum}" />
</propertyfile>
</target>
@ -34,11 +34,11 @@
<os family="Windows" />
</condition>
<condition property="mcp.exists">
<available file="${mcp.home}/runtime/commands.py"/>
<available file="${mcp.home}/runtime/commands.py" />
</condition>
<condition property="signature.exists">
<available file="${env.JENKINS_HOME}/fmlsigned.properties" />
</condition>
<condition property="signature.exists">
<available file="${env.JENKINS_HOME}/fmlsigned.properties"/>
</condition>
<property name="mcp.obfoutput" location="${mcp.home}/reobf" />
<property name="client.mcp.obfoutput" location="${mcp.obfoutput}/minecraft" />
<property name="mcp.srcdir" location="${mcp.home}/src" />
@ -54,7 +54,7 @@
<condition property="version.build" value="${env.BUILD_NUMBER}" else="1">
<isset property="env.BUILD_NUMBER" />
</condition>
<available file="eclipse" property="eclipse.exists"/>
<available file="eclipse" property="eclipse.exists" />
</target>
<target name="makeversion" depends="buildenvsetup">
@ -89,19 +89,19 @@
<arg value="${mcp.home}/runtime/reobfuscate.py" />
</exec>
<fail message="Reobfuscation failed">
<condition>
<not>
<and>
<available file="${mcp.home}/temp/client.md5"/>
<available file="${mcp.home}/temp/client_reobf.md5"/>
</and>
</not>
</condition>
<condition>
<not>
<and>
<available file="${mcp.home}/temp/client.md5" />
<available file="${mcp.home}/temp/client_reobf.md5" />
</and>
</not>
</condition>
</fail>
<exec executable="${python.exe}" dir="${mcp.home}">
<arg value="${basedir}/generatechangedfilelist.py"/>
<arg value="${mcp.home}"/>
<arg value="${basedir}/difflist.txt"/>
<arg value="${basedir}/generatechangedfilelist.py" />
<arg value="${mcp.home}" />
<arg value="${basedir}/difflist.txt" />
</exec>
</target>
@ -110,11 +110,11 @@
<arg value="${mcp.home}/runtime/recompile.py" />
</exec>
<fail message="Compilation failed">
<condition>
<not>
<available file="${mcp.home}/bin/minecraft/net/minecraft/client/Minecraft.class"/>
</not>
</condition>
<condition>
<not>
<available file="${mcp.home}/bin/minecraft/net/minecraft/client/Minecraft.class" />
</not>
</condition>
</fail>
</target>
@ -140,19 +140,19 @@
<mkdir dir="${basedir}/target" />
<jar destfile="${basedir}/target/${universal.jarname}.zip" duplicate="preserve">
<manifest>
<attribute name="Main-Class" value="cpw.mods.fml.relauncher.ServerLaunchWrapper"/>
<attribute name="Class-Path" value="minecraft_server.jar:lib/guava-14.0-rc3.jar:lib/bcprov-jdk15on-148-src.zip:lib/asm-debug-all-4.1.jar:lib/scala-library.jar:lib/argo-3.2-src.jar"/>
<attribute name="Main-Class" value="cpw.mods.fml.relauncher.ServerLaunchWrapper" />
<attribute name="Class-Path" value="minecraft_server.jar:lib/guava-14.0-rc3.jar:lib/bcprov-jdk15on-148-src.zip:lib/asm-debug-all-4.1.jar:lib/scala-library.jar:lib/argo-3.2-src.jar" />
</manifest>
<fileset dir="${client.mcp.obfoutput}" includes="**/*.class" excludes="*.class"/>
<fileset dir="${client.mcp.obfoutput}" includes="**/*.class" excludes="*.class" />
</jar>
<antcall target="signjar"/>
<zip update="true" destfile="${basedir}/target/${universal.jarname}.zip" >
<fileset dir="${client.mcp.obfoutput}" includes="*.class"/>
<zipfileset dir="${basedir}" includes="fmlversion.properties"/>
<antcall target="signjar" />
<zip update="true" destfile="${basedir}/target/${universal.jarname}.zip">
<fileset dir="${client.mcp.obfoutput}" includes="*.class" />
<zipfileset dir="${basedir}" includes="fmlversion.properties" />
<zipfileset dir="${basedir}" includes="LICENSE-fml.txt" />
<zipfileset dir="${common.src.dir}" includes="mcpmod.info" />
<zipfileset dir="${client.src.dir}" includes="mcp.png" />
<zipfileset dir="${basedir}" includes="install/CREDITS-fml.txt" fullpath="CREDITS-fml.txt"/>
<zipfileset dir="${common.src.dir}" includes="mcpmod.info" />
<zipfileset dir="${client.src.dir}" includes="mcp.png" />
<zipfileset dir="${basedir}" includes="install/CREDITS-fml.txt" fullpath="CREDITS-fml.txt" />
<zipfileset dir="${common.src.dir}" includes="*.cfg" />
<mappedresources>
<concat>
@ -205,25 +205,25 @@
</target>
<target name="build-deobf-data" depends="makeversion">
<mkdir dir="build-tmp-deobf"/>
<mkdir dir="build-tmp-deobf" />
<copy todir="build-tmp-deobf">
<mappedresources>
<fileset dir="${mcp.home}/conf" includes="packaged.srg"/>
<globmapper from="packaged.srg" to="joined.srg"/>
<fileset dir="${mcp.home}/conf" includes="packaged.srg" />
<globmapper from="packaged.srg" to="joined.srg" />
</mappedresources>
</copy>
<touch millis="0" file="build-tmp-deobf/joined.srg"/>
<touch millis="0" file="build-tmp-deobf/joined.srg" />
<zip file="deobfuscation_data_${version.minecraft}.zip" encoding="UTF-8">
<fileset dir="build-tmp-deobf" includes="joined.srg"/>
<fileset dir="build-tmp-deobf" includes="joined.srg" />
</zip>
<checksum algorithm="SHA1" property="deobf.checksum" file="deobfuscation_data_${version.minecraft}.zip"/>
<antcall target="writeversion"/>
<checksum algorithm="SHA1" property="deobf.checksum" file="deobfuscation_data_${version.minecraft}.zip" />
<antcall target="writeversion" />
<delete dir="build-tmp-deobf" />
</target>
<target name="build" depends="buildenvsetup,merge-client,merge-common,build-deobf-data,build-universal,build-source-pack" />
<target name="jenkinsbuild" depends="buildenvsetup,jenkinsfmldecompile,patch,build"/>
<target name="jenkinsbuild" depends="buildenvsetup,jenkinsfmldecompile,patch,build" />
<target name="patch" depends="buildenvsetup">
<exec executable="${python.exe}" dir="${basedir}">
@ -242,25 +242,25 @@
</condition>
<fail if="do.not.continue">You have decided not to continue. This script will stop now.</fail>
<echo>Preparing the MCP environment at ${mcp.home}</echo>
<antcall target="fmldecompile"/>
<antcall target="fmldecompile" />
<echo>Moving old patched sources at ${patch.mcp.srcdir} out of the way</echo>
<move todir="${mcp.home}/src-work${timestamp}" failonerror="false" verbose="true">
<fileset dir="${patch.mcp.srcdir}"/>
<fileset dir="${patch.mcp.srcdir}" />
</move>
<echo>Deleting old patch references at ${clean.mcp.srcdir}</echo>
<delete dir="${clean.mcp.srcdir}" failonerror="false"/>
<delete dir="${clean.mcp.srcdir}" failonerror="false" />
<echo>Creating new patch references at ${clean.mcp.srcdir}</echo>
<copy todir="${clean.mcp.srcdir}">
<fileset dir="${mcp.srcdir}"/>
<fileset dir="${mcp.srcdir}" />
</copy>
<antcall target="cleanargo"/>
<antcall target="patch"/>
<antcall target="cleanargo" />
<antcall target="patch" />
<echo>Creating clean patched references at ${patch.mcp.srcdir}</echo>
<copy todir="${patch.mcp.srcdir}">
<fileset dir="${mcp.srcdir}"/>
<fileset dir="${mcp.srcdir}" />
</copy>
<antcall target="writeversion"/>
<antcall target="makeeclipse"/>
<antcall target="writeversion" />
<antcall target="makeeclipse" />
<echo>Setup complete! You should now be able to open ${basedir}/eclipse as a workspace in eclipse and import/refresh the FML project</echo>
</target>
@ -284,45 +284,45 @@
<target name="repatch" depends="buildenvsetup,checkpatches">
<echo>Moving old patched sources at ${mcp.home}/src-work out of the way</echo>
<move todir="${mcp.home}/src-work${timestamp}" failonerror="false" verbose="true">
<fileset dir="${patch.mcp.srcdir}"/>
<fileset dir="${patch.mcp.srcdir}" />
</move>
<delete dir="${mcp.srcdir}"/>
<delete dir="${mcp.srcdir}" />
<copy todir="${mcp.srcdir}">
<fileset dir="${clean.mcp.srcdir}"/>
<fileset dir="${clean.mcp.srcdir}" />
</copy>
<antcall target="cleanargo"/>
<antcall target="cleanargo" />
<antcall target="patch"/>
<antcall target="patch" />
<copy todir="${patch.mcp.srcdir}">
<fileset dir="${mcp.srcdir}"/>
<fileset dir="${mcp.srcdir}" />
</copy>
</target>
<target name="repatchclean" depends="buildenvsetup">
<delete dir="${mcp.srcdir}"/>
<delete dir="${mcp.srcdir}" />
<copy todir="${mcp.srcdir}">
<fileset dir="${clean.mcp.srcdir}"/>
<fileset dir="${clean.mcp.srcdir}" />
</copy>
<antcall target="cleanargo"/>
<antcall target="cleanargo" />
<antcall target="patch"/>
<antcall target="patch" />
</target>
<target name="cleanargo" depends="buildenvsetup">
<delete dir="${client.mcp.srcdir}/argo"/>
<delete dir="${client.mcp.srcdir}/org"/>
<delete dir="${client.mcp.srcdir}/argo" />
<delete dir="${client.mcp.srcdir}/org" />
</target>
<target name="checkpatches" depends="buildenvsetup">
<uptodate property="checkUptodate.uptodate">
<srcfiles dir="${patch.mcp.srcdir}" includes="**/*.java">
<present targetdir="${patch.src.dir}">
<globmapper from="*.java" to="*.java.patch"/>
<globmapper from="*.java" to="*.java.patch" />
</present>
</srcfiles>
<globmapper from="*.java" to="${patch.src.dir}/*.java.patch"/>
<globmapper from="*.java" to="${patch.src.dir}/*.java.patch" />
</uptodate>
<fail unless="checkUptodate.uptodate">
A patch is out of date. Update your patches!
@ -332,8 +332,8 @@
<target name="updatepatches" depends="buildenvsetup">
<exec executable="${python.exe}" dir="${basedir}">
<arg value="${basedir}/update_patches.py" />
<arg value="${mcp.home}"/>
<arg value="${basedir}"/>
<arg value="${mcp.home}" />
<arg value="${basedir}" />
</exec>
</target>
@ -341,30 +341,43 @@
<echo>
Extracting fresh eclipse workspace to ${basedir}/eclipse
</echo>
<unzip src="${basedir}/eclipse-workspace-dev.zip" dest="${basedir}"/>
<unzip src="${basedir}/eclipse-workspace-dev.zip" dest="${basedir}" />
</target>
<target name="makerenamedsource" depends="buildenvsetup,repatch,merge-client,merge-common,reobfuscate">
<copy todir="${tmp.mcp.srcdir}">
<fileset dir="${mcp.srcdir}"/>
<fileset dir="${mcp.srcdir}" />
</copy>
<exec executable="${python.exe}" dir="${mcp.home}">
<arg value="${mcp.home}/runtime/updatenames.py" />
<arg value="-f" />
</exec>
<copy todir="${renamed.mcp.srcdir}">
<fileset dir="${mcp.srcdir}"/>
<fileset dir="${mcp.srcdir}" />
</copy>
<move todir="${mcp.srcdir}">
<fileset dir="${tmp.mcp.srcdir}"/>
<fileset dir="${tmp.mcp.srcdir}" />
</move>
</target>
<target name="signjar" depends="buildenvsetup,makeversion" if="signature.exists">
<condition property="universal.jarname" value="${modname}-universal-${version.minecraft}-${version}" else="${modname}-universal-${version.minecraft}-${version}-${version.branch}">
<equals arg1="${version.branch}" arg2="master" />
</condition>
<property file="${env.JENKINS_HOME}/fmlsigned.properties" prefix="sign"/>
<echo>${env.JENKINS_HOME} ${universal.jarname} ${sign.KEYPASS}</echo>
<signjar alias="FML" jar="${basedir}/target/${universal.jarname}.zip" keypass="${sign.KEYPASS}" keystore="${env.JENKINS_HOME}/${sign.KEYSTORE}" storepass="${sign.STOREPASS}" verbose="true"/>
<property file="${env.JENKINS_HOME}/fmlsigned.properties" prefix="sign" />
<echo>${env.JENKINS_HOME} ${universal.jarname} ${sign.KEYPASS}</echo>
<signjar alias="FML" jar="${basedir}/target/${universal.jarname}.zip" keypass="${sign.KEYPASS}" keystore="${env.JENKINS_HOME}/${sign.KEYSTORE}" storepass="${sign.STOREPASS}" verbose="true" />
</target>
<target name="makebinpatches">
<java classname="cpw.mods.fml.patcher.GenDiffSet">
<classpath>
<fileset dir="${mcp.home}/lib" includes="guava-14.0-rc3.jar"/>
<dirset dir="${mcp.obfoutput}"/>
</classpath>
<arg path="${mcp.home}/jars/bin/minecraft.jar.backup"/>
<arg path="${mcp.home}/jars/bin/minecraft.jar.backup"/>
<arg path="${mcp.obfoutput}"/>
<arg path="${basedir}/deobfuscation_data_${version.minecraft}.zip"/>
<arg path="${basedir}/binpatch/client"/>
</java>
</target>
</project>

View file

@ -20,12 +20,13 @@ import java.net.URLClassLoader;
import java.util.List;
import java.util.logging.Level;
import net.minecraft.launchwrapper.LaunchClassLoader;
import com.google.common.collect.ImmutableList;
import cpw.mods.fml.common.asm.ASMTransformer;
import cpw.mods.fml.common.asm.transformers.AccessTransformer;
import cpw.mods.fml.common.modloader.BaseModProxy;
import cpw.mods.fml.relauncher.RelaunchClassLoader;
/**
* A simple delegating class loader used to load mods into the system
@ -37,11 +38,11 @@ import cpw.mods.fml.relauncher.RelaunchClassLoader;
public class ModClassLoader extends URLClassLoader
{
private static final List<String> STANDARD_LIBRARIES = ImmutableList.of("jinput.jar", "lwjgl.jar", "lwjgl_util.jar");
private RelaunchClassLoader mainClassLoader;
private LaunchClassLoader mainClassLoader;
public ModClassLoader(ClassLoader parent) {
super(new URL[0], null);
this.mainClassLoader = (RelaunchClassLoader)parent;
this.mainClassLoader = (LaunchClassLoader)parent;
}
public void addFile(File modFile) throws MalformedURLException

View file

@ -35,6 +35,8 @@ import java.util.Map;
import javax.swing.JOptionPane;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
@ -43,10 +45,9 @@ import org.objectweb.asm.Opcodes;
import cpw.mods.fml.common.CertificateHelper;
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
import cpw.mods.fml.common.patcher.ClassPatchManager;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
import cpw.mods.fml.relauncher.FMLRelaunchLog;
import cpw.mods.fml.relauncher.FMLRelauncher;
import cpw.mods.fml.relauncher.IFMLCallHook;
import cpw.mods.fml.relauncher.RelaunchClassLoader;
public class FMLSanityChecker implements IFMLCallHook
{
@ -71,7 +72,7 @@ public class FMLSanityChecker implements IFMLCallHook
}
}
private RelaunchClassLoader cl;
private LaunchClassLoader cl;
@Override
public Void call() throws Exception
@ -140,12 +141,11 @@ public class FMLSanityChecker implements IFMLCallHook
@Override
public void injectData(Map<String, Object> data)
{
cl = (RelaunchClassLoader) data.get("classLoader");
cl = (LaunchClassLoader) data.get("classLoader");
File mcDir = (File)data.get("mcLocation");
FMLDeobfuscatingRemapper.INSTANCE.setup(mcDir, cl, (String) data.get("deobfuscationFileName"));
File binpatches = new File(mcDir,"binpatch");
File side = new File(binpatches,FMLRelauncher.side().toLowerCase(Locale.ENGLISH));
ClassPatchManager.INSTANCE.setup(side);
ClassPatchManager.INSTANCE.setup(FMLLaunchHandler.side(), getClass().getProtectionDomain().getCodeSource());
}
}

View file

@ -23,13 +23,13 @@ import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;
import cpw.mods.fml.relauncher.FMLRelauncher;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
import cpw.mods.fml.relauncher.IClassTransformer;
import cpw.mods.fml.relauncher.SideOnly;
public class SideTransformer implements IClassTransformer
{
private static String SIDE = FMLRelauncher.side();
private static String SIDE = FMLLaunchHandler.side().name();
private static final boolean DEBUG = false;
@SuppressWarnings("unchecked")
@Override

View file

@ -26,6 +26,8 @@ import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.commons.Remapper;
@ -49,7 +51,6 @@ import com.google.common.io.InputSupplier;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.relauncher.FMLRelaunchLog;
import cpw.mods.fml.relauncher.RelaunchClassLoader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
@ -65,7 +66,7 @@ public class FMLDeobfuscatingRemapper extends Remapper {
private Map<String,Map<String,String>> fieldNameMaps;
private Map<String,Map<String,String>> methodNameMaps;
private RelaunchClassLoader classLoader;
private LaunchClassLoader classLoader;
private FMLDeobfuscatingRemapper()
{
@ -124,7 +125,7 @@ public class FMLDeobfuscatingRemapper extends Remapper {
fieldNameMaps = Maps.newHashMapWithExpectedSize(rawFieldMaps.size());
}
public void setup(File mcDir, RelaunchClassLoader classLoader, String deobfFileName)
public void setup(File mcDir, LaunchClassLoader classLoader, String deobfFileName)
{
this.classLoader = classLoader;
try

View file

@ -27,7 +27,7 @@ import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.LoaderException;
import cpw.mods.fml.common.ModClassLoader;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.relauncher.RelaunchLibraryManager;
import cpw.mods.fml.relauncher.CoreModManager;
public class ModDiscoverer
{
@ -41,7 +41,7 @@ public class ModDiscoverer
public void findClasspathMods(ModClassLoader modClassLoader)
{
List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries()).addAll(RelaunchLibraryManager.getLibraries()).build();
List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries()).addAll(CoreModManager.getLibraries()).build();
File[] minecraftSources = modClassLoader.getParentSources();
if (minecraftSources.length == 1 && minecraftSources[0].isFile())
{

View file

@ -0,0 +1,18 @@
package cpw.mods.fml.common.launcher;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
import net.minecraft.launchwrapper.LaunchClassLoader;
public class FMLServerTweaker extends FMLTweaker {
@Override
public String getLaunchTarget()
{
return "net.minecraft.server.MinecraftServer";
}
@Override
public void injectIntoClassLoader(LaunchClassLoader classLoader)
{
FMLLaunchHandler.configureForServerLaunch(classLoader, this);
}
}

View file

@ -0,0 +1,49 @@
package cpw.mods.fml.common.launcher;
import java.io.File;
import java.util.List;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
import net.minecraft.launchwrapper.ITweaker;
import net.minecraft.launchwrapper.LaunchClassLoader;
public class FMLTweaker implements ITweaker {
private List<String> args;
private File gameDir;
private File assetsDir;
private String profile;
@Override
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile)
{
this.args = args;
this.gameDir = gameDir;
this.assetsDir = assetsDir;
this.profile = profile;
}
@Override
public void injectIntoClassLoader(LaunchClassLoader classLoader)
{
FMLLaunchHandler.configureForClientLaunch(classLoader, this);
}
@Override
public String getLaunchTarget()
{
return "net.minecraft.client.Minecraft";
}
@Override
public String[] getLaunchArguments()
{
return args.toArray(new String[args.size()]);
}
public File getGameDir()
{
return gameDir;
}
}

View file

@ -3,9 +3,19 @@ package cpw.mods.fml.common.patcher;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.CodeSource;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.regex.Pattern;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.io.ByteArrayDataInput;
@ -13,6 +23,8 @@ import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.relauncher.FMLRelaunchLog;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.repackage.com.nothome.delta.GDiffPatcher;
public class ClassPatchManager {
@ -67,48 +79,59 @@ public class ClassPatchManager {
return inputData;
}
public void setup(File dirToScan)
public void setup(Side side, CodeSource fmlLib)
{
File[] patchFiles = dirToScan.listFiles(new FilenameFilter()
Pattern binpatchMatcher = Pattern.compile(String.format("binpatch/%s/*.binpatch", side.toString().toLowerCase(Locale.ENGLISH)));
JarFile fmlJar;
try
{
@Override
public boolean accept(File dir, String name)
{
return Files.getFileExtension(new File(dir,name).getPath()).equals("binpatch");
}
});
if (patchFiles == null)
{
return;
File fmlJarFile = new File(fmlLib.getLocation().toURI());
fmlJar = new JarFile(fmlJarFile);
}
catch (Exception e)
{
FMLRelaunchLog.log(Level.SEVERE, e, "Error occurred reading binary patches. Problems may occur");
throw Throwables.propagate(e);
}
patches = ArrayListMultimap.create();
for (File patch : patchFiles)
for (JarEntry entry : Collections.list(fmlJar.entries()))
{
FMLLog.finest("Reading patch data from %s", patch.getAbsolutePath());
ByteArrayDataInput input;
try
if (binpatchMatcher.matcher(entry.getName()).matches())
{
input = ByteStreams.newDataInput(Files.toByteArray(patch));
ClassPatch cp = readPatch(entry, fmlJar);
if (cp != null)
{
patches.put(cp.sourceClassName, cp);
}
}
catch (IOException e)
{
FMLLog.log(Level.WARNING, e, "Unable to read binpatch file %s - ignoring", patch.getAbsolutePath());
continue;
}
String name = input.readUTF();
String sourceClassName = input.readUTF();
String targetClassName = input.readUTF();
boolean exists = input.readBoolean();
int patchLength = input.readInt();
byte[] patchBytes = new byte[patchLength];
input.readFully(patchBytes);
ClassPatch cp = new ClassPatch(name, sourceClassName, targetClassName, exists, patchBytes);
patches.put(sourceClassName, cp);
}
FMLLog.fine("Read %d binary patches from %s", patches.size(), fmlJar.getName());
FMLLog.fine("Patch list :\n\t%s", Joiner.on("\t\n").join(patches.asMap().entrySet()));
}
FMLLog.fine("Read %d binary patches from %s", patches.size(), dirToScan.getAbsolutePath());
FMLLog.fine("Patch list : %s", patches);
private ClassPatch readPatch(JarEntry patchEntry, JarFile jarFile)
{
FMLLog.finest("Reading patch data from %s in file %s", patchEntry.getName(), jarFile.getName());
ByteArrayDataInput input;
try
{
input = ByteStreams.newDataInput(ByteStreams.toByteArray(jarFile.getInputStream(patchEntry)));
}
catch (IOException e)
{
FMLLog.log(Level.WARNING, e, "Unable to read binpatch file %s - ignoring", patchEntry.getName());
return null;
}
String name = input.readUTF();
String sourceClassName = input.readUTF();
String targetClassName = input.readUTF();
boolean exists = input.readBoolean();
int patchLength = input.readInt();
byte[] patchBytes = new byte[patchLength];
input.readFully(patchBytes);
return new ClassPatch(name, sourceClassName, targetClassName, exists, patchBytes);
}
}

View file

@ -1,23 +0,0 @@
/*
* Forge Mod Loader
* Copyright (c) 2012-2013 cpw.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* cpw - implementation
*/
package cpw.mods.fml.relauncher;
public class ArgsWrapper
{
public ArgsWrapper(String[] args)
{
this.args=args;
}
public String[] args;
}

View file

@ -37,11 +37,13 @@ import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.logging.Level;
import net.minecraft.launchwrapper.LaunchClassLoader;
import cpw.mods.fml.common.CertificateHelper;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions;
public class RelaunchLibraryManager
public class CoreModManager
{
private static String[] rootPlugins = { "cpw.mods.fml.relauncher.FMLCorePlugin" , "net.minecraftforge.classloading.FMLForgePlugin" };
private static List<String> loadedLibraries = new ArrayList<String>();
@ -50,12 +52,12 @@ public class RelaunchLibraryManager
private static List<ILibrarySet> libraries;
private static boolean deobfuscatedEnvironment;
public static void handleLaunch(File mcDir, RelaunchClassLoader actualClassLoader)
public static void handleLaunch(File mcDir, LaunchClassLoader classLoader)
{
try
{
// Are we in a 'decompiled' environment?
byte[] bs = actualClassLoader.getClassBytes("net.minecraft.world.World");
byte[] bs = classLoader.getClassBytes("net.minecraft.world.World");
if (bs != null)
{
FMLRelaunchLog.info("Managed to load a deobfuscated Minecraft name- we are in a deobfuscated environment. Skipping runtime deobfuscation");
@ -72,17 +74,12 @@ public class RelaunchLibraryManager
}
pluginLocations = new HashMap<IFMLLoadingPlugin, File>();
loadPlugins = new ArrayList<IFMLLoadingPlugin>();
libraries = new ArrayList<ILibrarySet>();
for (String s : rootPlugins)
{
try
{
IFMLLoadingPlugin plugin = (IFMLLoadingPlugin) Class.forName(s, true, actualClassLoader).newInstance();
IFMLLoadingPlugin plugin = (IFMLLoadingPlugin) Class.forName(s, true, classLoader).newInstance();
loadPlugins.add(plugin);
for (String libName : plugin.getLibraryRequestClass())
{
libraries.add((ILibrarySet) Class.forName(libName, true, actualClassLoader).newInstance());
}
}
catch (Exception e)
{
@ -107,14 +104,14 @@ public class RelaunchLibraryManager
FMLRelaunchLog.info("Found a command line coremod : %s", s);
try
{
actualClassLoader.addTransformerExclusion(s);
Class<?> coreModClass = Class.forName(s, true, actualClassLoader);
classLoader.addTransformerExclusion(s);
Class<?> coreModClass = Class.forName(s, true, classLoader);
TransformerExclusions trExclusions = coreModClass.getAnnotation(IFMLLoadingPlugin.TransformerExclusions.class);
if (trExclusions!=null)
{
for (String st : trExclusions.value())
{
actualClassLoader.addTransformerExclusion(st);
classLoader.addTransformerExclusion(st);
}
}
IFMLLoadingPlugin plugin = (IFMLLoadingPlugin) coreModClass.newInstance();
@ -123,7 +120,7 @@ public class RelaunchLibraryManager
{
for (String libName : plugin.getLibraryRequestClass())
{
libraries.add((ILibrarySet) Class.forName(libName, true, actualClassLoader).newInstance());
libraries.add((ILibrarySet) Class.forName(libName, true, classLoader).newInstance());
}
}
}
@ -133,7 +130,7 @@ public class RelaunchLibraryManager
throw new RuntimeException(e);
}
}
discoverCoreMods(mcDir, actualClassLoader, loadPlugins, libraries);
discoverCoreMods(mcDir, classLoader, loadPlugins, libraries);
List<Throwable> caughtErrors = new ArrayList<Throwable>();
try
@ -213,7 +210,7 @@ public class RelaunchLibraryManager
try
{
actualClassLoader.addURL(libFile.toURI().toURL());
classLoader.addURL(libFile.toURI().toURL());
loadedLibraries.add(libName);
}
catch (MalformedURLException e)
@ -268,14 +265,14 @@ public class RelaunchLibraryManager
{
for (String xformClass : plug.getASMTransformerClass())
{
actualClassLoader.registerTransformer(xformClass);
classLoader.registerTransformer(xformClass);
}
}
}
// Deobfuscation transformer, always last
if (!deobfuscatedEnvironment)
{
actualClassLoader.registerTransformer("cpw.mods.fml.common.asm.transformers.DeobfuscationTransformer");
classLoader.registerTransformer("cpw.mods.fml.common.asm.transformers.DeobfuscationTransformer");
}
downloadMonitor.updateProgressString("Running coremod plugins");
Map<String,Object> data = new HashMap<String,Object>();
@ -292,10 +289,10 @@ public class RelaunchLibraryManager
{
try
{
IFMLCallHook call = (IFMLCallHook) Class.forName(setupClass, true, actualClassLoader).newInstance();
IFMLCallHook call = (IFMLCallHook) Class.forName(setupClass, true, classLoader).newInstance();
Map<String,Object> callData = new HashMap<String, Object>();
callData.put("mcLocation", mcDir);
callData.put("classLoader", actualClassLoader);
callData.put("classLoader", classLoader);
callData.put("coremodLocation", pluginLocations.get(plugin));
callData.put("deobfuscationFileName", FMLInjectionData.debfuscationDataName());
call.injectData(callData);
@ -317,7 +314,7 @@ public class RelaunchLibraryManager
try
{
downloadMonitor.updateProgressString("Validating minecraft");
Class<?> loaderClazz = Class.forName("cpw.mods.fml.common.Loader", true, actualClassLoader);
Class<?> loaderClazz = Class.forName("cpw.mods.fml.common.Loader", true, classLoader);
Method m = loaderClazz.getMethod("injectData", Object[].class);
m.invoke(null, (Object)FMLInjectionData.data());
m = loaderClazz.getMethod("instance");
@ -333,7 +330,7 @@ public class RelaunchLibraryManager
}
}
private static void discoverCoreMods(File mcDir, RelaunchClassLoader classLoader, List<IFMLLoadingPlugin> loadPlugins, List<ILibrarySet> libraries)
private static void discoverCoreMods(File mcDir, LaunchClassLoader classLoader, List<IFMLLoadingPlugin> loadPlugins, List<ILibrarySet> libraries)
{
downloadMonitor.updateProgressString("Discovering coremods");
File coreMods = setupCoreModDir(mcDir);

View file

@ -20,6 +20,8 @@ import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import net.minecraft.launchwrapper.LaunchClassLoader;
public class FMLInjectionData
{
static File minecraftHome;
@ -33,7 +35,7 @@ public class FMLInjectionData
public static List<String> containers = new ArrayList<String>();
static void build(File mcHome, RelaunchClassLoader classLoader)
static void build(File mcHome, LaunchClassLoader classLoader)
{
minecraftHome = mcHome;
InputStream stream = classLoader.getResourceAsStream("fmlversion.properties");

View file

@ -0,0 +1,116 @@
/*
* Forge Mod Loader
* Copyright (c) 2012-2013 cpw.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* cpw - implementation
*/
package cpw.mods.fml.relauncher;
import java.applet.Applet;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import com.google.common.base.Throwables;
import cpw.mods.fml.common.launcher.FMLTweaker;
import net.minecraft.launchwrapper.LaunchClassLoader;
public class FMLLaunchHandler
{
private static FMLLaunchHandler INSTANCE;
static Side side;
private LaunchClassLoader classLoader;
private FMLTweaker tweaker;
private File minecraftHome;
public static void configureForClientLaunch(LaunchClassLoader loader, FMLTweaker tweaker)
{
instance(loader, tweaker).setupClient();
}
public static void configureForServerLaunch(LaunchClassLoader loader, FMLTweaker tweaker)
{
instance(loader, tweaker).setupServer();
}
private static FMLLaunchHandler instance(LaunchClassLoader launchLoader, FMLTweaker tweaker)
{
if (INSTANCE == null)
{
INSTANCE = new FMLLaunchHandler(launchLoader, tweaker);
}
return INSTANCE;
}
private FMLLaunchHandler(LaunchClassLoader launchLoader, FMLTweaker tweaker)
{
this.classLoader = launchLoader;
this.tweaker = tweaker;
this.minecraftHome = tweaker.getGameDir();
this.classLoader.addClassLoaderExclusion("cpw.mods.fml.relauncher.");
this.classLoader.addClassLoaderExclusion("net.minecraftforge.classloading.");
this.classLoader.addTransformerExclusion("cpw.mods.fml.common.asm.transformers.deobf.");
this.classLoader.addTransformerExclusion("cpw.mods.fml.common.patcher.");
}
private void showWindow(boolean showIt)
{
if (CoreModManager.downloadMonitor != null) { return; }
CoreModManager.downloadMonitor = new DummyDownloader();
}
private void setupClient()
{
showWindow(true);
FMLRelaunchLog.logFileNamePattern = "ForgeModLoader-client-%g.log";
side = Side.CLIENT;
setupHome();
}
private void setupServer()
{
showWindow(false);
FMLRelaunchLog.logFileNamePattern = "ForgeModLoader-server-%g.log";
side = Side.SERVER;
setupHome();
}
private void setupHome()
{
FMLInjectionData.build(minecraftHome, classLoader);
FMLRelaunchLog.minecraftHome = minecraftHome;
FMLRelaunchLog.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft %s loading", FMLInjectionData.major, FMLInjectionData.minor,
FMLInjectionData.rev, FMLInjectionData.build, FMLInjectionData.mccversion, FMLInjectionData.mcpversion);
FMLRelaunchLog.info("Java is %s, version %s, running on %s:%s:%s, installed at %s", System.getProperty("java.vm.name"), System.getProperty("java.version"), System.getProperty("os.name"), System.getProperty("os.arch"), System.getProperty("os.version"), System.getProperty("java.home"));
FMLRelaunchLog.fine("Java classpath at launch is %s", System.getProperty("java.class.path"));
FMLRelaunchLog.fine("Java library path at launch is %s", System.getProperty("java.library.path"));
try
{
CoreModManager.handleLaunch(minecraftHome, classLoader);
}
catch (Throwable t)
{
FMLRelaunchLog.severe("An error occurred trying to configure the minecraft home at %s for Forge Mod Loader", minecraftHome.getAbsolutePath());
throw Throwables.propagate(t);
}
}
public static Side side()
{
return side;
}
}

View file

@ -148,6 +148,8 @@ public class FMLRelaunchLog
private static FMLLogFormatter formatter;
static String logFileNamePattern;
private FMLRelaunchLog()
{
}
@ -174,7 +176,7 @@ public class FMLRelaunchLog
formatter = new FMLLogFormatter();
try
{
File logPath = new File(minecraftHome, FMLRelauncher.logFileNamePattern);
File logPath = new File(minecraftHome, logFileNamePattern);
fileHandler = new FileHandler(logPath.getPath(), 0, 3)
{
public synchronized void close() throws SecurityException {

View file

@ -1,335 +0,0 @@
/*
* Forge Mod Loader
* Copyright (c) 2012-2013 cpw.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* cpw - implementation
*/
package cpw.mods.fml.relauncher;
import java.applet.Applet;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
public class FMLRelauncher
{
private static FMLRelauncher INSTANCE;
public static String logFileNamePattern;
static String side;
private RelaunchClassLoader classLoader;
private Object newApplet;
private Class<? super Object> appletClass;
JDialog popupWindow;
public static void handleClientRelaunch(ArgsWrapper wrap)
{
logFileNamePattern = "ForgeModLoader-client-%g.log";
side = "CLIENT";
instance().relaunchClient(wrap);
}
public static void handleServerRelaunch(ArgsWrapper wrap)
{
logFileNamePattern = "ForgeModLoader-server-%g.log";
side = "SERVER";
instance().relaunchServer(wrap);
}
static FMLRelauncher instance()
{
if (INSTANCE == null)
{
INSTANCE = new FMLRelauncher();
}
return INSTANCE;
}
private FMLRelauncher()
{
URLClassLoader ucl = (URLClassLoader) getClass().getClassLoader();
classLoader = new RelaunchClassLoader(ucl.getURLs());
}
private void showWindow(boolean showIt)
{
if (RelaunchLibraryManager.downloadMonitor != null) { return; }
try
{
if (showIt)
{
RelaunchLibraryManager.downloadMonitor = new Downloader();
popupWindow = (JDialog) RelaunchLibraryManager.downloadMonitor.makeDialog();
}
else
{
RelaunchLibraryManager.downloadMonitor = new DummyDownloader();
}
}
catch (Throwable e)
{
if (RelaunchLibraryManager.downloadMonitor == null)
{
RelaunchLibraryManager.downloadMonitor = new DummyDownloader();
e.printStackTrace();
}
else
{
RelaunchLibraryManager.downloadMonitor.makeHeadless();
}
popupWindow = null;
}
}
private void relaunchClient(ArgsWrapper wrap)
{
showWindow(true);
// Now we re-inject the home into the "new" minecraft under our control
Class<? super Object> client;
try
{
File minecraftHome = computeExistingClientHome();
setupHome(minecraftHome);
client = setupNewClientHome(minecraftHome);
}
finally
{
if (popupWindow != null)
{
popupWindow.setVisible(false);
popupWindow.dispose();
}
}
if (RelaunchLibraryManager.downloadMonitor.shouldStopIt())
{
System.exit(1);
}
try
{
ReflectionHelper.findMethod(client, null, new String[] { "fmlReentry" }, ArgsWrapper.class).invoke(null, wrap);
}
catch (Exception e)
{
e.printStackTrace();
// Hmmm
}
}
private Class<? super Object> setupNewClientHome(File minecraftHome)
{
Class<? super Object> client = ReflectionHelper.getClass(classLoader, "net.minecraft.client.Minecraft");
ReflectionHelper.setPrivateValue(client, null, minecraftHome,
"field_" + "71463_am" /*Separate that so that MCP's updatenames does not replace it*/,
"an", "minecraftDir");
return client;
}
private void relaunchServer(ArgsWrapper wrap)
{
showWindow(false);
// Now we re-inject the home into the "new" minecraft under our control
Class<? super Object> server;
File minecraftHome = new File(".");
setupHome(minecraftHome);
server = ReflectionHelper.getClass(classLoader, "net.minecraft.server.MinecraftServer");
try
{
ReflectionHelper.findMethod(server, null, new String[] { "fmlReentry" }, ArgsWrapper.class).invoke(null, wrap);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void setupHome(File minecraftHome)
{
FMLInjectionData.build(minecraftHome, classLoader);
FMLRelaunchLog.minecraftHome = minecraftHome;
FMLRelaunchLog.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft %s loading", FMLInjectionData.major, FMLInjectionData.minor,
FMLInjectionData.rev, FMLInjectionData.build, FMLInjectionData.mccversion, FMLInjectionData.mcpversion);
FMLRelaunchLog.info("Java is %s, version %s, running on %s:%s:%s, installed at %s", System.getProperty("java.vm.name"), System.getProperty("java.version"), System.getProperty("os.name"), System.getProperty("os.arch"), System.getProperty("os.version"), System.getProperty("java.home"));
FMLRelaunchLog.fine("Java classpath at launch is %s", System.getProperty("java.class.path"));
FMLRelaunchLog.fine("Java library path at launch is %s", System.getProperty("java.library.path"));
try
{
RelaunchLibraryManager.handleLaunch(minecraftHome, classLoader);
}
catch (Throwable t)
{
if (popupWindow != null)
{
try
{
String logFile = new File(minecraftHome, "ForgeModLoader-client-0.log").getCanonicalPath();
JOptionPane.showMessageDialog(popupWindow, String.format(
"<html><div align=\"center\"><font size=\"+1\">There was a fatal error starting up minecraft and FML</font></div><br/>"
+ "Minecraft cannot launch in it's current configuration<br/>"
+ "Please consult the file <i><a href=\"file:///%s\">%s</a></i> for further information</html>", logFile, logFile),
"Fatal FML error", JOptionPane.ERROR_MESSAGE);
}
catch (Exception ex)
{
// ah well, we tried
}
}
throw new RuntimeException(t);
}
}
/**
* @return the location of the client home
*/
private File computeExistingClientHome()
{
Class<? super Object> mcMaster = ReflectionHelper.getClass(getClass().getClassLoader(), "net.minecraft.client.Minecraft");
// If we get the system property we inject into the old MC, setup the
// dir, then pull the value
String str = System.getProperty("minecraft.applet.TargetDirectory");
if (str != null)
{
str = str.replace('/', File.separatorChar);
ReflectionHelper.setPrivateValue(mcMaster, null, new File(str), "minecraftDir", "an", "minecraftDir");
}
// We force minecraft to setup it's homedir very early on so we can
// inject stuff into it
Method setupHome = ReflectionHelper.findMethod(mcMaster, null, new String[] { "func_71380_b", "getMinecraftDir", "b" });
try
{
setupHome.invoke(null);
}
catch (Exception e)
{
// Hmmm
}
File minecraftHome = ReflectionHelper.getPrivateValue(mcMaster, null, "field_71463_am", "an", "minecraftDir");
return minecraftHome;
}
public static void appletEntry(Applet minecraftApplet)
{
side = "CLIENT";
logFileNamePattern = "ForgeModLoader-client-%g.log";
instance().relaunchApplet(minecraftApplet);
}
private void relaunchApplet(Applet minecraftApplet)
{
showWindow(true);
if (minecraftApplet.getClass().getClassLoader() == classLoader)
{
if (popupWindow != null)
{
popupWindow.setVisible(false);
popupWindow.dispose();
}
try
{
newApplet = minecraftApplet;
appletClass = ReflectionHelper.getClass(classLoader, "net.minecraft.client.MinecraftApplet");
ReflectionHelper.findMethod(appletClass, newApplet, new String[] { "fmlInitReentry" }).invoke(newApplet);
return;
}
catch (Exception e)
{
System.out.println("FMLRelauncher.relaunchApplet");
e.printStackTrace();
throw new RuntimeException(e);
}
}
File mcDir = computeExistingClientHome();
setupHome(mcDir);
setupNewClientHome(mcDir);
Class<? super Object> parentAppletClass = ReflectionHelper.getClass(getClass().getClassLoader(), "java.applet.Applet");
try
{
appletClass = ReflectionHelper.getClass(classLoader, "net.minecraft.client.MinecraftApplet");
newApplet = appletClass.newInstance();
Object appletContainer = ReflectionHelper.getPrivateValue(ReflectionHelper.getClass(getClass().getClassLoader(), "java.awt.Component"),
minecraftApplet, "parent");
String launcherClassName = System.getProperty("minecraft.applet.WrapperClass", "net.minecraft.Launcher");
Class<? super Object> launcherClass = ReflectionHelper.getClass(getClass().getClassLoader(), launcherClassName);
if (launcherClass.isInstance(appletContainer))
{
ReflectionHelper.findMethod(ReflectionHelper.getClass(getClass().getClassLoader(), "java.awt.Container"), minecraftApplet,
new String[] { "removeAll" }).invoke(appletContainer);
ReflectionHelper.findMethod(launcherClass, appletContainer, new String[] { "replace" }, parentAppletClass).invoke(appletContainer, newApplet);
}
else
{
FMLRelaunchLog.severe("Found unknown applet parent %s, unable to inject!\n", appletContainer.getClass().getName());
throw new RuntimeException();
}
}
catch (Exception e)
{
throw new RuntimeException(e);
}
finally
{
if (popupWindow != null)
{
popupWindow.setVisible(false);
popupWindow.dispose();
}
}
}
public static void appletStart(Applet applet)
{
instance().startApplet(applet);
}
private void startApplet(Applet applet)
{
if (applet.getClass().getClassLoader() == classLoader)
{
if (popupWindow != null)
{
popupWindow.setVisible(false);
popupWindow.dispose();
}
if (RelaunchLibraryManager.downloadMonitor.shouldStopIt())
{
System.exit(1);
}
try
{
ReflectionHelper.findMethod(appletClass, newApplet, new String[] { "fmlStartReentry" }).invoke(newApplet);
}
catch (Exception e)
{
System.out.println("FMLRelauncher.startApplet");
e.printStackTrace();
throw new RuntimeException(e);
}
}
return;
}
public static String side()
{
return side;
}
}

View file

@ -32,6 +32,7 @@ public interface IFMLLoadingPlugin
*
* @return a list of classes that implement the ILibrarySet interface
*/
@Deprecated
String[] getLibraryRequestClass();
/**
* Return a list of classes that implements the IClassTransformer interface

View file

@ -1,473 +0,0 @@
/*
* Forge Mod Loader
* Copyright (c) 2012-2013 cpw.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* cpw - implementation
*/
package cpw.mods.fml.relauncher;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes.Name;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Level;
import cpw.mods.fml.common.FMLLog;
public class RelaunchClassLoader extends URLClassLoader
{
private List<URL> sources;
private ClassLoader parent;
private List<IClassTransformer> transformers;
private Map<String, Class> cachedClasses;
private Set<String> invalidClasses;
private Set<String> classLoaderExceptions = new HashSet<String>();
private Set<String> transformerExceptions = new HashSet<String>();
private Map<Package,Manifest> packageManifests = new HashMap<Package,Manifest>();
private IClassNameTransformer renameTransformer;
private static Manifest EMPTY = new Manifest();
private ThreadLocal<byte[]> loadBuffer = new ThreadLocal<byte[]>();
private static final String[] RESERVED = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"};
private static final boolean DEBUG_CLASSLOADING = Boolean.parseBoolean(System.getProperty("fml.debugClassLoading", "false"));
private static final boolean DEBUG_CLASSLOADING_FINER = DEBUG_CLASSLOADING && Boolean.parseBoolean(System.getProperty("fml.debugClassLoadingFiner", "false"));
private static final boolean DEBUG_CLASSLOADING_SAVE = DEBUG_CLASSLOADING && Boolean.parseBoolean(System.getProperty("fml.debugClassLoadingSave", "false"));
private static File temp_folder = null;
public RelaunchClassLoader(URL[] sources)
{
super(sources, null);
this.sources = new ArrayList<URL>(Arrays.asList(sources));
this.parent = getClass().getClassLoader();
this.cachedClasses = new HashMap<String,Class>(1000);
this.invalidClasses = new HashSet<String>(1000);
this.transformers = new ArrayList<IClassTransformer>(2);
// ReflectionHelper.setPrivateValue(ClassLoader.class, null, this, "scl");
Thread.currentThread().setContextClassLoader(this);
// standard classloader exclusions
addClassLoaderExclusion("java.");
addClassLoaderExclusion("sun.");
addClassLoaderExclusion("org.lwjgl.");
addClassLoaderExclusion("cpw.mods.fml.relauncher.");
addClassLoaderExclusion("net.minecraftforge.classloading.");
// standard transformer exclusions
addTransformerExclusion("javax.");
addTransformerExclusion("argo.");
addTransformerExclusion("org.objectweb.asm.");
addTransformerExclusion("com.google.common.");
addTransformerExclusion("org.bouncycastle.");
addTransformerExclusion("cpw.mods.fml.common.asm.transformers.deobf.");
addTransformerExclusion("cpw.mods.fml.common.patcher.");
addTransformerExclusion("cpw.mods.fml.repackage.");
if (DEBUG_CLASSLOADING_SAVE)
{
int x = 1;
temp_folder = new File(FMLRelaunchLog.minecraftHome, "CLASSLOADER_TEMP");
while(temp_folder.exists() && x <= 10)
{
temp_folder = new File(FMLRelaunchLog.minecraftHome, "CLASSLOADER_TEMP" + x++);
}
if (temp_folder.exists())
{
FMLRelaunchLog.info("DEBUG_CLASSLOADING_SAVE enabled, but 10 temp directories already exist, clean them and try again.");
temp_folder = null;
}
else
{
FMLRelaunchLog.info("DEBUG_CLASSLOADING_SAVE Enabled, saving all classes to \"%s\"", temp_folder.getAbsolutePath().replace('\\', '/'));
temp_folder.mkdirs();
}
}
}
public void registerTransformer(String transformerClassName)
{
try
{
IClassTransformer transformer = (IClassTransformer) loadClass(transformerClassName).newInstance();
transformers.add(transformer);
if (transformer instanceof IClassNameTransformer && renameTransformer == null)
{
renameTransformer = (IClassNameTransformer) transformer;
}
}
catch (Exception e)
{
FMLRelaunchLog.log(Level.SEVERE, e, "A critical problem occured registering the ASM transformer class %s", transformerClassName);
}
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException
{
if (invalidClasses.contains(name))
{
throw new ClassNotFoundException(name);
}
for (String st : classLoaderExceptions)
{
if (name.startsWith(st))
{
return parent.loadClass(name);
}
}
if (cachedClasses.containsKey(name))
{
return cachedClasses.get(name);
}
for (String st : transformerExceptions)
{
if (name.startsWith(st))
{
try
{
Class<?> cl = super.findClass(name);
cachedClasses.put(name, cl);
return cl;
}
catch (ClassNotFoundException e)
{
invalidClasses.add(name);
throw e;
}
}
}
try
{
CodeSigner[] signers = null;
String transformedName = transformName(name);
String untransformedName = untransformName(name);
int lastDot = untransformedName.lastIndexOf('.');
String pkgname = lastDot == -1 ? "" : untransformedName.substring(0, lastDot);
String fName = untransformedName.replace('.', '/').concat(".class");
String pkgPath = pkgname.replace('.', '/');
URLConnection urlConnection = findCodeSourceConnectionFor(fName);
if (urlConnection instanceof JarURLConnection && lastDot > -1 && !untransformedName.startsWith("net.minecraft."))
{
JarURLConnection jarUrlConn = (JarURLConnection)urlConnection;
JarFile jf = jarUrlConn.getJarFile();
if (jf != null && jf.getManifest() != null)
{
Manifest mf = jf.getManifest();
JarEntry ent = jf.getJarEntry(fName);
Package pkg = getPackage(pkgname);
getClassBytes(untransformedName);
signers = ent.getCodeSigners();
if (pkg == null)
{
pkg = definePackage(pkgname, mf, jarUrlConn.getJarFileURL());
packageManifests.put(pkg, mf);
}
else
{
if (pkg.isSealed() && !pkg.isSealed(jarUrlConn.getJarFileURL()))
{
FMLLog.severe("The jar file %s is trying to seal already secured path %s", jf.getName(), pkgname);
}
else if (isSealed(pkgname, mf))
{
FMLLog.severe("The jar file %s has a security seal for path %s, but that path is defined and not secure", jf.getName(), pkgname);
}
}
}
}
else if (lastDot > -1 && !untransformedName.startsWith("net.minecraft."))
{
Package pkg = getPackage(pkgname);
if (pkg == null)
{
pkg = definePackage(pkgname, null, null, null, null, null, null, null);
packageManifests.put(pkg, EMPTY);
}
else if (pkg.isSealed())
{
FMLLog.severe("The URL %s is defining elements for sealed path %s", urlConnection.getURL(), pkgname);
}
}
byte[] basicClass = getClassBytes(untransformedName);
byte[] transformedClass = runTransformers(untransformedName, transformedName, basicClass);
saveTransformedClass(transformedClass, transformedName);
Class<?> cl = defineClass(transformedName, transformedClass, 0, transformedClass.length, (urlConnection == null ? null : new CodeSource(urlConnection.getURL(), signers)));
cachedClasses.put(transformedName, cl);
return cl;
}
catch (Throwable e)
{
invalidClasses.add(name);
if (DEBUG_CLASSLOADING)
{
FMLLog.log(Level.FINEST, e, "Exception encountered attempting classloading of %s", name);
}
throw new ClassNotFoundException(name, e);
}
}
private void saveTransformedClass(byte[] data, String transformedName)
{
if (!DEBUG_CLASSLOADING_SAVE || temp_folder == null)
{
return;
}
File outFile = new File(temp_folder, transformedName.replace('.', File.separatorChar) + ".class");
File outDir = outFile.getParentFile();
if (!outDir.exists())
{
outDir.mkdirs();
}
if (outFile.exists())
{
outFile.delete();
}
try
{
FMLRelaunchLog.fine("Saving transformed class \"%s\" to \"%s\"", transformedName, outFile.getAbsolutePath().replace('\\', '/'));
OutputStream output = new FileOutputStream(outFile);
output.write(data);
output.close();
}
catch(IOException ex)
{
FMLRelaunchLog.log(Level.WARNING, ex, "Could not save transformed class \"%s\"", transformedName);
}
}
private String untransformName(String name)
{
if (renameTransformer != null)
{
return renameTransformer.unmapClassName(name);
}
else
{
return name;
}
}
private String transformName(String name)
{
if (renameTransformer != null)
{
return renameTransformer.remapClassName(name);
}
else
{
return name;
}
}
private boolean isSealed(String path, Manifest man)
{
Attributes attr = man.getAttributes(path);
String sealed = null;
if (attr != null) {
sealed = attr.getValue(Name.SEALED);
}
if (sealed == null) {
if ((attr = man.getMainAttributes()) != null) {
sealed = attr.getValue(Name.SEALED);
}
}
return "true".equalsIgnoreCase(sealed);
}
private URLConnection findCodeSourceConnectionFor(String name)
{
URL res = findResource(name);
if (res != null)
{
try
{
return res.openConnection();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
else
{
return null;
}
}
private byte[] runTransformers(String name, String transformedName, byte[] basicClass)
{
if (DEBUG_CLASSLOADING_FINER)
{
FMLRelaunchLog.finest("Beginning transform of %s (%s) Start Length: %d", name, transformedName, (basicClass == null ? 0 : basicClass.length));
for (IClassTransformer transformer : transformers)
{
String transName = transformer.getClass().getName();
FMLRelaunchLog.finest("Before Transformer %s: %d", transName, (basicClass == null ? 0 : basicClass.length));
basicClass = transformer.transform(name, transformedName, basicClass);
FMLRelaunchLog.finest("After Transformer %s: %d", transName, (basicClass == null ? 0 : basicClass.length));
}
FMLRelaunchLog.finest("Ending transform of %s (%s) Start Length: %d", name, transformedName, (basicClass == null ? 0 : basicClass.length));
}
else
{
for (IClassTransformer transformer : transformers)
{
basicClass = transformer.transform(name, transformedName, basicClass);
}
}
return basicClass;
}
@Override
public void addURL(URL url)
{
super.addURL(url);
sources.add(url);
}
public List<URL> getSources()
{
return sources;
}
private byte[] readFully(InputStream stream)
{
try
{
byte[] buf = loadBuffer.get();
if (buf == null)
{
loadBuffer.set(new byte[1 << 12]);
buf = loadBuffer.get();
}
int r, totalLength = 0;
while ((r = stream.read(buf, totalLength, buf.length - totalLength)) != -1)
{
totalLength += r;
if (totalLength >= buf.length - 1)
{
byte[] oldbuf = buf;
buf = new byte[ oldbuf.length + (1 << 12 )];
System.arraycopy(oldbuf, 0, buf, 0, oldbuf.length);
}
}
byte[] result = new byte[totalLength];
System.arraycopy(buf, 0, result, 0, totalLength);
return result;
}
catch (Throwable t)
{
FMLRelaunchLog.log(Level.WARNING, t, "Problem loading class");
return new byte[0];
}
}
public List<IClassTransformer> getTransformers()
{
return Collections.unmodifiableList(transformers);
}
private void addClassLoaderExclusion(String toExclude)
{
classLoaderExceptions.add(toExclude);
}
void addTransformerExclusion(String toExclude)
{
transformerExceptions.add(toExclude);
}
public byte[] getClassBytes(String name) throws IOException
{
if (name.indexOf('.') == -1)
{
for (String res : RESERVED)
{
if (name.toUpperCase(Locale.ENGLISH).startsWith(res))
{
byte[] data = getClassBytes("_" + name);
if (data != null)
{
return data;
}
}
}
}
InputStream classStream = null;
try
{
URL classResource = findResource(name.replace('.', '/').concat(".class"));
if (classResource == null)
{
if (DEBUG_CLASSLOADING)
{
FMLLog.finest("Failed to find class resource %s", name.replace('.', '/').concat(".class"));
}
return null;
}
classStream = classResource.openStream();
if (DEBUG_CLASSLOADING)
{
FMLLog.finest("Loading class %s from resource %s", name, classResource.toString());
}
return readFully(classStream);
}
finally
{
if (classStream != null)
{
try
{
classStream.close();
}
catch (IOException e)
{
// Swallow the close exception
}
}
}
}
}

View file

@ -4,6 +4,9 @@ import java.io.File;
import java.net.URLClassLoader;
import java.util.logging.Level;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import com.google.common.base.Throwables;
public class ServerLaunchWrapper {
@ -23,42 +26,7 @@ public class ServerLaunchWrapper {
private void run(String[] args)
{
File minecraftHome = new File(".");
FMLRelaunchLog.minecraftHome = minecraftHome;
FMLRelauncher.logFileNamePattern = "ForgeModLoader-server-%g.log";
FMLRelauncher.side = "SERVER";
URLClassLoader ucl = (URLClassLoader) getClass().getClassLoader();
RelaunchClassLoader classLoader = new RelaunchClassLoader(ucl.getURLs());
RelaunchLibraryManager.downloadMonitor = new DummyDownloader();
Class<? super Object> server;
FMLInjectionData.build(minecraftHome, classLoader);
FMLRelaunchLog.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft %s loading", FMLInjectionData.major, FMLInjectionData.minor,
FMLInjectionData.rev, FMLInjectionData.build, FMLInjectionData.mccversion, FMLInjectionData.mcpversion);
FMLRelaunchLog.info("Java is %s, version %s, running on %s:%s:%s, installed at %s", System.getProperty("java.vm.name"), System.getProperty("java.version"), System.getProperty("os.name"), System.getProperty("os.arch"), System.getProperty("os.version"), System.getProperty("java.home"));
FMLRelaunchLog.fine("Java classpath at launch is %s", System.getProperty("java.class.path"));
FMLRelaunchLog.fine("Java library path at launch is %s", System.getProperty("java.library.path"));
try
{
RelaunchLibraryManager.handleLaunch(minecraftHome, classLoader);
}
catch (Throwable t)
{
throw Throwables.propagate(t);
}
server = ReflectionHelper.getClass(classLoader, "net.minecraft.server.MinecraftServer");
try
{
ReflectionHelper.findMethod(server, null, new String[] { "main" }, String[].class).invoke(null, (Object)args);
}
catch (Exception t)
{
throw Throwables.propagate(t);
}
Launch.main(args);
}
}

View file

@ -13,7 +13,7 @@
package cpw.mods.fml.relauncher;
public enum Side {
CLIENT, SERVER, BUKKIT;
CLIENT, SERVER;
/**
* @return If this is the server environment

View file

@ -17,7 +17,22 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cpw.mods.fml.common.SidedProxy;
/**
* Marks the associated element as being only available on a certain {@link Side}. This is
* generally meant for internal Forge and FML use only and should only be used on mod classes
* when other more common mechanisms, such as using a {@link SidedProxy} fail to work.
*
* Note, this will <em>only</em> apply to the direct element marked. This code:
* <code> @SideOnly public MyField field = new MyField();</code> will <strong>not</strong> work, as the initializer
* is a separate piece of code to the actual field declaration, and will not be able to find
* it's field on the wrong side.
*
* @author cpw
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface SideOnly

View file

@ -1,18 +1,16 @@
--- ../src-base/minecraft/net/minecraft/client/Minecraft.java
+++ ../src-work/minecraft/net/minecraft/client/Minecraft.java
@@ -1,5 +1,11 @@
@@ -1,5 +1,9 @@
package net.minecraft.client;
+import cpw.mods.fml.client.FMLClientHandler;
+import cpw.mods.fml.common.FMLCommonHandler;
+import cpw.mods.fml.common.registry.GameData;
+import cpw.mods.fml.common.registry.ItemData;
+import cpw.mods.fml.relauncher.ArgsWrapper;
+import cpw.mods.fml.relauncher.FMLRelauncher;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.awt.BorderLayout;
@@ -115,6 +121,8 @@
@@ -115,6 +119,8 @@
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.util.glu.GLU;
@ -21,7 +19,7 @@
@SideOnly(Side.CLIENT)
public abstract class Minecraft implements Runnable, IPlayerUsage
{
@@ -299,6 +307,8 @@
@@ -299,6 +305,8 @@
this.field_71466_p = new FontRenderer(this.field_71474_y, "/font/default.png", this.field_71446_o, false);
this.field_71464_q = new FontRenderer(this.field_71474_y, "/font/alternate.png", this.field_71446_o, false);
@ -30,7 +28,7 @@
if (this.field_71474_y.field_74363_ab != null)
{
StringTranslate.func_74808_a().func_74810_a(this.field_71474_y.field_74363_ab, false);
@@ -334,6 +344,8 @@
@@ -334,6 +342,8 @@
GL11.glViewport(0, 0, this.field_71443_c, this.field_71440_d);
this.field_71452_i = new EffectRenderer(this.field_71441_e, this.field_71446_o);
@ -39,7 +37,7 @@
try
{
this.field_71430_V = new ThreadDownloadResources(this.field_71412_D, this);
@@ -362,6 +374,8 @@
@@ -362,6 +372,8 @@
{
this.func_71352_k();
}
@ -48,7 +46,7 @@
}
private void func_71357_I() throws LWJGLException
@@ -723,9 +737,11 @@
@@ -723,9 +735,11 @@
if (!this.field_71454_w)
{
@ -60,7 +58,7 @@
}
GL11.glFlush();
@@ -1255,10 +1271,14 @@
@@ -1255,10 +1269,14 @@
public void func_71407_l()
{
@ -75,7 +73,7 @@
this.field_71424_I.func_76320_a("stats");
this.field_71413_E.func_77449_e();
@@ -1716,6 +1736,8 @@
@@ -1716,6 +1734,8 @@
this.field_71453_ak.func_74428_b();
}
@ -84,7 +82,7 @@
this.field_71424_I.func_76319_b();
this.field_71423_H = func_71386_F();
}
@@ -1754,8 +1776,27 @@
@@ -1754,8 +1774,27 @@
}
this.field_71413_E.func_77450_a(StatList.field_75936_f, 1);
@ -112,16 +110,3 @@
this.field_71455_al = true;
this.field_71461_s.func_73720_a(StatCollector.func_74838_a("menu.loadingLevel"));
@@ -1977,6 +2018,12 @@
public static void main(String[] p_main_0_)
{
+ FMLRelauncher.handleClientRelaunch(new ArgsWrapper(p_main_0_));
+ }
+
+ public static void fmlReentry(ArgsWrapper wrapper)
+ {
+ String[] p_main_0_ = wrapper.args;
HashMap hashmap = new HashMap();
boolean flag = false;
boolean flag1 = true;

View file

@ -1,33 +0,0 @@
--- ../src-base/minecraft/net/minecraft/client/MinecraftApplet.java
+++ ../src-work/minecraft/net/minecraft/client/MinecraftApplet.java
@@ -1,5 +1,6 @@
package net.minecraft.client;
+import cpw.mods.fml.relauncher.FMLRelauncher;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.applet.Applet;
@@ -15,6 +16,11 @@
private Thread field_71482_c = null;
public void init()
+ {
+ FMLRelauncher.appletEntry(this);
+ }
+
+ public void fmlInitReentry()
{
this.field_71483_a = new CanvasMinecraftApplet(this);
boolean flag = "true".equalsIgnoreCase(this.getParameter("fullscreen"));
@@ -63,6 +69,11 @@
public void start()
{
+ FMLRelauncher.appletStart(this);
+ }
+
+ public void fmlStartReentry()
+ {
if (this.field_71481_b != null)
{
this.field_71481_b.field_71445_n = false;

View file

@ -1,15 +1,13 @@
--- ../src-base/minecraft/net/minecraft/server/MinecraftServer.java
+++ ../src-work/minecraft/net/minecraft/server/MinecraftServer.java
@@ -1,5 +1,8 @@
@@ -1,5 +1,6 @@
package net.minecraft.server;
+import cpw.mods.fml.common.FMLCommonHandler;
+import cpw.mods.fml.relauncher.ArgsWrapper;
+import cpw.mods.fml.relauncher.FMLRelauncher;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.awt.GraphicsEnvironment;
@@ -352,7 +355,11 @@
@@ -352,7 +353,11 @@
{
if (this.func_71197_b())
{
@ -21,7 +19,7 @@
for (long j = 0L; this.field_71317_u; this.field_71296_Q = true)
{
@@ -391,6 +398,7 @@
@@ -391,6 +396,7 @@
Thread.sleep(1L);
}
@ -29,7 +27,7 @@
}
else
{
@@ -399,6 +407,10 @@
@@ -399,6 +405,10 @@
}
catch (Throwable throwable)
{
@ -40,7 +38,7 @@
throwable.printStackTrace();
this.func_98033_al().func_98234_c("Encountered an unexpected exception " + throwable.getClass().getSimpleName(), throwable);
CrashReport crashreport = null;
@@ -429,6 +441,10 @@
@@ -429,6 +439,10 @@
{
try
{
@ -51,7 +49,7 @@
this.func_71260_j();
this.field_71316_v = true;
}
@@ -438,6 +454,8 @@
@@ -438,6 +452,8 @@
}
finally
{
@ -60,7 +58,7 @@
this.func_71240_o();
}
}
@@ -454,8 +472,10 @@
@@ -454,8 +470,10 @@
public void func_71217_p()
{
@ -71,7 +69,7 @@
++this.field_71315_w;
if (this.field_71295_T)
@@ -501,6 +521,7 @@
@@ -501,6 +519,7 @@
this.field_71304_b.func_76319_b();
this.field_71304_b.func_76319_b();
@ -79,7 +77,7 @@
}
public void func_71190_q()
@@ -528,6 +549,7 @@
@@ -528,6 +547,7 @@
}
this.field_71304_b.func_76320_a("tick");
@ -87,7 +85,7 @@
CrashReport crashreport;
try
@@ -552,6 +574,7 @@
@@ -552,6 +572,7 @@
throw new ReportedException(crashreport);
}
@ -95,7 +93,7 @@
this.field_71304_b.func_76319_b();
this.field_71304_b.func_76320_a("tracker");
worldserver.func_73039_n().func_72788_a();
@@ -679,7 +702,7 @@
@@ -679,7 +700,7 @@
public String getServerModName()
{
@ -104,17 +102,3 @@
}
public CrashReport func_71230_b(CrashReport p_71230_1_)
@@ -1137,6 +1160,13 @@
@SideOnly(Side.SERVER)
public static void main(String[] p_main_0_)
{
+ FMLRelauncher.handleServerRelaunch(new ArgsWrapper(p_main_0_));
+ }
+
+ @SideOnly(Side.SERVER)
+ public static void fmlReentry(ArgsWrapper wrap)
+ {
+ String[] p_main_0_ = wrap.args;
StatList.func_75919_a();
ILogAgent ilogagent = null;