diff --git a/fml/client/cpw/mods/fml/client/FMLClientHandler.java b/fml/client/cpw/mods/fml/client/FMLClientHandler.java index ddab2b751..bf835e014 100644 --- a/fml/client/cpw/mods/fml/client/FMLClientHandler.java +++ b/fml/client/cpw/mods/fml/client/FMLClientHandler.java @@ -322,7 +322,6 @@ public class FMLClientHandler implements IFMLSidedHandler */ public void addSpecialModEntries(ArrayList mods) { - mods.add(new FMLDummyContainer()); if (optifineContainer!=null) { mods.add(optifineContainer); } diff --git a/fml/client/net/minecraft/src/EntityRendererProxy.java b/fml/client/net/minecraft/src/EntityRendererProxy.java index a875e2654..4994b1f74 100644 --- a/fml/client/net/minecraft/src/EntityRendererProxy.java +++ b/fml/client/net/minecraft/src/EntityRendererProxy.java @@ -18,7 +18,7 @@ import net.minecraft.client.Minecraft; public class EntityRendererProxy extends EntityRenderer { - + public static final String fmlMarker = "This is an FML marker"; private Minecraft game; public EntityRendererProxy(Minecraft minecraft) diff --git a/fml/client/net/minecraft/src/ModLoader.java b/fml/client/net/minecraft/src/ModLoader.java index 00320aec5..b5c99cf98 100644 --- a/fml/client/net/minecraft/src/ModLoader.java +++ b/fml/client/net/minecraft/src/ModLoader.java @@ -42,6 +42,7 @@ import cpw.mods.fml.common.ObfuscationReflectionHelper; public class ModLoader { + public static final String fmlMarker = "This is an FML marker"; // TODO dirty workaround for millinaire @Deprecated public static final Map> localizedStrings=Collections.emptyMap(); diff --git a/fml/common/cpw/mods/fml/common/DummyModContainer.java b/fml/common/cpw/mods/fml/common/DummyModContainer.java index e76d1693b..58d10a600 100644 --- a/fml/common/cpw/mods/fml/common/DummyModContainer.java +++ b/fml/common/cpw/mods/fml/common/DummyModContainer.java @@ -117,4 +117,9 @@ public class DummyModContainer implements ModContainer return null; } + @Override + public boolean isImmutable() + { + return false; + } } diff --git a/fml/common/cpw/mods/fml/common/FMLDummyContainer.java b/fml/common/cpw/mods/fml/common/FMLDummyContainer.java index 4a3f78134..c70c859a9 100644 --- a/fml/common/cpw/mods/fml/common/FMLDummyContainer.java +++ b/fml/common/cpw/mods/fml/common/FMLDummyContainer.java @@ -16,6 +16,8 @@ package cpw.mods.fml.common; import java.util.Arrays; +import com.google.common.eventbus.EventBus; + /** * @author cpw * @@ -41,4 +43,10 @@ public class FMLDummyContainer extends DummyModContainer meta.screenshots=new String[0]; meta.logoFile=""; } + + @Override + public boolean registerBus(EventBus bus, LoadController controller) + { + return true; + } } diff --git a/fml/common/cpw/mods/fml/common/FMLModContainer.java b/fml/common/cpw/mods/fml/common/FMLModContainer.java index bc2e26274..f704df81e 100644 --- a/fml/common/cpw/mods/fml/common/FMLModContainer.java +++ b/fml/common/cpw/mods/fml/common/FMLModContainer.java @@ -78,8 +78,8 @@ public class FMLModContainer implements ModContainer .put(FMLServerStoppingEvent.class, Mod.ServerStopping.class) .build(); private static final BiMap, Class> modTypeAnnotations = modAnnotationTypes.inverse(); - - + + public FMLModContainer(String className, File modSource, Map modDescriptor) { this.className = className; @@ -223,7 +223,7 @@ public class FMLModContainer implements ModContainer for (Annotation a : m.getAnnotations()) { Class[] paramTypes = new Class[] { modTypeAnnotations.get(a.annotationType()) }; - + if (Arrays.equals(m.getParameterTypes(), paramTypes)) { m.setAccessible(true); @@ -311,4 +311,9 @@ public class FMLModContainer implements ModContainer } return processedVersion; } + @Override + public boolean isImmutable() + { + return false; + } } diff --git a/fml/common/cpw/mods/fml/common/InjectedModContainer.java b/fml/common/cpw/mods/fml/common/InjectedModContainer.java new file mode 100644 index 000000000..b80e95580 --- /dev/null +++ b/fml/common/cpw/mods/fml/common/InjectedModContainer.java @@ -0,0 +1,105 @@ +package cpw.mods.fml.common; + +import java.io.File; +import java.util.List; + +import com.google.common.eventbus.EventBus; + +import cpw.mods.fml.common.versioning.ArtifactVersion; + +public class InjectedModContainer implements ModContainer +{ + + private ModContainer wrappedContainer; + + public InjectedModContainer(ModContainer mc) + { + this.wrappedContainer = mc; + } + + public String getModId() + { + return wrappedContainer.getModId(); + } + + public String getName() + { + return wrappedContainer.getName(); + } + + public String getVersion() + { + return wrappedContainer.getVersion(); + } + + public File getSource() + { + return wrappedContainer.getSource(); + } + + public ModMetadata getMetadata() + { + return wrappedContainer.getMetadata(); + } + + public void bindMetadata(MetadataCollection mc) + { + wrappedContainer.bindMetadata(mc); + } + + public void setEnabledState(boolean enabled) + { + wrappedContainer.setEnabledState(enabled); + } + + public List getRequirements() + { + return wrappedContainer.getRequirements(); + } + + public List getDependencies() + { + return wrappedContainer.getDependencies(); + } + + public List getDependants() + { + return wrappedContainer.getDependants(); + } + + public String getSortingRules() + { + return wrappedContainer.getSortingRules(); + } + + public boolean registerBus(EventBus bus, LoadController controller) + { + return wrappedContainer.registerBus(bus, controller); + } + + public boolean matches(Object mod) + { + return wrappedContainer.matches(mod); + } + + public Object getMod() + { + return wrappedContainer.getMod(); + } + + public ArtifactVersion getProcessedVersion() + { + return wrappedContainer.getProcessedVersion(); + } + + public ProxyInjector findSidedProxy() + { + return wrappedContainer.findSidedProxy(); + } + + @Override + public boolean isImmutable() + { + return true; + } +} diff --git a/fml/common/cpw/mods/fml/common/LoadController.java b/fml/common/cpw/mods/fml/common/LoadController.java index f0a109ee9..5eb73827d 100644 --- a/fml/common/cpw/mods/fml/common/LoadController.java +++ b/fml/common/cpw/mods/fml/common/LoadController.java @@ -17,6 +17,7 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import cpw.mods.fml.common.LoaderState.ModState; +import cpw.mods.fml.common.event.FMLLoadEvent; import cpw.mods.fml.common.event.FMLStateEvent; public class LoadController @@ -34,10 +35,16 @@ public class LoadController public LoadController(Loader loader) { this.loader = loader; - this.modList = loader.getIndexedModList(); this.masterChannel = new EventBus("FMLMainChannel"); this.masterChannel.register(this); + state = LoaderState.NOINIT; + } + + @Subscribe + public void buildModList(FMLLoadEvent event) + { + this.modList = loader.getIndexedModList(); Builder eventBus = ImmutableMap.builder(); for (ModContainer mod : loader.getModList()) @@ -60,8 +67,6 @@ public class LoadController } eventChannels = eventBus.build(); - - state = LoaderState.NOINIT; } public void distributeStateMessage(LoaderState state, Object... eventData) @@ -141,4 +146,17 @@ public class LoadController { return Iterables.getLast(modStates.get(selectedMod.getModId()), ModState.AVAILABLE); } + + public void distributeStateMessage(Class customEvent) + { + try + { + masterChannel.post(customEvent.newInstance()); + } + catch (Exception e) + { + FMLLog.log(Level.SEVERE, e, "An unexpected exception"); + throw new LoaderException(e); + } + } } diff --git a/fml/common/cpw/mods/fml/common/Loader.java b/fml/common/cpw/mods/fml/common/Loader.java index 56aaa3fea..9c1d7f712 100644 --- a/fml/common/cpw/mods/fml/common/Loader.java +++ b/fml/common/cpw/mods/fml/common/Loader.java @@ -47,6 +47,7 @@ import com.google.common.collect.Maps; import cpw.mods.fml.common.LoaderState.ModState; import cpw.mods.fml.common.discovery.ContainerType; import cpw.mods.fml.common.discovery.ModDiscoverer; +import cpw.mods.fml.common.event.FMLLoadEvent; import cpw.mods.fml.common.functions.ModIdFunction; import cpw.mods.fml.common.toposort.ModSorter; import cpw.mods.fml.common.toposort.ModSortingException; @@ -131,6 +132,7 @@ public class Loader private LoadController modController; private static File minecraftDir; + private static List injectedContainers; public static Loader instance() { @@ -151,6 +153,7 @@ public class Loader mccversion = (String) data[4]; mcsversion = (String) data[5]; minecraftDir = (File) data[6]; + injectedContainers = (List)data[7]; } private Loader() @@ -214,7 +217,10 @@ public class Loader FMLLog.fine("Mod sorting data:"); for (ModContainer mod : mods) { - FMLLog.fine("\t%s(%s): %s (%s)", mod.getModId(), mod.getName(), mod.getSource().getName(), mod.getSortingRules()); + if (!mod.isImmutable()) + { + FMLLog.fine("\t%s(%s): %s (%s)", mod.getModId(), mod.getName(), mod.getSource().getName(), mod.getSortingRules()); + } } if (mods.size()==0) { @@ -247,6 +253,21 @@ public class Loader */ private void identifyMods() { + FMLLog.fine("Building injected Mod Containers %s", injectedContainers); + for (String cont : injectedContainers) + { + ModContainer mc; + try + { + mc = (ModContainer) Class.forName(cont,true,modClassLoader).newInstance(); + } + catch (Exception e) + { + FMLLog.log(Level.SEVERE, e, "A problem occured instantiating the injected mod container %s", cont); + throw new LoaderException(e); + } + mods.add(new InjectedModContainer(mc)); + } ModDiscoverer discoverer = new ModDiscoverer(); FMLLog.fine("Attempting to load mods contained in the minecraft jar file and associated classes"); discoverer.findClasspathMods(modClassLoader); @@ -255,7 +276,7 @@ public class Loader FMLLog.info("Searching %s for mods", canonicalModsDir.getAbsolutePath()); discoverer.findModDirMods(canonicalModsDir); - mods = discoverer.identifyMods(); + mods.addAll(discoverer.identifyMods()); namedMods = Maps.uniqueIndex(mods, new ModIdFunction()); FMLLog.info("Forge Mod Loader has identified %d mod%s to load", mods.size(), mods.size() != 1 ? "s" : ""); } @@ -343,6 +364,7 @@ public class Loader disableRequestedMods(); sortModList(); mods = ImmutableList.copyOf(mods); + modController.distributeStateMessage(FMLLoadEvent.class); modController.transition(LoaderState.CONSTRUCTING); modController.distributeStateMessage(LoaderState.CONSTRUCTING, modClassLoader); modController.transition(LoaderState.PREINITIALIZATION); @@ -565,18 +587,18 @@ public class Loader modController.distributeStateMessage(LoaderState.SERVER_STARTING, server); modController.transition(LoaderState.SERVER_STARTING); } - + public void serverStarted() { modController.distributeStateMessage(LoaderState.SERVER_STARTED); modController.transition(LoaderState.SERVER_STARTED); } - + public void serverStopping() { modController.distributeStateMessage(LoaderState.SERVER_STOPPING); modController.transition(LoaderState.SERVER_STOPPING); modController.transition(LoaderState.AVAILABLE); - + } } diff --git a/fml/common/cpw/mods/fml/common/ModContainer.java b/fml/common/cpw/mods/fml/common/ModContainer.java index c7677c71f..13a5ad802 100644 --- a/fml/common/cpw/mods/fml/common/ModContainer.java +++ b/fml/common/cpw/mods/fml/common/ModContainer.java @@ -148,4 +148,6 @@ public interface ModContainer ArtifactVersion getProcessedVersion(); ProxyInjector findSidedProxy(); + + boolean isImmutable(); } diff --git a/fml/common/cpw/mods/fml/common/event/FMLLoadEvent.java b/fml/common/cpw/mods/fml/common/event/FMLLoadEvent.java new file mode 100644 index 000000000..a3354a412 --- /dev/null +++ b/fml/common/cpw/mods/fml/common/event/FMLLoadEvent.java @@ -0,0 +1,6 @@ +package cpw.mods.fml.common.event; + +public class FMLLoadEvent +{ + +} diff --git a/fml/common/cpw/mods/fml/common/modloader/ModLoaderModContainer.java b/fml/common/cpw/mods/fml/common/modloader/ModLoaderModContainer.java index 487c7a1be..ae3feef9a 100644 --- a/fml/common/cpw/mods/fml/common/modloader/ModLoaderModContainer.java +++ b/fml/common/cpw/mods/fml/common/modloader/ModLoaderModContainer.java @@ -558,4 +558,10 @@ public class ModLoaderModContainer implements ModContainer } return processedVersion; } + + @Override + public boolean isImmutable() + { + return false; + } } diff --git a/fml/common/cpw/mods/fml/common/toposort/ModSorter.java b/fml/common/cpw/mods/fml/common/toposort/ModSorter.java index 5640a8e25..1b946f009 100644 --- a/fml/common/cpw/mods/fml/common/toposort/ModSorter.java +++ b/fml/common/cpw/mods/fml/common/toposort/ModSorter.java @@ -16,6 +16,8 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import com.google.common.collect.Lists; + import cpw.mods.fml.common.DummyModContainer; import cpw.mods.fml.common.FMLModContainer; import cpw.mods.fml.common.ModContainer; @@ -35,6 +37,8 @@ public class ModSorter private ModContainer before = new DummyModContainer(); private ModContainer after = new DummyModContainer(); + private List immutableMods; + public ModSorter(List modList, Map nameLookup) { buildGraph(modList, nameLookup); @@ -43,6 +47,7 @@ public class ModSorter private void buildGraph(List modList, Map nameLookup) { modGraph = new DirectedGraph(); + immutableMods = Lists.newArrayList(); modGraph.addNode(beforeAll); modGraph.addNode(before); modGraph.addNode(afterAll); @@ -53,11 +58,20 @@ public class ModSorter for (ModContainer mod : modList) { - modGraph.addNode(mod); + if (!mod.isImmutable()) + { + modGraph.addNode(mod); + } + else + { + immutableMods.add(mod); + } } for (ModContainer mod : modList) { + if (mod.isImmutable()) + continue; boolean preDepAdded = false; boolean postDepAdded = false; @@ -117,6 +131,7 @@ public class ModSorter { List sortedList = TopologicalSort.topologicalSort(modGraph); sortedList.removeAll(Arrays.asList(new ModContainer[] {beforeAll, before, after, afterAll})); - return sortedList; + immutableMods.addAll(sortedList); + return immutableMods; } } diff --git a/fml/common/cpw/mods/fml/relauncher/FMLCorePlugin.java b/fml/common/cpw/mods/fml/relauncher/FMLCorePlugin.java index ec155ec91..c6df53e3f 100644 --- a/fml/common/cpw/mods/fml/relauncher/FMLCorePlugin.java +++ b/fml/common/cpw/mods/fml/relauncher/FMLCorePlugin.java @@ -1,5 +1,7 @@ package cpw.mods.fml.relauncher; +import java.util.Map; + public class FMLCorePlugin implements IFMLLoadingPlugin { @Override @@ -13,4 +15,22 @@ public class FMLCorePlugin implements IFMLLoadingPlugin { return new String[] {"cpw.mods.fml.common.asm.ASMTransformer"}; } + + @Override + public String getModContainerClass() + { + return "cpw.mods.fml.common.FMLDummyContainer"; + } + + @Override + public String getSetupClass() + { + return "cpw.mods.fml.relauncher.FMLSanityChecker"; + } + + @Override + public void injectData(Map data) + { + // don't care about this data + } } diff --git a/fml/common/cpw/mods/fml/relauncher/FMLVersionData.java b/fml/common/cpw/mods/fml/relauncher/FMLInjectionData.java similarity index 88% rename from fml/common/cpw/mods/fml/relauncher/FMLVersionData.java rename to fml/common/cpw/mods/fml/relauncher/FMLInjectionData.java index d99e7c7c0..a1a547801 100644 --- a/fml/common/cpw/mods/fml/relauncher/FMLVersionData.java +++ b/fml/common/cpw/mods/fml/relauncher/FMLInjectionData.java @@ -3,10 +3,12 @@ package cpw.mods.fml.relauncher; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import java.util.Properties; import java.util.logging.Level; -public class FMLVersionData +public class FMLInjectionData { static File minecraftHome; static String major; @@ -15,6 +17,7 @@ public class FMLVersionData static String build; static String mccversion; static String mcsversion; + public static List containers = new ArrayList(); static void build(File mcHome, RelaunchClassLoader classLoader) { @@ -46,6 +49,6 @@ public class FMLVersionData public static Object[] data() { - return new Object[] { major, minor, rev, build, mccversion, mcsversion, minecraftHome }; + return new Object[] { major, minor, rev, build, mccversion, mcsversion, minecraftHome, containers }; } } diff --git a/fml/common/cpw/mods/fml/relauncher/FMLRelauncher.java b/fml/common/cpw/mods/fml/relauncher/FMLRelauncher.java index 074cddc54..86612c45b 100644 --- a/fml/common/cpw/mods/fml/relauncher/FMLRelauncher.java +++ b/fml/common/cpw/mods/fml/relauncher/FMLRelauncher.java @@ -28,7 +28,7 @@ public class FMLRelauncher private Object newApplet; private Class appletClass; - private JDialog popupWindow; + JDialog popupWindow; public static void handleClientRelaunch(ArgsWrapper wrap) { @@ -39,7 +39,7 @@ public class FMLRelauncher { instance().relaunchServer(wrap); } - + static FMLRelauncher instance() { if (INSTANCE == null) @@ -128,8 +128,8 @@ public class FMLRelauncher private void setupHome(File minecraftHome) { - FMLVersionData.build(minecraftHome, classLoader); - FMLLog.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft client:%s, server:%s loading", FMLVersionData.major, FMLVersionData.minor, FMLVersionData.rev, FMLVersionData.build, FMLVersionData.mccversion, FMLVersionData.mcsversion); + FMLInjectionData.build(minecraftHome, classLoader); + FMLLog.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft client:%s, server:%s loading", FMLInjectionData.major, FMLInjectionData.minor, FMLInjectionData.rev, FMLInjectionData.build, FMLInjectionData.mccversion, FMLInjectionData.mcsversion); try { diff --git a/fml/common/cpw/mods/fml/relauncher/FMLSanityChecker.java b/fml/common/cpw/mods/fml/relauncher/FMLSanityChecker.java new file mode 100644 index 000000000..d2047f5b2 --- /dev/null +++ b/fml/common/cpw/mods/fml/relauncher/FMLSanityChecker.java @@ -0,0 +1,69 @@ +package cpw.mods.fml.relauncher; + +import java.util.Map; + +import javax.swing.JOptionPane; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Opcodes; + +public class FMLSanityChecker implements IFMLCallHook +{ + static class MLDetectorClassVisitor extends ClassVisitor + { + private boolean foundMarker = false; + private MLDetectorClassVisitor() + { + super(Opcodes.ASM4); + } + + @Override + public FieldVisitor visitField(int arg0, String arg1, String arg2, String arg3, Object arg4) + { + if (arg1 == "fmlMarker") + { + foundMarker = true; + } + return null; + } + } + + private RelaunchClassLoader cl; + + @Override + public Void call() throws Exception + { + byte[] mlClass = cl.getClassBytes("ModLoader"); + // Only care in obfuscated env + if (mlClass == null) + { + return null; + } + MLDetectorClassVisitor mlTester = new MLDetectorClassVisitor(); + ClassReader cr = new ClassReader(mlClass); + cr.accept(mlTester, ClassReader.SKIP_CODE); + if (!mlTester.foundMarker) + { + JOptionPane.showMessageDialog(FMLRelauncher.instance().popupWindow, "CRITICAL ERROR
" + + "ModLoader was detected in this environment
" + + "ForgeModLoader cannot be installed alongside ModLoader
" + + "All mods should work without ModLoader being installed
" + + "Because ForgeModLoader is 100% compatible with ModLoader
" + + "Re-install Minecraft Forge or Forge ModLoader into a clean
" + + "jar and try again.", + "ForgeModLoader critical error", + JOptionPane.ERROR_MESSAGE); + throw new RuntimeException("Invalid ModLoader class detected"); + } + return null; + } + + @Override + public void injectData(Map data) + { + cl = (RelaunchClassLoader) data.get("classLoader"); + } + +} diff --git a/fml/common/cpw/mods/fml/relauncher/IFMLCallHook.java b/fml/common/cpw/mods/fml/relauncher/IFMLCallHook.java new file mode 100644 index 000000000..b6b52c611 --- /dev/null +++ b/fml/common/cpw/mods/fml/relauncher/IFMLCallHook.java @@ -0,0 +1,22 @@ +package cpw.mods.fml.relauncher; + +import java.util.Map; +import java.util.concurrent.Callable; + +/** + * This call hook allows for code to execute at the very early stages of + * minecraft initialization. FML uses it to validate that there is a + * safe environment for further loading of FML. + * + * @author cpw + * + */ +public interface IFMLCallHook extends Callable +{ + /** + * Injected with data from the FML environment: + * "classLoader" : The FML Class Loader + * @param data + */ + void injectData(Map data); +} diff --git a/fml/common/cpw/mods/fml/relauncher/IFMLLoadingPlugin.java b/fml/common/cpw/mods/fml/relauncher/IFMLLoadingPlugin.java index a7a490143..972d9706f 100644 --- a/fml/common/cpw/mods/fml/relauncher/IFMLLoadingPlugin.java +++ b/fml/common/cpw/mods/fml/relauncher/IFMLLoadingPlugin.java @@ -1,5 +1,7 @@ package cpw.mods.fml.relauncher; +import java.util.Map; + /** * The base plugin that provides class name meta information to FML to * enhance the classloading lifecycle for mods in FML @@ -20,4 +22,34 @@ public interface IFMLLoadingPlugin * @return */ String[] getASMTransformerClass(); + + /** + * Return a class name that implements "ModContainer" for injection into the mod list + * The "getName" function should return a name that other mods can, if need be, + * depend on. + * Trivially, this modcontainer will be loaded before all regular mod containers, + * which means it will be forced to be "immutable" - not susceptible to normal + * sorting behaviour. + * All other mod behaviours are available however- this container can receive and handle + * normal loading events + */ + String getModContainerClass(); + + /** + * Return the class name of an implementor of "IFMLCallHook", that will be run, in the + * main thread, to perform any additional setup this coremod may require. It will be + * run prior to Minecraft starting, so it CANNOT operate on minecraft + * itself. The game will deliberately crash if this code is detected to trigger a + * minecraft class loading (TODO: implement crash ;) ) + */ + String getSetupClass(); + + /** + * Inject coremod data into this coremod + * This data includes: + * "mcLocation" : the location of the minecraft directory, + * "coremodList" : the list of coremods + * "coremodLocation" : the file this coremod loaded from, + */ + void injectData(Map data); } diff --git a/fml/common/cpw/mods/fml/relauncher/RelaunchClassLoader.java b/fml/common/cpw/mods/fml/relauncher/RelaunchClassLoader.java index 7c7354bf4..114c9eec7 100644 --- a/fml/common/cpw/mods/fml/relauncher/RelaunchClassLoader.java +++ b/fml/common/cpw/mods/fml/relauncher/RelaunchClassLoader.java @@ -2,6 +2,7 @@ package cpw.mods.fml.relauncher; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; @@ -79,7 +80,7 @@ public class RelaunchClassLoader extends URLClassLoader try { - byte[] basicClass = readFully(findResource(name.replace('.', '/').concat(".class")).openStream()); + byte[] basicClass = getClassBytes(name); byte[] transformedClass = runTransformers(name, basicClass); Class cl = defineClass(name, transformedClass, 0, transformedClass.length); cachedClasses.put(name, cl); @@ -91,6 +92,40 @@ public class RelaunchClassLoader extends URLClassLoader } } + /** + * @param name + * @return + * @throws IOException + */ + public byte[] getClassBytes(String name) throws IOException + { + InputStream classStream = null; + try + { + URL classResource = findResource(name.replace('.', '/').concat(".class")); + if (classResource == null) + { + return null; + } + classStream = classResource.openStream(); + return readFully(classStream); + } + finally + { + if (classStream != null) + { + try + { + classStream.close(); + } + catch (IOException e) + { + // Swallow the close exception + } + } + } + } + private byte[] runTransformers(String name, byte[] basicClass) { for (IClassTransformer transformer : transformers) diff --git a/fml/common/cpw/mods/fml/relauncher/RelaunchLibraryManager.java b/fml/common/cpw/mods/fml/relauncher/RelaunchLibraryManager.java index 1bffcc0c6..4fe9ccda4 100644 --- a/fml/common/cpw/mods/fml/relauncher/RelaunchLibraryManager.java +++ b/fml/common/cpw/mods/fml/relauncher/RelaunchLibraryManager.java @@ -14,6 +14,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLConnection; +import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; @@ -23,7 +24,9 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -40,10 +43,14 @@ public class RelaunchLibraryManager private static String[] rootPlugins = { "cpw.mods.fml.relauncher.FMLCorePlugin" , "net.minecraftforge.classloading.FMLForgePlugin" }; private static final String HEXES = "0123456789abcdef"; private static List loadedLibraries = new ArrayList(); + private static Map pluginLocations; + private static List loadPlugins; + private static List libraries; public static void handleLaunch(File mcDir, RelaunchClassLoader actualClassLoader) { - List loadPlugins = new ArrayList(); - List libraries = new ArrayList(); + pluginLocations = new HashMap(); + loadPlugins = new ArrayList(); + libraries = new ArrayList(); for (String s : rootPlugins) { try @@ -189,11 +196,42 @@ public class RelaunchLibraryManager } } } + + Map data = new HashMap(); + data.put("mcLocation", mcDir); + data.put("coremodList", loadPlugins); + for (IFMLLoadingPlugin plugin : loadPlugins) + { + data.put("coremodLocation", pluginLocations.get(plugin)); + plugin.injectData(data); + String setupClass = plugin.getSetupClass(); + if (setupClass != null) + { + try + { + IFMLCallHook call = (IFMLCallHook) Class.forName(setupClass, true, actualClassLoader).newInstance(); + Map callData = new HashMap(); + callData.put("classLoader", actualClassLoader); + call.injectData(callData); + call.call(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + + String modContainer = plugin.getModContainerClass(); + if (modContainer != null) + { + FMLInjectionData.containers.add(modContainer); + } + } try { Class loaderClazz = Class.forName("cpw.mods.fml.common.Loader", true, actualClassLoader); Method m = loaderClazz.getMethod("injectData", Object[].class); - m.invoke(null, (Object)FMLVersionData.data()); + m.invoke(null, (Object)FMLInjectionData.data()); } catch (Exception e) { @@ -270,6 +308,7 @@ public class RelaunchLibraryManager Class coreModClass = Class.forName(fmlCorePlugin, true, classLoader); IFMLLoadingPlugin plugin = (IFMLLoadingPlugin) coreModClass.newInstance(); loadPlugins.add(plugin); + pluginLocations .put(plugin, coreMod); if (plugin.getLibraryRequestClass()!=null) { for (String libName : plugin.getLibraryRequestClass()) diff --git a/fml/eclipse/FML-Client/.classpath b/fml/eclipse/FML-Client/.classpath index 61f25769b..18fbd49a6 100644 --- a/fml/eclipse/FML-Client/.classpath +++ b/fml/eclipse/FML-Client/.classpath @@ -1,8 +1,8 @@ - + diff --git a/fml/eclipse/FML-Server/.classpath b/fml/eclipse/FML-Server/.classpath index b2e28853c..5811580b7 100644 --- a/fml/eclipse/FML-Server/.classpath +++ b/fml/eclipse/FML-Server/.classpath @@ -1,7 +1,7 @@ - + diff --git a/fml/patches/minecraft/net/minecraft/src/WorldType.java.patch b/fml/patches/minecraft/net/minecraft/src/WorldType.java.patch index cdcd521f1..9d98bf095 100644 --- a/fml/patches/minecraft/net/minecraft/src/WorldType.java.patch +++ b/fml/patches/minecraft/net/minecraft/src/WorldType.java.patch @@ -1,6 +1,6 @@ --- ../src-base/minecraft/net/minecraft/src/WorldType.java +++ ../src-work/minecraft/net/minecraft/src/WorldType.java -@@ -1,4 +1,14 @@ +@@ -1,7 +1,20 @@ package net.minecraft.src; + +import java.util.Arrays; @@ -15,19 +15,23 @@ public class WorldType { -@@ -12,6 +22,11 @@ - private boolean field_77140_h; - private boolean field_77141_i; - -+ protected BiomeGenBase[] biomesForWorldType; -+ + public static final BiomeGenBase[] base11Biomes = new BiomeGenBase[] {BiomeGenBase.field_76769_d, BiomeGenBase.field_76767_f, BiomeGenBase.field_76770_e, BiomeGenBase.field_76780_h, BiomeGenBase.field_76772_c, BiomeGenBase.field_76768_g}; + public static final BiomeGenBase[] base12Biomes = ObjectArrays.concat(base11Biomes, BiomeGenBase.field_76782_w); + + public static final WorldType[] field_77139_a = new WorldType[16]; + public static final WorldType field_77137_b = (new WorldType(0, "default", 1)).func_77129_f(); + public static final WorldType field_77138_c = new WorldType(1, "flat"); +@@ -11,6 +24,9 @@ + private final int field_77134_g; + private boolean field_77140_h; + private boolean field_77141_i; ++ ++ protected BiomeGenBase[] biomesForWorldType; ++ + private WorldType(int p_i3737_1_, String p_i3737_2_) { - this(p_i3737_1_, p_i3737_2_, 0); -@@ -23,6 +38,14 @@ +@@ -23,6 +39,14 @@ this.field_77134_g = p_i3738_3_; this.field_77140_h = true; field_77139_a[p_i3738_1_] = this; @@ -42,11 +46,11 @@ } public String func_77127_a() -@@ -84,4 +107,63 @@ +@@ -84,4 +108,63 @@ return null; } -+ ++ + public WorldChunkManager getChunkManager(World world) + { + return this == field_77138_c ? new WorldChunkManagerHell(BiomeGenBase.field_76772_c, 0.5F, 0.5F) : new WorldChunkManager(world); @@ -96,7 +100,7 @@ + newBiomesForWorld.remove(biome); + biomesForWorldType = newBiomesForWorld.toArray(new BiomeGenBase[0]); + } -+ ++ + public boolean handleSlimeSpawnReduction(Random random, World world) + { + return this == field_77138_c ? random.nextInt(4) != 1 : false; diff --git a/fml/patches/minecraft_server/net/minecraft/src/WorldType.java.patch b/fml/patches/minecraft_server/net/minecraft/src/WorldType.java.patch index de99045b7..6a81c8358 100644 --- a/fml/patches/minecraft_server/net/minecraft/src/WorldType.java.patch +++ b/fml/patches/minecraft_server/net/minecraft/src/WorldType.java.patch @@ -1,6 +1,6 @@ --- ../src-base/minecraft_server/net/minecraft/src/WorldType.java +++ ../src-work/minecraft_server/net/minecraft/src/WorldType.java -@@ -1,4 +1,14 @@ +@@ -1,7 +1,19 @@ package net.minecraft.src; + +import java.util.Arrays; @@ -15,18 +15,21 @@ public class WorldType { -@@ -12,6 +22,11 @@ - private boolean field_77140_h; - private boolean field_77141_i; - -+ protected BiomeGenBase[] biomesForWorldType; -+ + public static final BiomeGenBase[] base11Biomes = new BiomeGenBase[] {BiomeGenBase.field_76769_d, BiomeGenBase.field_76767_f, BiomeGenBase.field_76770_e, BiomeGenBase.field_76780_h, BiomeGenBase.field_76772_c, BiomeGenBase.field_76768_g}; + public static final BiomeGenBase[] base12Biomes = ObjectArrays.concat(base11Biomes, BiomeGenBase.field_76782_w); + public static final WorldType[] field_77139_a = new WorldType[16]; + public static final WorldType field_77137_b = (new WorldType(0, "default", 1)).func_77129_f(); + public static final WorldType field_77138_c = new WorldType(1, "flat"); +@@ -11,6 +23,9 @@ + private final int field_77134_g; + private boolean field_77140_h; + private boolean field_77141_i; + ++ protected BiomeGenBase[] biomesForWorldType; ++ + private WorldType(int p_i3737_1_, String p_i3737_2_) { - this(p_i3737_1_, p_i3737_2_, 0); @@ -23,6 +38,14 @@ this.field_77134_g = p_i3738_3_; this.field_77140_h = true; @@ -46,7 +49,7 @@ return null; } -+ ++ + public WorldChunkManager getChunkManager(World world) + { + return this == field_77138_c ? new WorldChunkManagerHell(BiomeGenBase.field_76772_c, 0.5F, 0.5F) : new WorldChunkManager(world); @@ -96,7 +99,7 @@ + newBiomesForWorld.remove(biome); + biomesForWorldType = newBiomesForWorld.toArray(new BiomeGenBase[0]); + } -+ ++ + public boolean handleSlimeSpawnReduction(Random random, World world) + { + return this == field_77138_c ? random.nextInt(4) != 1 : false;