New logging stuff, also the early plugin api for forge

This commit is contained in:
Christian 2012-07-29 22:54:59 -04:00
parent 50ed44359d
commit ba28161f16
18 changed files with 560 additions and 244 deletions

View File

@ -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;
}

View File

@ -32,7 +32,7 @@ public class SpriteHelper
private static HashMap<String, BitSet> spriteInfo = new HashMap<String, BitSet>();
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;

View File

@ -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();
}
/**

View File

@ -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();
}
}

View File

@ -52,12 +52,12 @@ import cpw.mods.fml.common.toposort.TopologicalSort;
/**
* The loader class performs the actual loading of the mod code from disk.
*
*
* <p>
* 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.
* </p>
*
*
* <ol>
* <li>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.</li>
* </ol>
*
*
* 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<String, String> 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<String, String> 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<String, Boolean> isEnabled = Maps.transformValues(modStates, new Function<String, Boolean>()
{
@ -387,12 +387,12 @@ public class Loader
return !Boolean.parseBoolean(input);
}
});
for (Map.Entry<String, Boolean> 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<String> 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<String> 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);

View File

@ -37,7 +37,7 @@ 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", "argo-2.25.jar", "asm-all-4.0.jar", "guava-12.0.jar");
private static final List<String> 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);
}
}

View File

@ -34,11 +34,11 @@ public class DirectoryDiscoverer implements ITypeDiscoverer
public List<ModContainer> discover(ModCandidate candidate)
{
List<ModContainer> 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<ModContainer> 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);
}
}
}
}

View File

@ -21,7 +21,7 @@ public class JarDiscoverer implements ITypeDiscoverer
public List<ModContainer> discover(ModCandidate candidate)
{
List<ModContainer> 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
{

View File

@ -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<String> knownLibraries = ImmutableList.<String>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<ModContainer> identifyMods()
{
List<ModContainer> modList = Lists.newArrayList();
for (ModCandidate candidate : candidates)
{
try
@ -123,7 +126,7 @@ public class ModDiscoverer
Throwables.propagate(t);
}
}
return modList;
}
}

View File

@ -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)
{

View File

@ -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";
}
}

View File

@ -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"};
}
}

View File

@ -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<? super Object> client = ReflectionHelper.getClass(clientLoader, "net.minecraft.client.Minecraft");
ReflectionHelper.setPrivateValue(client, null, minecraftHome, "field_6275_Z", "ap", "minecraftDir");
Class<? super Object> 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();
}
}

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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<String> loadedLibraries = new ArrayList<String>();
public static void handleLaunch(File mcDir, RelaunchClassLoader actualClassLoader)
{
List<IFMLLoadingPlugin> loadPlugins = new ArrayList<IFMLLoadingPlugin>();
List<ILibrarySet> libraries = new ArrayList<ILibrarySet>();
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<Throwable> caughtErrors = new ArrayList<Throwable>();
try
{
File libDir;
try
{
libDir = setupLibDir(mcDir);
}
catch (Exception e)
{
caughtErrors.add(e);
return;
}
for (ILibrarySet lib : libraries)
{
for (int i=0; i<lib.getLibraries().length; i++)
{
boolean download = false;
String libName = lib.getLibraries()[i];
String checksum = lib.getHashes()[i];
File libFile = new File(libDir, libName);
if (!libFile.exists())
{
try
{
downloadFile(libFile, lib.getRootURL());
download = true;
}
catch (Throwable e)
{
caughtErrors.add(e);
continue;
}
}
if (libFile.exists() && !libFile.isFile())
{
caughtErrors.add(new RuntimeException(String.format("Found a file %s that is not a normal file - you should clear this out of the way", libName)));
continue;
}
String fileChecksum = generateChecksum(libFile);
if (!checksum.equals(fileChecksum))
{
caughtErrors.add(new RuntimeException(String.format("The file %s has an invalid checksum %s (expecting %s) - delete it and try again.", libName, fileChecksum, checksum)));
continue;
}
if (!download)
{
System.out.printf("Found library file %s present and correct in lib dir\n", libName);
}
else
{
System.out.printf("Library file %s was downloaded and verified successfully", libName);
}
try
{
actualClassLoader.addURL(libFile.toURI().toURL());
loadedLibraries.add(libName);
}
catch (MalformedURLException e)
{
caughtErrors.add(new RuntimeException(String.format("Should never happen - %s is broken - probably a somehow corrupted download. Delete it and try again.", libFile.getName()), e));
}
}
}
}
finally
{
if (!caughtErrors.isEmpty())
{
FMLLog.severe("There were errors during initial FML setup. " +
"Some files failed to download or were otherwise corrupted. " +
"You will need to manually obtain the following files from " +
"these download links and ensure your lib directory is clean. ");
for (ILibrarySet set : libraries)
{
for (String file : set.getLibraries())
{
FMLLog.severe("*** Download "+set.getRootURL(), file);
}
}
FMLLog.severe("<===========>");
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<libraries.length; i++)
{
String libName = libraries[i];
String checksum = checksums[i];
File libFile = new File(libDir, libName);
if (!libFile.exists())
{
downloadFile(libFile);
}
if (libFile.exists() && !libFile.isFile())
{
throw new RuntimeException(String.format("Found a file %s that is not a normal file", libName));
}
String fileChecksum = generateChecksum(libFile);
if (!checksum.equals(fileChecksum))
{
throw new RuntimeException(String.format("The file %s has an invalid checksum %s (expecting %s)", libName, fileChecksum, checksum));
}
try
{
actualClassLoader.addURL(libFile.toURI().toURL());
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
}
// Register our class loading transformer now we have everything we need
actualClassLoader.registerTransformer("cpw.mods.fml.common.asm.ASMTransformer");
// Register the forge class loading transformer now we have everything we need
actualClassLoader.registerTransformer("net.minecraftforge.asm.ASMTransformer");
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
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<String> getLibraries()
{
return loadedLibraries;
}
}