/* * CraftBook Copyright (C) 2010-2017 sk89q <http://www.sk89q.com> * CraftBook Copyright (C) 2011-2017 me4502 <http://www.me4502.com> * CraftBook Copyright (C) Contributors * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program. If not, * see <http://www.gnu.org/licenses/>. */ package com.sk89q.craftbook.sponge; import com.google.inject.Inject; import com.me4502.modularframework.ModuleController; import com.me4502.modularframework.ShadedModularFramework; import com.me4502.modularframework.exception.ModuleNotInstantiatedException; import com.me4502.modularframework.module.ModuleWrapper; import com.sk89q.craftbook.core.CraftBookAPI; import com.sk89q.craftbook.core.Mechanic; import com.sk89q.craftbook.core.st.SelfTriggerManager; import com.sk89q.craftbook.core.util.RegexUtil; import com.sk89q.craftbook.core.util.documentation.DocumentationGenerator; import com.sk89q.craftbook.core.util.documentation.DocumentationProvider; import com.sk89q.craftbook.sponge.command.AboutCommand; import com.sk89q.craftbook.sponge.command.ReportCommand; import com.sk89q.craftbook.sponge.command.docs.GenerateDocsCommand; import com.sk89q.craftbook.sponge.command.docs.GetDocsCommand; import com.sk89q.craftbook.sponge.st.SelfTriggeringMechanic; import com.sk89q.craftbook.sponge.st.SpongeSelfTriggerManager; import com.sk89q.craftbook.sponge.util.Metrics; import com.sk89q.craftbook.sponge.util.data.CraftBookData; import com.sk89q.craftbook.sponge.util.locale.TranslationsManager; import com.sk89q.craftbook.sponge.util.type.TypeSerializers; import ninja.leaping.configurate.ConfigurationOptions; import ninja.leaping.configurate.commented.CommentedConfigurationNode; import ninja.leaping.configurate.loader.ConfigurationLoader; import org.slf4j.Logger; import org.spongepowered.api.GameState; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.args.GenericArguments; import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.config.DefaultConfig; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.cause.Cause; import org.spongepowered.api.event.game.GameReloadEvent; import org.spongepowered.api.event.game.state.GamePreInitializationEvent; import org.spongepowered.api.event.game.state.GameStartedServerEvent; import org.spongepowered.api.event.game.state.GameStoppingServerEvent; import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.text.Text; import java.io.File; import java.io.IOException; import java.util.Optional; @Plugin(id = "craftbook", name = "CraftBook", version = "4.0", description = "CraftBook adds a number of new mechanics to Minecraft with no client mods required.") public class CraftBookPlugin extends CraftBookAPI { /* Configuration Data */ @Inject @DefaultConfig(sharedRoot = false) private File mainConfig; @Inject private Metrics metrics; @Inject @DefaultConfig(sharedRoot = false) private ConfigurationLoader<CommentedConfigurationNode> configManager; @Inject public PluginContainer container; public ModuleController<CraftBookPlugin> moduleController; private SelfTriggerManager selfTriggerManager; protected SpongeConfiguration config; ConfigurationOptions configurationOptions; public static String BUILD_NUMBER = "UNKNOWN"; public static String GIT_HASH = "UNKNOWN"; /* Logging */ @Inject private Logger logger; @Override public Logger getLogger() { return logger; } @Override public String getVersionString() { return this.container.getVersion().orElse("UNKNOWN") + '-' + BUILD_NUMBER + '-' + GIT_HASH; } public PluginContainer getContainer() { return this.container; } @Listener public void onPreInitialization(GamePreInitializationEvent event) { logger.info("Performing Pre-Initialization"); setInstance(this); // Load build information. container.getAsset("build.txt").ifPresent(asset -> { try { for (String line : asset.readLines()) { if (line.startsWith("hash=")) { if (line.contains("-")) { String[] bits = RegexUtil.MINUS_PATTERN.split(line.substring(5)); BUILD_NUMBER = bits[0]; GIT_HASH = bits[1]; } } } } catch (IOException e) { e.printStackTrace(); } }); TypeSerializers.registerDefaults(); CraftBookData.registerData(); discoverMechanics(); loadConfig(); if(config.dataOnlyMode.getValue()) { logger.info("Halting CraftBook Initialization - Data Only Mode! Note: Nothing will work."); return; } loadMechanics(event.getState()); } @Listener public void onInitialization(GameStartedServerEvent event) throws IllegalAccessException { if(config.dataOnlyMode.getValue()) { logger.info("Halting CraftBook Initialization - Data Only Mode! Note: Nothing will work."); return; } logger.info("Starting CraftBook"); CommandSpec generateDocsCommandSpec = CommandSpec.builder() .description(Text.of("Generates Documentation")) .permission("craftbook.docs.generate") .executor(new GenerateDocsCommand()) .build(); CommandSpec getDocsCommandSpec = CommandSpec.builder() .description(Text.of("Gets a Link to the Documentation")) .permission("craftbook.docs.get") .executor(new GetDocsCommand()) .build(); CommandSpec docsCommandSpec = CommandSpec.builder() .description(Text.of("Docs Base Command")) .permission("craftbook.docs") .child(generateDocsCommandSpec, "generate", "make", "build") .child(getDocsCommandSpec, "get", "help", "link") .build(); CommandSpec aboutCommandSpec = CommandSpec.builder() .description(Text.of("CraftBook About Command")) .permission("craftbook.about") .executor(new AboutCommand()) .build(); CommandSpec reportCommandSpec = CommandSpec.builder() .description(Text.of("CraftBook Report Command")) .permission("craftbook.report") .arguments( GenericArguments.flags().permissionFlag("craftbook.report.pastebin", "p").buildWith(GenericArguments.none()) ) .executor(new ReportCommand()) .build(); CommandSpec craftBookCommandSpec = CommandSpec.builder() .description(Text.of("CraftBook Base Command")) .permission("craftbook.craftbook") .child(docsCommandSpec, "docs", "manual", "man", "documentation", "doc", "help") .child(aboutCommandSpec, "about", "version", "ver") .child(reportCommandSpec, "report", "dump") .build(); Sponge.getCommandManager().register(this, craftBookCommandSpec, "cb", "craftbook"); loadMechanics(event.getState()); saveConfig(); //Do initial save of config. } @Listener public void onServerReload(GameReloadEvent event) { disableMechanics(); loadConfig(); for (GameState state : GameState.values()) { loadMechanics(state); } } @Listener public void onServerStopping(GameStoppingServerEvent event) { saveConfig(); disableMechanics(); } private void loadConfig() { config = new SpongeConfiguration(this, mainConfig, configManager); configurationOptions = ConfigurationOptions.defaults(); logger.info("Loading Configuration"); config.load(); TranslationsManager.initialize(); } public void saveConfig() { config.save(); } @Override public void discoverMechanics() { logger.info("Enumerating Mechanics"); moduleController = ShadedModularFramework.registerModuleController(this, Sponge.getGame()); File configDir = new File(getWorkingDirectory(), "mechanics"); configDir.mkdir(); moduleController.setConfigurationDirectory(configDir); moduleController.setConfigurationOptions(configurationOptions); moduleController.setOverrideConfigurationNode(false); //Standard Mechanics moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.variable.Variables", GameState.PRE_INITIALIZATION); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.blockbags.BlockBagManager", GameState.PRE_INITIALIZATION); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.BetterPhysics"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.BetterPlants"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.BounceBlocks"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.Chairs"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.ChunkAnchor"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.CookingPot"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.CommandSigns"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.Elevator"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.Snow"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.area.Bridge"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.area.Door"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.area.Gate"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.area.complex.ComplexArea"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.Bookshelf"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.Footprints"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.HeadDrops"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.HiddenSwitch"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.LightStone"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.Teleporter"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.treelopper.TreeLopper"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.PaintingSwitcher"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.pipe.Pipes"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.LightSwitch"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.signcopier.SignCopier"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.XPStorer"); //Circuit Mechanics moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.Ammeter"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.ics.ICSocket", GameState.PRE_INITIALIZATION); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.powerable.GlowStone"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.powerable.Netherrack"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.powerable.JackOLantern"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.powerable.RedstoneJukebox"); //Vehicle Mechanics //Boat moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.boat.EmptyDecay"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.boat.ExitRemover"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.boat.LandBoats"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.boat.RemoveEntities"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.boat.SpeedModifiers"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.boat.WaterPlaceOnly"); //Minecart moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.minecart.EmptyDecay"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.minecart.MobBlocker"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.minecart.MoreRails"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.minecart.NoCollide"); moduleController.registerModule("com.sk89q.craftbook.sponge.mechanics.minecart.RemoveEntities"); logger.info("Found " + moduleController.getModules().size()); } private void loadMechanics(GameState loadState) { moduleController.enableModules(input -> { if (loadState == input.getLoadState() && (config.enabledMechanics.getValue().contains(input.getName()) || "true".equalsIgnoreCase(System.getProperty("craftbook.enable-all")) || "true".equalsIgnoreCase(System.getProperty("craftbook.generate-docs")))) { logger.debug("Enabled: " + input.getName()); return true; } return false; }); for (ModuleWrapper module : moduleController.getModules()) { if (!module.isEnabled()) continue; try { if (module.getModuleUnchecked() instanceof SelfTriggeringMechanic && !getSelfTriggerManager().isPresent()) { this.selfTriggerManager = new SpongeSelfTriggerManager(); getSelfTriggerManager().ifPresent(SelfTriggerManager::initialize); break; } } catch(ModuleNotInstantiatedException e) { logger.error("Failed to initialize module: " + module.getName(), e); } } if("true".equalsIgnoreCase(System.getProperty("craftbook.generate-docs"))) { for (ModuleWrapper module : moduleController.getModules()) { if(!module.isEnabled()) continue; try { Mechanic mechanic = (Mechanic) module.getModuleUnchecked(); if(mechanic instanceof DocumentationProvider) DocumentationGenerator.generateDocumentation((DocumentationProvider) mechanic); } catch (ModuleNotInstantiatedException e) { logger.error("Failed to generate docs for module: " + module.getName(), e); } } DocumentationGenerator.generateDocumentation(config); } } private void disableMechanics() { getSelfTriggerManager().ifPresent(SelfTriggerManager::unload); this.selfTriggerManager = null; moduleController.disableModules(); } public Cause.Builder getCause() { return Cause.source(this.container); } @Override public Optional<SelfTriggerManager> getSelfTriggerManager() { return Optional.ofNullable(this.selfTriggerManager); } public SpongeConfiguration getConfig() { return config; } @Override public File getWorkingDirectory() { return mainConfig.getParentFile(); } public static CraftBookPlugin spongeInst() { return inst(); } }