Merge in binpatch and use launcher
This commit is contained in:
parent
21240df8bc
commit
07a5efe612
23 changed files with 414 additions and 1103 deletions
159
fml/build.xml
159
fml/build.xml
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
49
fml/common/cpw/mods/fml/common/launcher/FMLTweaker.java
Normal file
49
fml/common/cpw/mods/fml/common/launcher/FMLTweaker.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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");
|
||||
|
|
116
fml/common/cpw/mods/fml/relauncher/FMLLaunchHandler.java
Normal file
116
fml/common/cpw/mods/fml/relauncher/FMLLaunchHandler.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
public enum Side {
|
||||
CLIENT, SERVER, BUKKIT;
|
||||
CLIENT, SERVER;
|
||||
|
||||
/**
|
||||
* @return If this is the server environment
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue