/*
* Copyright (c) CovertJaguar, 2014 http://railcraft.info
*
* This code is the property of CovertJaguar
* and may only be used with explicit written
* permission unless otherwise specified on the
* license page at http://railcraft.info/wiki/info:license.
*/
package mods.railcraft.common.modules;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.io.File;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import org.apache.logging.log4j.Level;
import mods.railcraft.common.core.Railcraft;
import mods.railcraft.common.gui.EnumGui;
import mods.railcraft.common.util.misc.Game;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.world.World;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
public class ModuleManager {
public static final String MODULE_CONFIG_FILE_NAME = "modules.cfg";
public static final String CATEGORY_MODULES = "modules";
public enum Stage {
PRE_INIT, INIT_FIRST, INIT_SECOND, POST_INIT, POST_INIT_NOT_LOADED, FINISHED;
}
public enum Module {
CORE(ModuleCore.class),
FACTORY(ModuleFactory.class),
EXTRAS(ModuleExtras.class),
TRACKS(ModuleTrack.class),
TRACKS_HIGHSPEED(ModuleTracksHighSpeed.class),
TRACKS_WOOD(ModuleTracksWood.class),
TRACKS_REINFORCED(ModuleTracksReinforced.class),
TRACKS_ELECTRIC(ModuleTracksElectric.class),
SIGNALS(ModuleSignals.class),
STRUCTURES(ModuleStructures.class),
AUTOMATION(ModuleAutomation.class),
TRANSPORT(ModuleTransport.class),
IC2(ModuleIC2.class),
FORESTRY(ModuleForestry.class),
THAUMCRAFT(ModuleThaumcraft.class),
STEAM(ModuleSteam.class),
WORLD(ModuleWorld.class),
CHUNK_LOADING(ModuleChunkLoading.class),
SEASONAL(ModuleSeasonal.class),
TRAIN(ModuleTrain.class),
LOCOMOTIVES(ModuleLocomotives.class),
ROUTING(ModuleRouting.class),
EMBLEM(getClass("mods.railcraft.common.modules.ModuleEmblem")),
MAGIC(ModuleMagic.class),
ELECTRICITY(ModuleElectricity.class);
private final RailcraftModule instance;
private Module(Class<? extends RailcraftModule> moduleClass) {
RailcraftModule inst = null;
if (moduleClass != null)
try {
inst = moduleClass.newInstance();
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
}
this.instance = inst;
}
public boolean isEnabled() {
return isModuleLoaded(this);
}
private static Class<? extends RailcraftModule> getClass(String className) {
Class<? extends RailcraftModule> moduleClass = null;
try {
moduleClass = (Class<? extends RailcraftModule>) Class.forName(className);
} catch (ClassNotFoundException ex) {
}
return moduleClass;
}
};
private static final Set<Module> loadedModules = EnumSet.noneOf(Module.class);
private static final Set<Module> unloadedModules = EnumSet.allOf(Module.class);
private static Stage stage = Stage.PRE_INIT;
private ModuleManager() {
}
public static Stage getStage() {
return stage;
}
public static void preInit() {
stage = Stage.PRE_INIT;
Locale locale = Locale.getDefault();
Locale.setDefault(Locale.ENGLISH);
Configuration config = new Configuration(new File(Railcraft.getMod().getConfigFolder(), MODULE_CONFIG_FILE_NAME));
config.load();
config.addCustomCategoryComment(CATEGORY_MODULES, "Disabling these modules can greatly change how the mod functions.\n"
+ "For example, disabling the Train Module will prevent you from linking carts.\n"
+ "Disabling the World Module will disable all world gen.\n"
+ "Disabling the Energy Module will remove the energy requirement from machines, "
+ "but will only do so if Forestry or Buildcraft are not installed.");
Set<Module> toLoad = EnumSet.allOf(Module.class);
Iterator<Module> it = toLoad.iterator();
while (it.hasNext()) {
Module m = it.next();
if (m == Module.CORE)
continue;
if (!isEnabled(config, m)) {
it.remove();
Game.log(Level.INFO, "Module disabled: {0}", m);
continue;
}
RailcraftModule inst = m.instance;
if (inst == null) {
it.remove();
Game.log(Level.INFO, "Module not found: {0}", m);
continue;
}
if (!inst.canModuleLoad()) {
it.remove();
inst.printLoadError();
continue;
}
}
boolean changed;
do {
changed = false;
it = toLoad.iterator();
while (it.hasNext()) {
Module m = it.next();
if (m.instance == null)
continue;
Set<Module> deps = m.instance.getDependencies();
if (!toLoad.containsAll(deps)) {
it.remove();
changed = true;
Game.log(Level.WARN, "Module {0} is missing dependancies: {1}", m, deps);
continue;
}
}
} while (changed);
unloadedModules.removeAll(toLoad);
loadedModules.addAll(toLoad);
if (config.hasChanged())
config.save();
Locale.setDefault(locale);
for (Module m : loadedModules) {
preInit(m);
}
stage = Stage.INIT_FIRST;
for (Module m : loadedModules) {
initFirst(m);
}
}
public static void init() {
stage = Stage.INIT_SECOND;
for (Module m : loadedModules) {
initSecond(m);
}
}
public static void postInit() {
stage = Stage.POST_INIT;
for (Module m : loadedModules) {
postInit(m);
}
stage = Stage.POST_INIT_NOT_LOADED;
for (Module m : unloadedModules) {
postInitNotLoaded(m);
}
stage = Stage.FINISHED;
}
private static boolean isEnabled(Configuration config, Module m) {
boolean defaultValue = true;
Property prop = config.get(CATEGORY_MODULES, m.toString().toLowerCase(Locale.ENGLISH).replace('_', '.'), defaultValue);
return prop.getBoolean(true);
}
public static boolean isModuleLoaded(Module module) {
return loadedModules.contains(module);
}
@SideOnly(Side.CLIENT)
public static GuiScreen getGuiScreen(EnumGui guiType, InventoryPlayer inv, Object obj, World world, int x, int y, int z) {
for (Module m : loadedModules) {
GuiScreen gui = m.instance.getGuiScreen(guiType, inv, obj, world, x, y, z);
if (gui != null)
return gui;
}
return null;
}
public static Container getGuiContainer(EnumGui guiType, InventoryPlayer inv, Object obj, World world, int x, int y, int z) {
for (Module m : loadedModules) {
Container con = m.instance.getGuiContainer(guiType, inv, obj, world, x, y, z);
if (con != null)
return con;
}
return null;
}
private static void preInit(Module module) {
RailcraftModule instance = module.instance;
if (instance != null) {
boolean override = false;
try {
override = instance.getClass().getMethod("preInit").getDeclaringClass() != RailcraftModule.class;
} catch (Exception ex) {
}
if (override) {
Game.log(Level.TRACE, "Pre-Init Start: {0}", instance);
instance.preInit();
Game.log(Level.TRACE, "Pre-Init Complete: {0}", instance);
}
}
}
private static void initFirst(Module module) {
RailcraftModule instance = module.instance;
if (instance != null) {
boolean override = false;
try {
override = instance.getClass().getMethod("initFirst").getDeclaringClass() != RailcraftModule.class;
} catch (Exception ex) {
}
if (override) {
Game.log(Level.TRACE, "Init-First Start: {0}", instance);
instance.initBlocks();
instance.initFirst();
Game.log(Level.TRACE, "Init-First Complete: {0}", instance);
}
}
}
private static void initSecond(Module module) {
RailcraftModule instance = module.instance;
if (instance != null) {
boolean override = false;
try {
override = instance.getClass().getMethod("initSecond").getDeclaringClass() != RailcraftModule.class;
} catch (Exception ex) {
}
if (override) {
Game.log(Level.TRACE, "Init-Second Start: {0}", instance);
instance.initRecipes(module);
instance.initSecond();
Game.log(Level.TRACE, "Init-Second Complete: {0}", instance);
}
}
}
private static void postInit(Module module) {
RailcraftModule instance = module.instance;
if (instance != null) {
boolean override = false;
try {
override = instance.getClass().getMethod("postInit").getDeclaringClass() != RailcraftModule.class;
} catch (Exception ex) {
}
if (override) {
Game.log(Level.TRACE, "Post-Init Start: {0}", instance);
instance.postInit();
instance.finalizeBlocks(module);
Game.log(Level.TRACE, "Post-Init Complete: {0}", instance);
}
}
}
private static void postInitNotLoaded(Module module) {
RailcraftModule instance = module.instance;
if (instance != null) {
boolean override = false;
try {
override = instance.getClass().getMethod("postInitNotLoaded").getDeclaringClass() != RailcraftModule.class;
} catch (Exception ex) {
}
if (override) {
Game.log(Level.TRACE, "Disabled-Init Start: {0}", instance);
instance.postInitNotLoaded();
Game.log(Level.TRACE, "Disabled-Init Complete: {0}", instance);
}
}
}
}