From 1ea6ba273b2c181f08b90db0b565cb03bf8dfc36 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 29 Jul 2012 22:54:59 -0400 Subject: [PATCH] New logging stuff, also the early plugin api for forge --- .../cpw/mods/fml/client/FMLClientHandler.java | 10 +- client/cpw/mods/fml/client/SpriteHelper.java | 18 +- .../cpw/mods/fml/common/FMLCommonHandler.java | 4 +- common/cpw/mods/fml/common/FMLLog.java | 68 +----- common/cpw/mods/fml/common/Loader.java | 112 ++++----- .../cpw/mods/fml/common/ModClassLoader.java | 4 +- .../common/discovery/DirectoryDiscoverer.java | 16 +- .../fml/common/discovery/JarDiscoverer.java | 6 +- .../fml/common/discovery/ModDiscoverer.java | 25 +- .../modloader/ModLoaderModContainer.java | 38 +-- .../mods/fml/relauncher/CoreFMLLibraries.java | 26 ++ .../mods/fml/relauncher/FMLCorePlugin.java | 16 ++ .../relauncher/FMLEmbeddingRelauncher.java | 7 +- common/cpw/mods/fml/relauncher/FMLLog.java | 162 +++++++++++++ .../FMLLogFormatter.java | 15 +- .../fml/relauncher/IFMLLoadingPlugin.java | 23 ++ .../cpw/mods/fml/relauncher/ILibrarySet.java | 30 +++ .../relauncher/RelaunchLibraryManager.java | 224 +++++++++++++----- 18 files changed, 560 insertions(+), 244 deletions(-) create mode 100644 common/cpw/mods/fml/relauncher/CoreFMLLibraries.java create mode 100644 common/cpw/mods/fml/relauncher/FMLCorePlugin.java create mode 100644 common/cpw/mods/fml/relauncher/FMLLog.java rename common/cpw/mods/fml/{common => relauncher}/FMLLogFormatter.java (82%) create mode 100644 common/cpw/mods/fml/relauncher/IFMLLoadingPlugin.java create mode 100644 common/cpw/mods/fml/relauncher/ILibrarySet.java diff --git a/client/cpw/mods/fml/client/FMLClientHandler.java b/client/cpw/mods/fml/client/FMLClientHandler.java index b36b910fd8..e892aef208 100644 --- a/client/cpw/mods/fml/client/FMLClientHandler.java +++ b/client/cpw/mods/fml/client/FMLClientHandler.java @@ -239,7 +239,7 @@ public class FMLClientHandler implements IFMLSidedHandler // } // Mark this as a "first tick" KeyBindingRegistry.uploadKeyBindingsToGame(client.field_6304_y); - + firstTick = true; } @@ -497,7 +497,7 @@ public class FMLClientHandler implements IFMLSidedHandler { networkManager.func_972_a(packet); } - + // TODO // for (ModContainer mod : Loader.getModList()) { // mod.getNetworkHandler().onServerLogin(handler); @@ -518,7 +518,7 @@ public class FMLClientHandler implements IFMLSidedHandler return; } // TODO - + // ModContainer mod = FMLCommonHandler.instance().getModForChannel(packet.field_44012_a); // // if (mod != null) @@ -961,7 +961,7 @@ public class FMLClientHandler implements IFMLSidedHandler } catch (Exception e) { - FMLLog.log.warning("Texture FX %s has failed to animate. Likely caused by a texture pack change that they did not respond correctly to", name); + FMLLog.warning("Texture FX %s has failed to animate. Likely caused by a texture pack change that they did not respond correctly to", name); if (ifx != null) { ifx.setErrored(true); @@ -977,7 +977,7 @@ public class FMLClientHandler implements IFMLSidedHandler int target = ((dim.width >> 4) * (dim.height >> 4)) << 2; if (effect.field_1127_a.length != target) { - FMLLog.log.warning("Detected a texture FX sizing discrepancy in %s (%d, %d)", name, effect.field_1127_a.length, target); + FMLLog.warning("Detected a texture FX sizing discrepancy in %s (%d, %d)", name, effect.field_1127_a.length, target); ifx.setErrored(true); return false; } diff --git a/client/cpw/mods/fml/client/SpriteHelper.java b/client/cpw/mods/fml/client/SpriteHelper.java index 896c21e20b..92d65f0ee9 100644 --- a/client/cpw/mods/fml/client/SpriteHelper.java +++ b/client/cpw/mods/fml/client/SpriteHelper.java @@ -32,7 +32,7 @@ public class SpriteHelper private static HashMap spriteInfo = new HashMap(); private static void initMCSpriteMaps() { - BitSet slots = + BitSet slots = SpriteHelper.toBitSet( "0000000000000000" + "0000000000000000" + @@ -51,7 +51,7 @@ public class SpriteHelper "0000000111111000" + "0000000000000000"); spriteInfo.put("/terrain.png", slots); - + slots = SpriteHelper.toBitSet( "0000000000000000" + "0000000000000000" + @@ -74,8 +74,8 @@ public class SpriteHelper /** * Register a sprite map for ModTextureStatic, to allow for other mods to override * your sprite page. - * - * + * + * */ public static void registerSpriteMapForFile(String file, String spriteMap) { if (spriteInfo.size() == 0) { @@ -87,20 +87,20 @@ public class SpriteHelper } spriteInfo.put(file, toBitSet(spriteMap)); } - + public static int getUniqueSpriteIndex(String path) { if (!spriteInfo.containsKey("/terrain.png")) { initMCSpriteMaps(); } - + BitSet slots = spriteInfo.get(path); - + if (slots == null) { Exception ex = new Exception(String.format("Invalid getUniqueSpriteIndex call for texture: %s", path)); - FMLLog.log.log(Level.SEVERE, ex, "A critical error has been detected with sprite overrides"); + FMLLog.log(Level.SEVERE, ex, "A critical error has been detected with sprite overrides"); FMLCommonHandler.instance().raiseException(ex,"Invalid request to getUniqueSpriteIndex",true); } @@ -109,7 +109,7 @@ public class SpriteHelper if (ret == -1) { Exception ex = new Exception(String.format("No more sprite indicies left for: %s", path)); - FMLLog.log.log(Level.SEVERE, ex, "There are no sprite indicies left for %s", path); + FMLLog.log(Level.SEVERE, ex, "There are no sprite indicies left for %s", path); FMLCommonHandler.instance().raiseException(ex,"No more sprite indicies left", true); } return ret; diff --git a/common/cpw/mods/fml/common/FMLCommonHandler.java b/common/cpw/mods/fml/common/FMLCommonHandler.java index 6e827272f1..29bceee9d8 100644 --- a/common/cpw/mods/fml/common/FMLCommonHandler.java +++ b/common/cpw/mods/fml/common/FMLCommonHandler.java @@ -271,7 +271,7 @@ public class FMLCommonHandler } catch (UnsupportedEncodingException e) { - FMLLog.log.log(Level.WARNING, e, "Error building registration list"); + FMLLog.log(Level.WARNING, e, "Error building registration list"); return new byte[0]; } } @@ -293,7 +293,7 @@ public class FMLCommonHandler */ public Logger getFMLLogger() { - return FMLLog.log.getLogger(); + return FMLLog.getLogger(); } /** diff --git a/common/cpw/mods/fml/common/FMLLog.java b/common/cpw/mods/fml/common/FMLLog.java index 1e2d15af05..53326568d7 100644 --- a/common/cpw/mods/fml/common/FMLLog.java +++ b/common/cpw/mods/fml/common/FMLLog.java @@ -1,78 +1,22 @@ package cpw.mods.fml.common; -import java.io.File; -import java.util.logging.ConsoleHandler; -import java.util.logging.FileHandler; import java.util.logging.Level; -import java.util.logging.LogManager; import java.util.logging.Logger; public class FMLLog { + private static cpw.mods.fml.relauncher.FMLLog coreLog = cpw.mods.fml.relauncher.FMLLog.log; - /** - * Our special logger for logging issues to. We copy various assets from the - * Minecraft logger to acheive a similar appearance. - */ - public static FMLLog log = new FMLLog(); - - private static File minecraftHome; - private static boolean configured; - private Logger myLog; - - private FMLLog() - { - } - /** - * Configure the FML logger - */ - private static void configureLogging() - { - LogManager.getLogManager().reset(); - Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); - globalLogger.setLevel(Level.OFF); - - log.myLog = Logger.getLogger("ForgeModLoader"); - FMLLogFormatter formatter = new FMLLogFormatter(); - ConsoleHandler ch = new ConsoleHandler(); - log.myLog.setUseParentHandlers(false); - log.myLog.addHandler(ch); - ch.setFormatter(formatter); - log.myLog.setLevel(Level.ALL); - try - { - File logPath = new File(minecraftHome, "ForgeModLoader-%g.log"); - FileHandler fileHandler = new FileHandler(logPath.getPath(), 0, 3); - fileHandler.setFormatter(new FMLLogFormatter()); - fileHandler.setLevel(Level.ALL); - log.myLog.addHandler(fileHandler); - } - catch (Exception e) - { - } - - // Reset global logging to shut up other logging sources (thanks guava!) - configured = true; - } - public static void log(Level level, String format, Object... data) { - if (!configured) - { - configureLogging(); - } - log.myLog.log(level, String.format(format, data)); + coreLog.log(level, String.format(format, data)); } public static void log(Level level, Throwable ex, String format, Object... data) { - if (!configured) - { - configureLogging(); - } - log.myLog.log(level, String.format(format, data), ex); + coreLog.log(level, String.format(format, data), ex); } - + public static void severe(String format, Object... data) { log(Level.SEVERE, format, data); @@ -102,8 +46,8 @@ public class FMLLog { log(Level.FINEST, format, data); } - public Logger getLogger() + public static Logger getLogger() { - return myLog; + return coreLog.getLogger(); } } diff --git a/common/cpw/mods/fml/common/Loader.java b/common/cpw/mods/fml/common/Loader.java index ca8b379304..a8586dbff8 100644 --- a/common/cpw/mods/fml/common/Loader.java +++ b/common/cpw/mods/fml/common/Loader.java @@ -52,12 +52,12 @@ import cpw.mods.fml.common.toposort.TopologicalSort; /** * The loader class performs the actual loading of the mod code from disk. - * + * *

* There are several {@link LoaderState}s to mod loading, triggered in two * different stages from the FML handler code's hooks into the minecraft code. *

- * + * *
    *
  1. LOADING. Scanning the filesystem for mod containers to load (zips, jars, * directories), adding them to the {@link #modClassLoader} Scanning, the loaded @@ -74,12 +74,12 @@ import cpw.mods.fml.common.toposort.TopologicalSort; * but it attempts to continue loading before abandoning and giving a fatal * error.
  2. *
- * + * * Phase 1 code triggers the LOADING and PREINIT states. Phase 2 code triggers * the INIT and POSTINIT states. - * + * * @author cpw - * + * */ public class Loader { @@ -153,7 +153,7 @@ public class Loader } catch (IOException ex) { - FMLLog.log.log(Level.SEVERE, "Could not get FML version information - corrupted installation detected!", ex); + FMLLog.log(Level.SEVERE, "Could not get FML version information - corrupted installation detected!", ex); throw new LoaderException(ex); } } @@ -164,9 +164,9 @@ public class Loader build = properties.getProperty("fmlbuild.build.number", "missing"); mccversion = properties.getProperty("fmlbuild.mcclientversion", "missing"); mcsversion = properties.getProperty("fmlbuild.mcserverversion", "missing"); - - FMLLog.log.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft client:%s, server:%s loading", major, minor, rev, build, mccversion, mcsversion); - + + FMLLog.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft client:%s, server:%s loading", major, minor, rev, build, mccversion, mcsversion); + modClassLoader = new ModClassLoader(getClass().getClassLoader()); } @@ -177,47 +177,47 @@ public class Loader */ private void sortModList() { - FMLLog.log.fine("Verifying mod requirements are satisfied"); + FMLLog.fine("Verifying mod requirements are satisfied"); try { for (ModContainer mod : mods) { if (!namedMods.keySet().containsAll(mod.getRequirements())) { - FMLLog.log.log(Level.SEVERE, "The mod %s (%s) requires mods %s to be available, one or more are not", mod.getModId(), mod.getName(), mod.getRequirements()); + FMLLog.log(Level.SEVERE, "The mod %s (%s) requires mods %s to be available, one or more are not", mod.getModId(), mod.getName(), mod.getRequirements()); throw new LoaderException(); } } - FMLLog.log.fine("All mod requirements are satisfied"); - + FMLLog.fine("All mod requirements are satisfied"); + ModSorter sorter = new ModSorter(mods, namedMods); try { - FMLLog.log.fine("Sorting mods into an ordered list"); + FMLLog.fine("Sorting mods into an ordered list"); mods = sorter.sort(); - FMLLog.log.fine("Mod sorting completed successfully"); + FMLLog.fine("Mod sorting completed successfully"); } catch (ModSortingException sortException) { - FMLLog.log.severe("A dependency cycle was detected in the input mod set so an ordering cannot be determined"); - FMLLog.log.severe("The visited mod list is %s", sortException.getExceptionData().getVisitedNodes()); - FMLLog.log.severe("The first mod in the cycle is %s", sortException.getExceptionData().getFirstBadNode()); - FMLLog.log.log(Level.SEVERE, sortException, "The full error"); + FMLLog.severe("A dependency cycle was detected in the input mod set so an ordering cannot be determined"); + FMLLog.severe("The visited mod list is %s", sortException.getExceptionData().getVisitedNodes()); + FMLLog.severe("The first mod in the cycle is %s", sortException.getExceptionData().getFirstBadNode()); + FMLLog.log(Level.SEVERE, sortException, "The full error"); throw new LoaderException(sortException); } } finally { - FMLLog.log.fine("Mod sorting data:"); + FMLLog.fine("Mod sorting data:"); for (ModContainer mod : mods) { - FMLLog.log.fine("\t%s(%s): %s (%s)", mod.getModId(), mod.getName(), mod.getSource().getName(), mod.getSortingRules()); + FMLLog.fine("\t%s(%s): %s (%s)", mod.getModId(), mod.getName(), mod.getSource().getName(), mod.getSortingRules()); } if (mods.size()==0) - { - FMLLog.log.fine("No mods found to sort"); + { + FMLLog.fine("No mods found to sort"); } } @@ -225,38 +225,38 @@ public class Loader /** * The primary loading code - * + * * This is visited during first initialization by Minecraft to scan and load * the mods from all sources 1. The minecraft jar itself (for loading of in * jar mods- I would like to remove this if possible but forge depends on it * at present) 2. The mods directory with expanded subdirs, searching for * mods named mod_*.class 3. The mods directory for zip and jar files, * searching for mod classes named mod_*.class again - * + * * The found resources are first loaded into the {@link #modClassLoader} * (always) then scanned for class resources matching the specification * above. - * + * * If they provide the {@link Mod} annotation, they will be loaded as * "FML mods", which currently is effectively a NO-OP. If they are * determined to be {@link BaseMod} subclasses they are loaded as such. - * + * * Finally, if they are successfully loaded as classes, they are then added * to the available mod list. */ private void identifyMods() { ModDiscoverer discoverer = new ModDiscoverer(); - FMLLog.log.fine("Attempting to load mods contained in the minecraft jar file and associated classes"); + FMLLog.fine("Attempting to load mods contained in the minecraft jar file and associated classes"); discoverer.findClasspathMods(modClassLoader); - FMLLog.log.fine("Minecraft jar mods loaded successfully"); + FMLLog.fine("Minecraft jar mods loaded successfully"); - FMLLog.log.info("Searching %s for mods", canonicalModsDir.getAbsolutePath()); + FMLLog.info("Searching %s for mods", canonicalModsDir.getAbsolutePath()); discoverer.findModDirMods(canonicalModsDir); mods = discoverer.identifyMods(); namedMods = Maps.uniqueIndex(mods, new ModIdFunction()); - FMLLog.log.info("Forge Mod Loader has identified %d mod%s to load", mods.size(), mods.size() != 1 ? "s" : ""); + FMLLog.info("Forge Mod Loader has identified %d mod%s to load", mods.size(), mods.size() != 1 ? "s" : ""); } /** @@ -280,7 +280,7 @@ public class Loader } catch (IOException ioe) { - FMLLog.log.log(Level.SEVERE, + FMLLog.log(Level.SEVERE, String.format("Failed to resolve loader directories: mods : %s ; config %s", canonicalModsDir.getAbsolutePath(), configDir.getAbsolutePath()), ioe); throw new LoaderException(ioe); @@ -288,37 +288,37 @@ public class Loader if (!canonicalModsDir.exists()) { - FMLLog.log.info("No mod directory found, creating one: %s", canonicalModsPath); + FMLLog.info("No mod directory found, creating one: %s", canonicalModsPath); boolean dirMade = canonicalModsDir.mkdir(); if (!dirMade) { - FMLLog.log.severe("Unable to create the mod directory %s", canonicalModsPath); + FMLLog.severe("Unable to create the mod directory %s", canonicalModsPath); throw new LoaderException(); } - FMLLog.log.info("Mod directory created successfully"); + FMLLog.info("Mod directory created successfully"); } if (!canonicalConfigDir.exists()) { - FMLLog.log.fine("No config directory found, creating one: %s", canonicalConfigPath); + FMLLog.fine("No config directory found, creating one: %s", canonicalConfigPath); boolean dirMade = canonicalConfigDir.mkdir(); if (!dirMade) { - FMLLog.log.severe("Unable to create the config directory %s", canonicalConfigPath); + FMLLog.severe("Unable to create the config directory %s", canonicalConfigPath); throw new LoaderException(); } - FMLLog.log.info("Config directory created successfully"); + FMLLog.info("Config directory created successfully"); } if (!canonicalModsDir.isDirectory()) { - FMLLog.log.severe("Attempting to load mods from %s, which is not a directory", canonicalModsPath); + FMLLog.severe("Attempting to load mods from %s, which is not a directory", canonicalModsPath); throw new LoaderException(); } if (!configDir.isDirectory()) { - FMLLog.log.severe("Attempting to load configuration from %s, which is not a directory", canonicalConfigPath); + FMLLog.severe("Attempting to load configuration from %s, which is not a directory", canonicalConfigPath); throw new LoaderException(); } } @@ -354,31 +354,31 @@ public class Loader private void disableRequestedMods() { String disabledModList = System.getProperty("fml.disabledMods", ""); - FMLLog.log.fine("Received a system property request \'%s\'",disabledModList); + FMLLog.fine("Received a system property request \'%s\'",disabledModList); Map sysPropertyStateList = Splitter.on(CharMatcher.anyOf(";:")) .omitEmptyStrings().trimResults().withKeyValueSeparator("=") .split(disabledModList); - FMLLog.log.fine("System property request managing the state of %d mods", sysPropertyStateList.size()); + FMLLog.fine("System property request managing the state of %d mods", sysPropertyStateList.size()); Map modStates = Maps.newHashMap(); - + File disabledModFile = new File(canonicalConfigDir, "fmlModState.properties"); Properties disabledModListProperties = new Properties(); if (disabledModFile.exists() && disabledModFile.isFile()) { - FMLLog.log.fine("Found a mod state file %s", disabledModFile.getName()); + FMLLog.fine("Found a mod state file %s", disabledModFile.getName()); try { disabledModListProperties.load(new FileReader(disabledModFile)); - FMLLog.log.fine("Loaded states for %d mods from file", disabledModListProperties.size()); + FMLLog.fine("Loaded states for %d mods from file", disabledModListProperties.size()); } catch (Exception e) { - FMLLog.log.log(Level.INFO, e, "An error occurred reading the fmlModState.properties file"); + FMLLog.log(Level.INFO, e, "An error occurred reading the fmlModState.properties file"); } } modStates.putAll(Maps.fromProperties(disabledModListProperties)); modStates.putAll(sysPropertyStateList); - FMLLog.log.fine("After merging, found state information for %d mods", modStates.size()); + FMLLog.fine("After merging, found state information for %d mods", modStates.size()); Map isEnabled = Maps.transformValues(modStates, new Function() { @@ -387,12 +387,12 @@ public class Loader return !Boolean.parseBoolean(input); } }); - + for (Map.Entry entry : isEnabled.entrySet()) { if (namedMods.containsKey(entry.getKey())) { - FMLLog.log.info("Setting mod %s to enabled state %b", entry.getKey(), entry.getValue()); + FMLLog.info("Setting mod %s to enabled state %b", entry.getKey(), entry.getValue()); namedMods.get(entry.getKey()).setEnabledState(entry.getValue()); } } @@ -400,7 +400,7 @@ public class Loader /** * Query if we know of a mod named modname - * + * * @param modname * @return */ @@ -421,7 +421,7 @@ public class Loader { StringBuilder ret = new StringBuilder(); List branding = FMLCommonHandler.instance().getBrandings(); - + Joiner.on(' ').skipNulls().appendTo(ret, branding.subList(1, branding.size())); if (modController!=null) { @@ -452,9 +452,9 @@ public class Loader { return; } - + boolean parseFailure=false; - + for (String dep : DEPENDENCYSPLITTER.split(dependencyString)) { List depparts = Lists.newArrayList(DEPENDENCYPARTSPLITTER.split(dep)); @@ -467,7 +467,7 @@ public class Loader String target = depparts.get(1); boolean targetIsAll = target.equals("*"); // If we don't have two parts to each substring, this is an invalid dependency string - + // If this is a required element, add it to the required list if ("required-before".equals(instruction) || "required-after".equals(instruction)) { @@ -482,7 +482,7 @@ public class Loader continue; } } - + // before elements are things we are loaded before (so they are our dependants) if ("required-before".equals(instruction) || "before".equals(instruction)) { @@ -498,7 +498,7 @@ public class Loader parseFailure=true; } } - + if (parseFailure) { FMLLog.log(Level.WARNING, "Unable to parse dependency string %s", dependencyString); diff --git a/common/cpw/mods/fml/common/ModClassLoader.java b/common/cpw/mods/fml/common/ModClassLoader.java index 0842caac55..efdcccd263 100644 --- a/common/cpw/mods/fml/common/ModClassLoader.java +++ b/common/cpw/mods/fml/common/ModClassLoader.java @@ -37,7 +37,7 @@ import cpw.mods.fml.relauncher.RelaunchClassLoader; */ public class ModClassLoader extends URLClassLoader { - private static final List STANDARD_LIBRARIES = ImmutableList.of("jinput.jar", "lwjgl.jar", "lwjgl_util.jar", "argo-2.25.jar", "asm-all-4.0.jar", "guava-12.0.jar"); + private static final List STANDARD_LIBRARIES = ImmutableList.of("jinput.jar", "lwjgl.jar", "lwjgl_util.jar"); private RelaunchClassLoader mainClassLoader; public ModClassLoader(ClassLoader parent) { @@ -70,7 +70,7 @@ public class ModClassLoader extends URLClassLoader } catch (URISyntaxException e) { - FMLLog.log.log(Level.SEVERE, "Unable to process our input to locate the minecraft code", e); + FMLLog.log(Level.SEVERE, "Unable to process our input to locate the minecraft code", e); throw new LoaderException(e); } } diff --git a/common/cpw/mods/fml/common/discovery/DirectoryDiscoverer.java b/common/cpw/mods/fml/common/discovery/DirectoryDiscoverer.java index 0be9a89788..7fd289a337 100644 --- a/common/cpw/mods/fml/common/discovery/DirectoryDiscoverer.java +++ b/common/cpw/mods/fml/common/discovery/DirectoryDiscoverer.java @@ -34,11 +34,11 @@ public class DirectoryDiscoverer implements ITypeDiscoverer public List discover(ModCandidate candidate) { List found = Lists.newArrayList(); - FMLLog.log.fine("Examining directory %s for potential mods", candidate.getModContainer().getName()); + FMLLog.fine("Examining directory %s for potential mods", candidate.getModContainer().getName()); exploreFileSystem("", candidate.getModContainer(), found, candidate, null); return found; } - + public void exploreFileSystem(String path, File modDir, List harvestedMods, ModCandidate candidate, MetadataCollection mc) { if (path.length() == 0) @@ -55,7 +55,7 @@ public class DirectoryDiscoverer implements ITypeDiscoverer mc = MetadataCollection.from(null); } } - + File[] content = modDir.listFiles(new ClassFilter()); // Always sort our content @@ -64,12 +64,12 @@ public class DirectoryDiscoverer implements ITypeDiscoverer { if (file.isDirectory()) { - FMLLog.log.finest("Recursing into package %s", path + file.getName()); + FMLLog.finest("Recursing into package %s", path + file.getName()); exploreFileSystem(path + file.getName() + ".", file, harvestedMods, candidate, mc); continue; } Matcher match = classFile.matcher(file.getName()); - + if (match.matches()) { ASMModParser modParser = null; @@ -83,7 +83,7 @@ public class DirectoryDiscoverer implements ITypeDiscoverer { Throwables.propagate(e); } - + modParser.validate(); ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer()); if (container!=null) @@ -92,8 +92,8 @@ public class DirectoryDiscoverer implements ITypeDiscoverer container.bindMetadata(mc); } } - - + + } } diff --git a/common/cpw/mods/fml/common/discovery/JarDiscoverer.java b/common/cpw/mods/fml/common/discovery/JarDiscoverer.java index e3d9cc3de2..cfb571a320 100644 --- a/common/cpw/mods/fml/common/discovery/JarDiscoverer.java +++ b/common/cpw/mods/fml/common/discovery/JarDiscoverer.java @@ -21,7 +21,7 @@ public class JarDiscoverer implements ITypeDiscoverer public List discover(ModCandidate candidate) { List foundMods = Lists.newArrayList(); - FMLLog.log.fine("Examining file %s for potential mods", candidate.getModContainer().getName()); + FMLLog.fine("Examining file %s for potential mods", candidate.getModContainer().getName()); ZipFile jar = null; try { @@ -31,7 +31,7 @@ public class JarDiscoverer implements ITypeDiscoverer MetadataCollection mc = null; if (modInfo != null) { - FMLLog.log.finer("Located mcmod.info file in file %s", candidate.getModContainer().getName()); + FMLLog.finer("Located mcmod.info file in file %s", candidate.getModContainer().getName()); mc = MetadataCollection.from(jar.getInputStream(modInfo)); } for (ZipEntry ze : Collections.list(jar.entries())) @@ -52,7 +52,7 @@ public class JarDiscoverer implements ITypeDiscoverer } catch (Exception e) { - FMLLog.log.warning("Zip file %s failed to read properly, it will be ignored", candidate.getModContainer().getName()); + FMLLog.warning("Zip file %s failed to read properly, it will be ignored", candidate.getModContainer().getName()); } finally { diff --git a/common/cpw/mods/fml/common/discovery/ModDiscoverer.java b/common/cpw/mods/fml/common/discovery/ModDiscoverer.java index 00c7534da7..b6b0b67748 100644 --- a/common/cpw/mods/fml/common/discovery/ModDiscoverer.java +++ b/common/cpw/mods/fml/common/discovery/ModDiscoverer.java @@ -26,12 +26,14 @@ import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Opcodes; import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; 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; public class ModDiscoverer { @@ -41,10 +43,11 @@ public class ModDiscoverer public void findClasspathMods(ModClassLoader modClassLoader) { + List knownLibraries = ImmutableList.builder().addAll(modClassLoader.getDefaultLibraries()).addAll(RelaunchLibraryManager.getLibraries()).build(); File[] minecraftSources = modClassLoader.getParentSources(); if (minecraftSources.length == 1 && minecraftSources[0].isFile()) { - FMLLog.log.fine("Minecraft is a file at %s, loading", minecraftSources[0].getAbsolutePath()); + FMLLog.fine("Minecraft is a file at %s, loading", minecraftSources[0].getAbsolutePath()); candidates.add(new ModCandidate(minecraftSources[0], minecraftSources[0], ContainerType.JAR)); } else @@ -53,19 +56,19 @@ public class ModDiscoverer { if (minecraftSources[i].isFile()) { - if (modClassLoader.getDefaultLibraries().contains(minecraftSources[i].getName())) + if (knownLibraries.contains(minecraftSources[i].getName())) { - FMLLog.log.fine("Skipping known library file %s", minecraftSources[i].getAbsolutePath()); - } + FMLLog.fine("Skipping known library file %s", minecraftSources[i].getAbsolutePath()); + } else { - FMLLog.log.fine("Found a minecraft related file at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()); + FMLLog.fine("Found a minecraft related file at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()); candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.JAR, true)); } } else if (minecraftSources[i].isDirectory()) { - FMLLog.log.fine("Found a minecraft related directory at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()); + FMLLog.fine("Found a minecraft related directory at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()); candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.DIR, true)); } } @@ -83,7 +86,7 @@ public class ModDiscoverer { if (modFile.isDirectory()) { - FMLLog.log.fine("Found a candidate mod directory %s", modFile.getName()); + FMLLog.fine("Found a candidate mod directory %s", modFile.getName()); candidates.add(new ModCandidate(modFile, modFile, ContainerType.DIR)); } else @@ -92,12 +95,12 @@ public class ModDiscoverer if (matcher.matches()) { - FMLLog.log.fine("Found a candidate zip or jar file %s", matcher.group(0)); + FMLLog.fine("Found a candidate zip or jar file %s", matcher.group(0)); candidates.add(new ModCandidate(modFile, modFile, ContainerType.JAR)); } else { - FMLLog.log.fine("Ignoring unknown file %s in mods directory", modFile.getName()); + FMLLog.fine("Ignoring unknown file %s in mods directory", modFile.getName()); } } } @@ -106,7 +109,7 @@ public class ModDiscoverer public List identifyMods() { List modList = Lists.newArrayList(); - + for (ModCandidate candidate : candidates) { try @@ -123,7 +126,7 @@ public class ModDiscoverer Throwables.propagate(t); } } - + return modList; } } diff --git a/common/cpw/mods/fml/common/modloader/ModLoaderModContainer.java b/common/cpw/mods/fml/common/modloader/ModLoaderModContainer.java index 89b3af0101..614070f41c 100644 --- a/common/cpw/mods/fml/common/modloader/ModLoaderModContainer.java +++ b/common/cpw/mods/fml/common/modloader/ModLoaderModContainer.java @@ -104,7 +104,7 @@ public class ModLoaderModContainer implements ModContainer this.gameTickHandler = new BaseModTicker(instance, false); this.guiTickHandler = new BaseModTicker(instance, true); } - + /** * */ @@ -122,14 +122,14 @@ public class ModLoaderModContainer implements ModContainer { try { - FMLLog.log.fine("Reading existing configuration file for %s : %s", modClazzName, modConfig.getName()); + FMLLog.fine("Reading existing configuration file for %s : %s", modClazzName, modConfig.getName()); FileReader configReader = new FileReader(modConfig); props.load(configReader); configReader.close(); } catch (Exception e) { - FMLLog.log.log(Level.SEVERE, e, "Error occured reading mod configuration file %s", modConfig.getName()); + FMLLog.log(Level.SEVERE, e, "Error occured reading mod configuration file %s", modConfig.getName()); throw new LoaderException(e); } existingConfigFound = true; @@ -161,17 +161,17 @@ public class ModLoaderModContainer implements ModContainer defaultValue = f.get(null); propertyValue = props.getProperty(propertyName, extractValue(defaultValue)); Object currentValue = parseValue(propertyValue, property, f.getType(), propertyName, modClazzName); - FMLLog.log.finest("Configuration for %s.%s found values default: %s, configured: %s, interpreted: %s", modClazzName, propertyName, defaultValue, propertyValue, currentValue); + FMLLog.finest("Configuration for %s.%s found values default: %s, configured: %s, interpreted: %s", modClazzName, propertyName, defaultValue, propertyValue, currentValue); if (currentValue != null && !currentValue.equals(defaultValue)) { - FMLLog.log.finest("Configuration for %s.%s value set to: %s", modClazzName, propertyName, currentValue); + FMLLog.finest("Configuration for %s.%s value set to: %s", modClazzName, propertyName, currentValue); f.set(null, currentValue); } } catch (Exception e) { - FMLLog.log.log(Level.SEVERE, e, "Invalid configuration found for %s in %s", propertyName, modConfig.getName()); + FMLLog.log(Level.SEVERE, e, "Invalid configuration found for %s in %s", propertyName, modConfig.getName()); throw new LoaderException(e); } finally @@ -208,22 +208,22 @@ public class ModLoaderModContainer implements ModContainer { if (!mlPropFound && !existingConfigFound) { - FMLLog.log.fine("No MLProp configuration for %s found or required. No file written", modClazzName); + FMLLog.fine("No MLProp configuration for %s found or required. No file written", modClazzName); return; } if (!mlPropFound && existingConfigFound) { File mlPropBackup = new File(modConfig.getParent(),modConfig.getName()+".bak"); - FMLLog.log.fine("MLProp configuration file for %s found but not required. Attempting to rename file to %s", modClazzName, mlPropBackup.getName()); + FMLLog.fine("MLProp configuration file for %s found but not required. Attempting to rename file to %s", modClazzName, mlPropBackup.getName()); boolean renamed = modConfig.renameTo(mlPropBackup); if (renamed) { - FMLLog.log.fine("Unused MLProp configuration file for %s renamed successfully to %s", modClazzName, mlPropBackup.getName()); + FMLLog.fine("Unused MLProp configuration file for %s renamed successfully to %s", modClazzName, mlPropBackup.getName()); } else { - FMLLog.log.fine("Unused MLProp configuration file for %s renamed UNSUCCESSFULLY to %s", modClazzName, mlPropBackup.getName()); + FMLLog.fine("Unused MLProp configuration file for %s renamed UNSUCCESSFULLY to %s", modClazzName, mlPropBackup.getName()); } return; @@ -233,11 +233,11 @@ public class ModLoaderModContainer implements ModContainer FileWriter configWriter = new FileWriter(modConfig); props.store(configWriter, comments.toString()); configWriter.close(); - FMLLog.log.fine("Configuration for %s written to %s", modClazzName, modConfig.getName()); + FMLLog.fine("Configuration for %s written to %s", modClazzName, modConfig.getName()); } catch (IOException e) { - FMLLog.log.log(Level.SEVERE, e, "Error trying to write the config file %s", modConfig.getName()); + FMLLog.log(Level.SEVERE, e, "Error trying to write the config file %s", modConfig.getName()); throw new LoaderException(e); } } @@ -288,7 +288,7 @@ public class ModLoaderModContainer implements ModContainer if (n.doubleValue() < property.min() || n.doubleValue() > property.max()) { - FMLLog.log.warning("Configuration for %s.%s found value %s outside acceptable range %s,%s", modConfigName,propertyName, n, property.min(), property.max()); + FMLLog.warning("Configuration for %s.%s found value %s outside acceptable range %s,%s", modConfigName,propertyName, n, property.min(), property.max()); return null; } else @@ -332,7 +332,7 @@ public class ModLoaderModContainer implements ModContainer { return sortingProperties; } - + @Override public boolean matches(Object mod) { @@ -477,11 +477,11 @@ public class ModLoaderModContainer implements ModContainer } // Lifecycle mod events - + @Subscribe public void constructMod(FMLConstructionEvent event) { - try + try { ModClassLoader modClassLoader = event.getModClassLoader(); modClassLoader.addFile(modSource); @@ -516,8 +516,8 @@ public class ModLoaderModContainer implements ModContainer Throwables.propagateIfPossible(e); } } - - + + @Subscribe public void init(FMLInitializationEvent event) { @@ -531,7 +531,7 @@ public class ModLoaderModContainer implements ModContainer Throwables.propagateIfPossible(t); } } - + @Subscribe public void postInit(FMLPostInitializationEvent event) { diff --git a/common/cpw/mods/fml/relauncher/CoreFMLLibraries.java b/common/cpw/mods/fml/relauncher/CoreFMLLibraries.java new file mode 100644 index 0000000000..6620614377 --- /dev/null +++ b/common/cpw/mods/fml/relauncher/CoreFMLLibraries.java @@ -0,0 +1,26 @@ +package cpw.mods.fml.relauncher; + +public class CoreFMLLibraries implements ILibrarySet +{ + private static String[] libraries = { "argo-2.25.jar","guava-12.0.1.jar","asm-all-4.0.jar" }; + private static String[] checksums = { "bb672829fde76cb163004752b86b0484bd0a7f4b", "b8e78b9af7bf45900e14c6f958486b6ca682195f", "98308890597acb64047f7e896638e0d98753ae82" }; + + @Override + public String[] getLibraries() + { + return libraries; + } + + @Override + public String[] getHashes() + { + return checksums; + } + + @Override + public String getRootURL() + { + return "http://cloud.github.com/downloads/cpw/FML/%s"; + } + +} diff --git a/common/cpw/mods/fml/relauncher/FMLCorePlugin.java b/common/cpw/mods/fml/relauncher/FMLCorePlugin.java new file mode 100644 index 0000000000..ec155ec917 --- /dev/null +++ b/common/cpw/mods/fml/relauncher/FMLCorePlugin.java @@ -0,0 +1,16 @@ +package cpw.mods.fml.relauncher; + +public class FMLCorePlugin implements IFMLLoadingPlugin +{ + @Override + public String[] getLibraryRequestClass() + { + return new String[] {"cpw.mods.fml.relauncher.CoreFMLLibraries"}; + } + + @Override + public String[] getASMTransformerClass() + { + return new String[] {"cpw.mods.fml.common.asm.ASMTransformer"}; + } +} diff --git a/common/cpw/mods/fml/relauncher/FMLEmbeddingRelauncher.java b/common/cpw/mods/fml/relauncher/FMLEmbeddingRelauncher.java index 78b8a13bce..4176564367 100644 --- a/common/cpw/mods/fml/relauncher/FMLEmbeddingRelauncher.java +++ b/common/cpw/mods/fml/relauncher/FMLEmbeddingRelauncher.java @@ -28,7 +28,6 @@ public class FMLEmbeddingRelauncher if (INSTANCE == null) { INSTANCE = new FMLEmbeddingRelauncher(); - System.out.println("FML relaunch active"); } return INSTANCE; } @@ -47,8 +46,6 @@ public class FMLEmbeddingRelauncher // Now we re-inject the home into the "new" minecraft under our control Class client = ReflectionHelper.getClass(clientLoader, "net.minecraft.client.Minecraft"); ReflectionHelper.setPrivateValue(client, null, minecraftHome, "field_6275_Z", "ap", "minecraftDir"); - Class log = ReflectionHelper.getClass(clientLoader, "cpw.mods.fml.common.FMLLog"); - ReflectionHelper.setPrivateValue(log, null, minecraftHome, "minecraftHome"); try { @@ -75,6 +72,8 @@ public class FMLEmbeddingRelauncher // Hmmm } File minecraftHome = ReflectionHelper.getPrivateValue(mcMaster, null, "field_6275_Z", "ap", "minecraftDir"); + FMLLog.minecraftHome = minecraftHome; + FMLLog.info("FML relaunch active"); RelaunchLibraryManager.handleLaunch(minecraftHome, clientLoader); return minecraftHome; @@ -119,7 +118,7 @@ public class FMLEmbeddingRelauncher } else { - System.out.printf("Found unknown applet parent %s, unable to inject!\n", launcherClass); + FMLLog.severe("Found unknown applet parent %s, unable to inject!\n", launcherClass); throw new RuntimeException(); } } diff --git a/common/cpw/mods/fml/relauncher/FMLLog.java b/common/cpw/mods/fml/relauncher/FMLLog.java new file mode 100644 index 0000000000..d2e560031e --- /dev/null +++ b/common/cpw/mods/fml/relauncher/FMLLog.java @@ -0,0 +1,162 @@ +package cpw.mods.fml.relauncher; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.logging.ConsoleHandler; +import java.util.logging.FileHandler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +import cpw.mods.fml.relauncher.FMLLogFormatter; + +public class FMLLog +{ + + private static class LoggingOutStream extends ByteArrayOutputStream + { + private Logger log; + private StringBuilder currentMessage; + + public LoggingOutStream(Logger log) + { + this.log = log; + this.currentMessage = new StringBuilder(); + } + + @Override + public void flush() throws IOException + { + String record; + synchronized(this) + { + super.flush(); + record = this.toString(); + super.reset(); + + currentMessage.append(record); + if (currentMessage.lastIndexOf(FMLLogFormatter.LINE_SEPARATOR)>=0) + { + // Are we longer than just the line separator? + if (currentMessage.length()>FMLLogFormatter.LINE_SEPARATOR.length()) + { + // Trim the line separator + currentMessage.setLength(currentMessage.length()-FMLLogFormatter.LINE_SEPARATOR.length()); + log.log(Level.INFO, currentMessage.toString()); + } + currentMessage.setLength(0); + } + } + } + } + /** + * Our special logger for logging issues to. We copy various assets from the + * Minecraft logger to acheive a similar appearance. + */ + public static FMLLog log = new FMLLog(); + + static File minecraftHome; + private static boolean configured; + private Logger myLog; + + private FMLLog() + { + } + /** + * Configure the FML logger + */ + private static void configureLogging() + { + LogManager.getLogManager().reset(); + Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + globalLogger.setLevel(Level.OFF); + + log.myLog = Logger.getLogger("ForgeModLoader"); + + Logger stdOut = Logger.getLogger("STDOUT"); + stdOut.setParent(log.myLog); + Logger stdErr = Logger.getLogger("STDERR"); + stdErr.setParent(log.myLog); + FMLLogFormatter formatter = new FMLLogFormatter(); + + // Console handler captures the normal stderr before it gets replaced + ConsoleHandler ch = new ConsoleHandler(); + ch.setLevel(Level.parse(System.getProperty("fml.log.level","INFO"))); + log.myLog.setUseParentHandlers(false); + log.myLog.addHandler(ch); + ch.setFormatter(formatter); + log.myLog.setLevel(Level.ALL); + try + { + File logPath = new File(minecraftHome, "ForgeModLoader-%g.log"); + FileHandler fileHandler = new FileHandler(logPath.getPath(), 0, 3); + fileHandler.setFormatter(formatter); + fileHandler.setLevel(Level.ALL); + log.myLog.addHandler(fileHandler); + } + catch (Exception e) + { + } + + // Set system out to a log stream + System.setOut(new PrintStream(new LoggingOutStream(stdOut), true)); + System.setErr(new PrintStream(new LoggingOutStream(stdErr), true)); + + // Reset global logging to shut up other logging sources (thanks guava!) + configured = true; + } + + public static void log(Level level, String format, Object... data) + { + if (!configured) + { + configureLogging(); + } + log.myLog.log(level, String.format(format, data)); + } + + public static void log(Level level, Throwable ex, String format, Object... data) + { + if (!configured) + { + configureLogging(); + } + log.myLog.log(level, String.format(format, data), ex); + } + + public static void severe(String format, Object... data) + { + log(Level.SEVERE, format, data); + } + + public static void warning(String format, Object... data) + { + log(Level.WARNING, format, data); + } + + public static void info(String format, Object... data) + { + log(Level.INFO, format, data); + } + + public static void fine(String format, Object... data) + { + log(Level.FINE, format, data); + } + + public static void finer(String format, Object... data) + { + log(Level.FINER, format, data); + } + + public static void finest(String format, Object... data) + { + log(Level.FINEST, format, data); + } + public Logger getLogger() + { + return myLog; + } +} diff --git a/common/cpw/mods/fml/common/FMLLogFormatter.java b/common/cpw/mods/fml/relauncher/FMLLogFormatter.java similarity index 82% rename from common/cpw/mods/fml/common/FMLLogFormatter.java rename to common/cpw/mods/fml/relauncher/FMLLogFormatter.java index d8576d346c..7f81db1b11 100644 --- a/common/cpw/mods/fml/common/FMLLogFormatter.java +++ b/common/cpw/mods/fml/relauncher/FMLLogFormatter.java @@ -1,8 +1,8 @@ -package cpw.mods.fml.common; +package cpw.mods.fml.relauncher; /** * Copied from ConsoleLogFormatter for shared use on the client - * + * */ import java.io.PrintWriter; import java.io.StringWriter; @@ -13,6 +13,7 @@ import java.util.logging.LogRecord; final class FMLLogFormatter extends Formatter { + static final String LINE_SEPARATOR = System.getProperty("line.separator"); private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public String format(LogRecord record) @@ -50,8 +51,16 @@ final class FMLLogFormatter extends Formatter msg.append(" [" + lvl.getLocalizedName() + "] "); } + if (record.getLoggerName() != null) + { + msg.append("["+record.getLoggerName()+"] "); + } + else + { + msg.append("[] "); + } msg.append(record.getMessage()); - msg.append(System.getProperty("line.separator")); + msg.append(LINE_SEPARATOR); Throwable thr = record.getThrown(); if (thr != null) diff --git a/common/cpw/mods/fml/relauncher/IFMLLoadingPlugin.java b/common/cpw/mods/fml/relauncher/IFMLLoadingPlugin.java new file mode 100644 index 0000000000..a7a4901436 --- /dev/null +++ b/common/cpw/mods/fml/relauncher/IFMLLoadingPlugin.java @@ -0,0 +1,23 @@ +package cpw.mods.fml.relauncher; + +/** + * The base plugin that provides class name meta information to FML to + * enhance the classloading lifecycle for mods in FML + * + * @author cpw + * + */ +public interface IFMLLoadingPlugin +{ + /** + * Return a list of classes that implement the ILibrarySet interface + * + * @return + */ + String[] getLibraryRequestClass(); + /** + * Return a list of classes that implements the IClassTransformer interface + * @return + */ + String[] getASMTransformerClass(); +} diff --git a/common/cpw/mods/fml/relauncher/ILibrarySet.java b/common/cpw/mods/fml/relauncher/ILibrarySet.java new file mode 100644 index 0000000000..2b632f8d62 --- /dev/null +++ b/common/cpw/mods/fml/relauncher/ILibrarySet.java @@ -0,0 +1,30 @@ +package cpw.mods.fml.relauncher; + +/** + * Interface for certain core plugins to register libraries to + * be loaded in by the FML class loader at launch time + * + * @author cpw + * + */ +public interface ILibrarySet +{ + /** + * Return a list of libraries available from a common location + * + * @return + */ + String[] getLibraries(); + /** + * Return the string encoded sha1 hash for each library in the returned list + * + * @return + */ + String[] getHashes(); + /** + * Return the root URL format string from which this library set can be obtained + * There needs to be a single %s string substitution which is the library name + * @return + */ + String getRootURL(); +} diff --git a/common/cpw/mods/fml/relauncher/RelaunchLibraryManager.java b/common/cpw/mods/fml/relauncher/RelaunchLibraryManager.java index a13c1e936a..73cdf332d3 100644 --- a/common/cpw/mods/fml/relauncher/RelaunchLibraryManager.java +++ b/common/cpw/mods/fml/relauncher/RelaunchLibraryManager.java @@ -19,17 +19,165 @@ import java.nio.channels.ReadableByteChannel; import java.nio.channels.FileChannel.MapMode; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; +import cpw.mods.fml.common.discovery.ModCandidate; + public class RelaunchLibraryManager { - private static String[] libraries = { "argo-2.25.jar","guava-12.0.jar","asm-all-4.0.jar" }; - private static String[] checksums = { "bb672829fde76cb163004752b86b0484bd0a7f4b", "5bc66dd95b79db1e437eb08adba124a3e4088dc0", "98308890597acb64047f7e896638e0d98753ae82" }; + private static String[] plugins = { "cpw.mods.fml.relauncher.FMLCorePlugin" , "net.minecraftforge.classloading.FMLForgePlugin" }; private static final String HEXES = "0123456789abcdef"; + private static List loadedLibraries = new ArrayList(); public static void handleLaunch(File mcDir, RelaunchClassLoader actualClassLoader) + { + List loadPlugins = new ArrayList(); + List libraries = new ArrayList(); + for (String s : plugins) + { + try + { + IFMLLoadingPlugin plugin = (IFMLLoadingPlugin) Class.forName(s, true, actualClassLoader).newInstance(); + loadPlugins.add(plugin); + for (String libName : plugin.getLibraryRequestClass()) + { + libraries.add((ILibrarySet) Class.forName(libName, true, actualClassLoader).newInstance()); + } + } + catch (Exception e) + { + // HMMM + } + } + + if (loadPlugins.isEmpty()) + { + throw new RuntimeException("A fatal error has occured - no valid fml load plugin was found - this is a completely corrupt FML installation."); + } + + List caughtErrors = new ArrayList(); + try + { + File libDir; + try + { + libDir = setupLibDir(mcDir); + } + catch (Exception e) + { + caughtErrors.add(e); + return; + } + + for (ILibrarySet lib : libraries) + { + for (int i=0; i"); + FMLLog.severe("The following is the errors that caused the setup to fail. " + + "They may help you diagnose and resolve the issue"); + for (Throwable t : caughtErrors) + { + FMLLog.log(Level.SEVERE, t, "Fatal error"); + } + throw new RuntimeException("A fatal error occured and FML cannot continue"); + } + } + + for (IFMLLoadingPlugin plug : loadPlugins) + { + for (String xformClass : plug.getASMTransformerClass()) + { + actualClassLoader.registerTransformer(xformClass); + } + } + try + { + Class loaderClazz = Class.forName("cpw.mods.fml.common.Loader", true, actualClassLoader); + } + catch (Exception e) + { + // Load in the Loader, make sure he's ready to roll - this will initialize most of the rest of minecraft here + throw new RuntimeException(e); + } + } + + /** + * @param mcDir + * @return + */ + private static File setupLibDir(File mcDir) { File libDir = new File(mcDir,"lib"); try @@ -48,51 +196,7 @@ public class RelaunchLibraryManager { throw new RuntimeException(String.format("Found a lib file in %s that's not a directory", mcDir.getName())); } - - for (int i=0; i loaderClazz = Class.forName("cpw.mods.fml.common.Loader", true, actualClassLoader); - } - catch (Exception e) - { - // Load in the Loader, make sure he's ready to roll - throw new RuntimeException(e); - } + return libDir; } private static String generateChecksum(File file) @@ -119,20 +223,12 @@ public class RelaunchLibraryManager return null; } } - private static void downloadFile(File libFile) + private static void downloadFile(File libFile, String rootUrl) { - // try -// { -// JOptionPane.showMessageDialog(null, String.format("Downloading required FML library %s from github.com",libName)); -// } -// catch (HeadlessException he) -// { -// // Ignore -// } try { - URL libDownload = new URL(String.format("http://cloud.github.com/downloads/cpw/FML/%s",libFile.getName())); - System.out.printf("Downloading %s..", libDownload.toString()); + URL libDownload = new URL(String.format(rootUrl,libFile.getName())); + FMLLog.info("Downloading %s", libDownload.toString()); InputStream urlConn = libDownload.openStream(); ReadableByteChannel urlChannel = Channels.newChannel(urlConn); FileOutputStream libFileStream = new FileOutputStream(libFile); @@ -142,11 +238,19 @@ public class RelaunchLibraryManager libFileStream.close(); urlChannel.close(); urlConn.close(); - System.out.println("download successful"); + FMLLog.info("Download complete"); } catch (Exception e) { - + FMLLog.severe("There was a problem downloading the file %s automatically. Perhaps you" + + "have an environment without internet access. You will need to download " + + "the file manually\n", libFile.getName()); + throw new RuntimeException("A download error occured", e); } } + + public static List getLibraries() + { + return loadedLibraries; + } }