/******************************************************************************* * Copyright (c) 2011-2014 SirSengir. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl-3.0.txt * * Various Contributors including, but not limited to: * SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges ******************************************************************************/ package forestry.plugins; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import java.io.File; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Random; import java.util.Set; import net.minecraft.command.CommandHandler; import net.minecraft.command.ICommand; import net.minecraft.server.MinecraftServer; import net.minecraft.util.StatCollector; import net.minecraft.world.World; import net.minecraft.world.chunk.IChunkProvider; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.common.config.Property; import cpw.mods.fml.common.IFuelHandler; import cpw.mods.fml.common.event.FMLInterModComms; import cpw.mods.fml.common.network.IGuiHandler; import cpw.mods.fml.common.registry.GameRegistry; import forestry.Forestry; import forestry.api.core.ForestryAPI; import forestry.core.IPickupHandler; import forestry.core.IResupplyHandler; import forestry.core.ISaveEventHandler; import forestry.core.utils.Log; public class PluginManager { private static final String MODULE_CONFIG_FILE_NAME = "modules.cfg"; private static final String CATEGORY_MODULES = "modules"; public static final ArrayList guiHandlers = Lists.newArrayList(); public static final ArrayList pickupHandlers = Lists.newArrayList(); public static final ArrayList saveEventHandlers = Lists.newArrayList(); public static final ArrayList resupplyHandlers = Lists.newArrayList(); private static final Set loadedModules = EnumSet.noneOf(Module.class); private static final Set unloadedModules = EnumSet.allOf(Module.class); private static Stage stage = Stage.SETUP; public enum Stage { SETUP, SETUP_DISABLED, PRE_INIT, INIT, POST_INIT, FINISHED } public enum Module { CORE(new PluginCore(), false), FLUIDS(new PluginFluids(), false), APICULTURE(new PluginApiculture()), ARBORICULTURE(new PluginArboriculture()), ENERGY(new PluginEnergy()), FACTORY(new PluginFactory()), FARMING(new PluginFarming()), FOOD(new PluginFood()), LEPIDOPTEROLOGY(new PluginLepidopterology()), MAIL(new PluginMail()), STORAGE(new PluginStorage()), BUILDCRAFT_FUELS(new PluginBuildCraftFuels()), BUILDCRAFT_RECIPES(new PluginBuildCraftRecipes()), BUILDCRAFT_STATEMENTS(new PluginBuildCraftStatements()), BUILDCRAFT_TRANSPORT(new PluginBuildCraftTransport()), AGRICRAFT(new PluginAgriCraft()), BIOMESOPLENTY(new PluginBiomesOPlenty()), CHISEL(new PluginChisel()), ENDERIO(new PluginEnderIO()), EREBUS(new PluginErebus()), EXTRAUTILITIES(new PluginExtraUtilities()), GROWTHCRAFT(new PluginGrowthCraft()), HARVESTCRAFT(new PluginHarvestCraft()), IMMERSIVEENGINEERING(new PluginImmersiveEngineering()), INDUSTRIALCRAFT(new PluginIC2()), MAGICALCROPS(new PluginMagicalCrops()), NATURA(new PluginNatura()), PLANTMEGAPACK(new PluginPlantMegaPack()), WITCHERY(new PluginWitchery()); static { ForestryAPI.enabledPlugins = new HashSet<>(); } private final ForestryPlugin instance; private final boolean canBeDisabled; Module(ForestryPlugin plugin) { this(plugin, true); } Module(ForestryPlugin plugin, boolean canBeDisabled) { this.instance = plugin; this.canBeDisabled = canBeDisabled; } public ForestryPlugin instance() { return instance; } public boolean isEnabled() { return ForestryAPI.enabledPlugins.contains(toString()); } public boolean canBeDisabled() { return canBeDisabled; } public String configName() { return toString().toLowerCase(Locale.ENGLISH).replace('_', '.'); } } public static final EnumSet configDisabledModules = EnumSet.noneOf(Module.class); public static Stage getStage() { return stage; } public static EnumSet getLoadedModules() { return EnumSet.copyOf(loadedModules); } private static void registerHandlers(ForestryPlugin plugin) { Log.fine("Registering Handlers for Plugin: {0}", plugin); IGuiHandler guiHandler = plugin.getGuiHandler(); if (guiHandler != null) { guiHandlers.add(guiHandler); } plugin.registerPacketHandlers(); IPickupHandler pickupHandler = plugin.getPickupHandler(); if (pickupHandler != null) { pickupHandlers.add(pickupHandler); } ISaveEventHandler saveHandler = plugin.getSaveEventHandler(); if (saveHandler != null) { saveEventHandlers.add(saveHandler); } IResupplyHandler resupplyHandler = plugin.getResupplyHandler(); if (resupplyHandler != null) { resupplyHandlers.add(resupplyHandler); } IFuelHandler fuelHandler = plugin.getFuelHandler(); if (fuelHandler != null) { GameRegistry.registerFuelHandler((fuelHandler)); } } private static void configureModules() { Locale locale = Locale.getDefault(); Locale.setDefault(Locale.ENGLISH); Configuration config = new Configuration(new File(Forestry.instance.getConfigFolder(), MODULE_CONFIG_FILE_NAME)); config.load(); config.addCustomCategoryComment(CATEGORY_MODULES, "Disabling these modules can greatly change how the mod functions.\n" + "Your mileage may vary, please report any issues."); Set toLoad = EnumSet.allOf(Module.class); Iterator it = toLoad.iterator(); while (it.hasNext()) { Module m = it.next(); if (!m.canBeDisabled()) { continue; } if (!isEnabled(config, m)) { it.remove(); Log.info("Module disabled: {0}", m); continue; } ForestryPlugin plugin = m.instance; if (!plugin.isAvailable()) { it.remove(); Log.info("Module {0} failed to load: {1}", plugin, plugin.getFailMessage()); continue; } } boolean changed; do { changed = false; it = toLoad.iterator(); while (it.hasNext()) { Module m = it.next(); Set deps = m.instance().getDependancies(); if (!toLoad.containsAll(deps)) { it.remove(); changed = true; Log.warning("Module {0} is missing dependencies: {1}", m, deps); continue; } } } while (changed); unloadedModules.removeAll(toLoad); loadedModules.addAll(toLoad); for (Module m : loadedModules) { ForestryAPI.enabledPlugins.add(m.toString()); } if (config.hasChanged()) { config.save(); } Locale.setDefault(locale); } public static void runSetup() { stage = Stage.SETUP; configureModules(); for (Module m : loadedModules) { ForestryPlugin plugin = m.instance; Log.fine("Setup Start: {0}", plugin); plugin.setupAPI(); Log.fine("Setup Complete: {0}", plugin); } stage = Stage.SETUP_DISABLED; for (Module m : unloadedModules) { ForestryPlugin plugin = m.instance; Log.fine("Disabled-Setup Start: {0}", plugin); plugin.disabledSetupAPI(); Log.fine("Disabled-Setup Complete: {0}", plugin); } } public static void runPreInit() { stage = Stage.PRE_INIT; for (Module m : loadedModules) { ForestryPlugin plugin = m.instance; Log.fine("Pre-Init Start: {0}", plugin); registerHandlers(plugin); plugin.preInit(); plugin.registerItems(); if (Module.BUILDCRAFT_STATEMENTS.isEnabled()) { plugin.registerTriggers(); } if (Module.STORAGE.isEnabled()) { plugin.registerBackpackItems(); plugin.registerCrates(); } Log.fine("Pre-Init Complete: {0}", plugin); } } public static void runInit() { stage = Stage.INIT; for (Module m : loadedModules) { ForestryPlugin plugin = m.instance; Log.fine("Init Start: {0}", plugin); plugin.doInit(); plugin.registerRecipes(); Log.fine("Init Complete: {0}", plugin); } } public static void runPostInit() { stage = Stage.POST_INIT; for (Module m : loadedModules) { ForestryPlugin plugin = m.instance; Log.fine("Post-Init Start: {0}", plugin); plugin.postInit(); Log.fine("Post-Init Complete: {0}", plugin); } stage = Stage.FINISHED; } public static void serverStarting(MinecraftServer server) { CommandHandler commandManager = (CommandHandler) server.getCommandManager(); for (Module m : loadedModules) { ForestryPlugin plugin = m.instance; ICommand[] commands = plugin.getConsoleCommands(); if (commands == null) { continue; } for (ICommand command : commands) { commandManager.registerCommand(command); } } } public static void processIMCMessages(ImmutableList messages) { for (FMLInterModComms.IMCMessage message : messages) { for (Module m : loadedModules) { ForestryPlugin plugin = m.instance; if (plugin.processIMCMessage(message)) { break; } } } } public static void populateChunk(IChunkProvider chunkProvider, World world, Random rand, int chunkX, int chunkZ, boolean hasVillageGenerated) { for (Module m : loadedModules) { ForestryPlugin plugin = m.instance; plugin.populateChunk(chunkProvider, world, rand, chunkX, chunkZ, hasVillageGenerated); } } public static void populateChunkRetroGen(World world, Random rand, int chunkX, int chunkZ) { for (Module m : loadedModules) { ForestryPlugin plugin = m.instance; plugin.populateChunkRetroGen(world, rand, chunkX, chunkZ); } } private static boolean isEnabled(Configuration config, Module m) { Plugin info = m.instance().getClass().getAnnotation(Plugin.class); String comment = StatCollector.translateToLocal(info.unlocalizedDescription()); Property prop = config.get(CATEGORY_MODULES, m.configName(), true, comment); boolean enabled = prop.getBoolean(); if (!enabled) { configDisabledModules.add(m); } return enabled; } }