Files
MinecraftForge/common/fml/Loader.java
T

256 lines
8.7 KiB
Java
Raw Normal View History

2012-03-30 10:11:13 -04:00
/*
2012-03-30 11:35:04 -04:00
* The FML Forge Mod Loader suite.
2012-03-30 10:11:13 -04:00
* Copyright (C) 2012 cpw
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package fml;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
2012-03-30 01:12:59 -04:00
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
2012-03-30 01:12:59 -04:00
import java.util.Map;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
2012-03-30 01:12:59 -04:00
import java.util.logging.SimpleFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
2012-03-30 01:12:59 -04:00
import net.minecraft.src.BaseMod;
2012-03-30 10:11:13 -04:00
import fml.ml.ModLoaderModContainer;
2012-03-30 21:03:25 -04:00
public class Loader {
2012-03-30 01:12:59 -04:00
private enum State {
NOINIT, LOADING, PREINIT, INIT, POSTINIT, UP, ERRORED
};
2012-03-30 21:03:25 -04:00
private static Loader instance;
2012-03-30 21:21:43 -04:00
private static Logger LOG = Logger.getLogger("ForgeModLoader");
2012-03-30 01:12:59 -04:00
private static Pattern zipJar = Pattern.compile("([^\\s]+).(zip|jar)$");
private static Pattern modClass = Pattern.compile("(.*/)(mod\\_[^\\s]+).class$");
2012-03-30 21:03:25 -04:00
private static int major=Integer.parseInt("@MAJOR@");
private static int minor=Integer.parseInt("@MINOR@");
private static int rev =Integer.parseInt("@REV@");
private static int build=Integer.parseInt("@BUILD@");
private static String mcversion="@MCVERSION@";
private State state;
private ModClassLoader modClassLoader;
private List<ModContainer> mods;
private Map<String,ModContainer> namedMods;
public static Loader instance() {
2012-03-30 21:07:42 -04:00
if (instance==null) {
instance=new Loader();
}
return instance;
2012-03-30 21:03:25 -04:00
}
private Loader() {
Loader.LOG.setLevel(Level.ALL);
2012-03-30 01:12:59 -04:00
FileHandler fileHandler;
try {
fileHandler = new FileHandler("ForgeModLoader-%g.log", 0, 3);
fileHandler.setLevel(Level.ALL);
2012-03-30 21:03:25 -04:00
Loader.LOG.addHandler(fileHandler);
2012-03-30 01:12:59 -04:00
} catch (Exception e) {
// Whatever - give up
}
2012-03-30 21:21:43 -04:00
LOG.info(String.format("Forge Mod Loader version %d.%d.%d.%d for Minecraft %s loading.",major,minor,rev,build,mcversion));
2012-03-30 01:12:59 -04:00
}
private void sortModList() {
// NOOP for a minute
}
private void preModInit() {
2012-03-30 01:12:59 -04:00
state = State.PREINIT;
for (ModContainer mod : mods) {
if (mod.wantsPreInit()) {
2012-03-30 01:12:59 -04:00
LOG.finer(String.format("Pre-initializing %s", mod.getName()));
mod.preInit();
2012-03-30 01:12:59 -04:00
namedMods.put(mod.getName(), mod);
}
}
}
private void modInit() {
2012-03-30 01:12:59 -04:00
state = State.INIT;
for (ModContainer mod : mods) {
2012-03-30 01:12:59 -04:00
LOG.finer(String.format("Initializing %s", mod.getName()));
mod.init();
}
}
private void postModInit() {
2012-03-30 01:12:59 -04:00
state = State.POSTINIT;
for (ModContainer mod : mods) {
if (mod.wantsPostInit()) {
2012-03-30 01:12:59 -04:00
LOG.finer(String.format("Post-initializing %s", mod.getName()));
mod.postInit();
}
}
}
private void load() {
File modsDir = new File(".", "mods");
String canonicalModsPath;
try {
canonicalModsPath = modsDir.getCanonicalPath();
} catch (IOException ioe) {
2012-03-30 01:12:59 -04:00
LOG.severe(String.format("Failed to resolve mods directory mods %s", modsDir.getAbsolutePath()));
LOG.throwing("fml.server.Loader", "initialize", ioe);
throw new LoaderException(ioe);
}
if (!modsDir.exists()) {
LOG.fine(String.format("No mod directory found, creating one: %s", canonicalModsPath));
try {
modsDir.mkdir();
} catch (Exception e) {
LOG.throwing("fml.server.Loader", "initialize", e);
throw new LoaderException(e);
}
}
if (!modsDir.isDirectory()) {
LOG.severe(String.format("Attempting to load mods from %s, which is not a directory", canonicalModsPath));
LoaderException loaderException = new LoaderException();
LOG.throwing("fml.server.Loader", "initialize", loaderException);
throw loaderException;
}
File[] modList = modsDir.listFiles();
// Sort the files into alphabetical order first
Arrays.sort(modList);
2012-03-30 01:12:59 -04:00
state = State.LOADING;
for (File modFile : modList) {
if (modFile.isDirectory()) {
LOG.info(String.format("Found directory %s. Attempting load", modFile.getName()));
attemptDirLoad(modFile);
2012-03-30 01:12:59 -04:00
LOG.info(String.format("Directory %s loaded successfully", modFile.getName()));
} else {
Matcher matcher = zipJar.matcher(modFile.getName());
2012-03-30 01:12:59 -04:00
if (matcher.matches()) {
LOG.info(String.format("Found zip or jar file %s. Attempting load.", matcher.group(0)));
attemptFileLoad(modFile);
2012-03-30 01:12:59 -04:00
LOG.info(String.format("File %s loaded successfully.", matcher.group(0)));
}
}
}
2012-03-30 01:12:59 -04:00
if (state == State.ERRORED) {
LOG.severe("A problem has occured during mod loading. Giving up now");
throw new RuntimeException("Giving up please");
}
}
private void attemptDirLoad(File modDir) {
extendClassLoader(modDir);
2012-03-30 01:12:59 -04:00
File[] content = modDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return modClass.matcher(name).find();
}
});
for (File modClassFile : content) {
2012-03-30 01:12:59 -04:00
String clazzName = modClass.matcher(modClassFile.getName()).group(2);
LOG.fine(String.format("Found a mod class %s in directory %s. Attempting to load it", clazzName, modDir.getName()));
loadModClass(modDir, modClassFile.getName(), clazzName);
2012-03-30 01:12:59 -04:00
LOG.fine(String.format("Successfully loaded mod class %s", modClassFile.getName()));
}
}
private void loadModClass(File classSource, String classFileName, String clazzName) {
try {
2012-03-30 01:12:59 -04:00
System.out.printf("Loading %s\n", clazzName);
Class<?> clazz = Class.forName(clazzName, false, modClassLoader);
System.out.printf("Got %s\n", clazz);
if (clazz.isAnnotationPresent(Mod.class)) {
// an FML mod
mods.add(FMLModContainer.buildFor(clazz));
2012-03-30 01:12:59 -04:00
} else if (BaseMod.class.isAssignableFrom(clazz)) {
LOG.fine(String.format("ModLoader BaseMod class found: %s. Loading", clazzName));
@SuppressWarnings("unchecked")
Class<? extends BaseMod> bmClazz = (Class<? extends BaseMod>) clazz;
ModContainer mc=new ModLoaderModContainer(bmClazz);
mods.add(mc);
LOG.fine(String.format("ModLoader BaseMod class loaded: %s.", clazzName));
} else {
// Unrecognized
}
2012-03-30 01:12:59 -04:00
} catch (Exception e) {
LOG.warning(String.format("Failed to load mod class %s in %s", classFileName, classSource.getName()));
LOG.throwing("fml.server.Loader", "attemptLoad", e);
state = State.ERRORED;
}
}
private void extendClassLoader(File file) {
2012-03-30 01:12:59 -04:00
if (modClassLoader == null) {
modClassLoader = new ModClassLoader();
}
try {
modClassLoader.addFile(file);
} catch (MalformedURLException e) {
throw new LoaderException(e);
}
}
private void attemptFileLoad(File modFile) {
extendClassLoader(modFile);
2012-03-30 01:12:59 -04:00
try {
2012-03-30 01:12:59 -04:00
ZipFile jar = new ZipFile(modFile);
for (ZipEntry ze : Collections.list(jar.entries())) {
2012-03-30 01:12:59 -04:00
Matcher match = modClass.matcher(ze.getName());
if (match.matches()) {
String pkg = match.group(1).replace('/', '.');
String clazzName = pkg + match.group(2);
LOG.fine(String.format("Found a mod class %s in file %s. Attempting to load it", clazzName, modFile.getName()));
loadModClass(modFile, ze.getName(), clazzName);
2012-03-30 01:12:59 -04:00
LOG.fine(String.format("Mod class %s loaded successfully", clazzName, modFile.getName()));
}
}
} catch (Exception e) {
LOG.warning(String.format("Zip file %s failed to read properly", modFile.getName()));
LOG.throwing("fml.server.Loader", "attemptFileLoad", e);
2012-03-30 01:12:59 -04:00
state = State.ERRORED;
}
}
2012-03-30 01:12:59 -04:00
public static List<ModContainer> getModList() {
2012-03-30 21:03:25 -04:00
return instance().mods;
}
2012-03-30 10:11:13 -04:00
public void loadMods() {
state = State.NOINIT;
mods = new ArrayList<ModContainer>();
load();
sortModList();
// Make mod list immutable
mods=Collections.unmodifiableList(mods);
preModInit();
}
public void initializeMods() {
modInit();
postModInit();
state = State.UP;
2012-03-30 21:03:25 -04:00
LOG.info("Forge Mod Loader load complete");
2012-03-30 10:11:13 -04:00
}
}