diff --git a/.idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_v1_0_g8d3b6b6_296.xml b/.idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_248b0d8d0a_1.xml similarity index 55% rename from .idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_v1_0_g8d3b6b6_296.xml rename to .idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_248b0d8d0a_1.xml index 8991a67..0d3e00e 100644 --- a/.idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_v1_0_g8d3b6b6_296.xml +++ b/.idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_248b0d8d0a_1.xml @@ -1,13 +1,13 @@ - + - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_c8cb88f27a_1.xml b/.idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_431c5273c2_1.xml similarity index 55% rename from .idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_c8cb88f27a_1.xml rename to .idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_431c5273c2_1.xml index b5aaa43..19b24a3 100644 --- a/.idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_c8cb88f27a_1.xml +++ b/.idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_431c5273c2_1.xml @@ -1,13 +1,13 @@ - + - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_bukkit_bukkit_1_13_1_R0_1_SNAPSHOT.xml b/.idea/libraries/Maven__org_bukkit_bukkit_1_13_1_R0_1_SNAPSHOT.xml index 4f2c5e4..63108e8 100644 --- a/.idea/libraries/Maven__org_bukkit_bukkit_1_13_1_R0_1_SNAPSHOT.xml +++ b/.idea/libraries/Maven__org_bukkit_bukkit_1_13_1_R0_1_SNAPSHOT.xml @@ -1,13 +1,13 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_spigotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml b/.idea/libraries/Maven__org_spigotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml index 42f0d6f..b6f88ae 100644 --- a/.idea/libraries/Maven__org_spigotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml +++ b/.idea/libraries/Maven__org_spigotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml @@ -1,13 +1,13 @@ - + - + - + \ No newline at end of file diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index 73696cd..4902d56 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -12,6 +12,7 @@ + diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java new file mode 100644 index 0000000..a83037b --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -0,0 +1,30 @@ +package buttondevteam.core; + +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.TBMCCommandBase; +import org.bukkit.command.CommandSender; + +@CommandClass(modOnly = true) +public class ComponentCommand extends TBMCCommandBase { + @Override + public boolean OnCommand(CommandSender sender, String alias, String[] args) { + if (args.length < 2) + return false; + switch (args[0]) { + case "enable": + break; + case "disable": + break; + case "list": + break; + default: + return false; + } + return true; + } + + @Override + public String[] GetHelpText(String alias) { + return new String[0]; + } +} diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java new file mode 100644 index 0000000..023dee4 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java @@ -0,0 +1,33 @@ +package buttondevteam.core; + +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException; + +public final class ComponentManager { + private ComponentManager() {} + + /** + * Enables components based on a configuration + */ + public static void enableComponents() { + //Component.getComponents().values().stream().filter(c->cs.getConfigurationSection(c.getClass().getSimpleName()).getBoolean("enabled")).forEach(c-> { + Component.getComponents().values().stream().filter(c -> c.shouldBeEnabled().get()).forEach(c -> { + try { + Component.setComponentEnabled(c, true); + } catch (UnregisteredComponentException ignored) { //This *should* never happen + } + }); + } + + /** + * Disables all components that are enabled + */ + public static void disableComponents() { + Component.getComponents().values().stream().filter(Component::isEnabled).forEach(c -> { + try { + Component.setComponentEnabled(c, false); + } catch (UnregisteredComponentException ignored) { //This *should* never happen + } + }); + } +} diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index b25ed1f..ec130f1 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -40,6 +40,7 @@ public class MainPlugin extends JavaPlugin { setupPermissions(); Test = getConfig().getBoolean("test", true); saveConfig(); + ComponentManager.enableComponents(); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class); TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fOOC§f", Color.White, "ooc", null)); @@ -67,6 +68,7 @@ public class MainPlugin extends JavaPlugin { @Override public void onDisable() { + ComponentManager.disableComponents(); logger.info("Saving player data..."); TBMCPlayerBase.savePlayers(); logger.info("Player data saved."); diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 33c6788..d59cbd9 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -1,17 +1,75 @@ package buttondevteam.lib.architecture; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCCommandBase; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NonNull; +import lombok.experimental.var; import lombok.val; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; +import java.util.Collections; import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +/** + * Configuration is based on class name + */ public abstract class Component { - private static HashMap, Component> components; + private static HashMap, Component> components = new HashMap<>(); + + @Getter + private boolean enabled = false; + @Getter(value = AccessLevel.PROTECTED) + @NonNull + private JavaPlugin plugin; + @NonNull + private ConfigurationSection config; + + public ConfigData shouldBeEnabled() { + return getData("enabled", true); + } + + private HashMap> datamap = new HashMap<>(); + + /** + * This method overload should only be used with primitves or String. + * + * @param path The path in config to use + * @param def The value to use by default + * @param The type of this variable (only use primitives or String) + * @return The data object that can be used to get or set the value + */ + @SuppressWarnings("unchecked") + protected ConfigData getData(String path, T def) { + ConfigData data = datamap.get(path); + if (data == null) datamap.put(path, data = new ConfigData<>(config, path, def)); + return (ConfigData) data; + } + + /** + * This method overload may be used with any class. + * + * @param path The path in config to use + * @param def The value to use by default + * @param getter A function that converts a primitive representation to the correct value + * @param setter A function that converts a value to a primitive representation + * @param The type of this variable (can be any class) + * @return The data object that can be used to get or set the value + */ + @SuppressWarnings("unchecked") + protected ConfigData getData(String path, T def, Function getter, Function setter) { + ConfigData data = datamap.get(path); + if (data == null) datamap.put(path, data = new ConfigData<>(config, path, def, getter, setter)); + return (ConfigData) data; + } /** * Registers a component checking it's dependencies and calling {@link #register(JavaPlugin)}.
@@ -20,18 +78,7 @@ public abstract class Component { * @param component The component to register */ public static void registerComponent(JavaPlugin plugin, Component component) { - val metaAnn = component.getClass().getAnnotation(ComponentMetadata.class); - if (metaAnn != null) { - Class[] dependencies = metaAnn.depends(); - for (val dep : dependencies) { - if (!components.containsKey(dep)) { - plugin.getLogger().warning("Failed to register component " + component.getClassName() + " as a required dependency is missing/disabled: " + dep.getSimpleName()); - return; - } - } - } - component.register(plugin); - components.put(component.getClass(), component); + registerUnregisterComponent(plugin, component, true); } /** @@ -44,27 +91,56 @@ public abstract class Component { val component = components.get(componentClass); if (component == null) return; //Failed to load - val metaAnn = componentClass.getAnnotation(ComponentMetadata.class); + registerUnregisterComponent(plugin, component, false); + } + + public static void registerUnregisterComponent(JavaPlugin plugin, Component component, boolean register) { + val metaAnn = component.getClass().getAnnotation(ComponentMetadata.class); if (metaAnn != null) { Class[] dependencies = metaAnn.depends(); for (val dep : dependencies) { if (!components.containsKey(dep)) { - plugin.getLogger().warning("Failed to unregister component " + component.getClassName() + " as a required dependency is missing/disabled: " + dep.getSimpleName()); + plugin.getLogger().warning("Failed to " + (register ? "" : "un") + "register component " + component.getClassName() + " as a required dependency is missing/disabled: " + dep.getSimpleName()); return; } } } - component.unregister(plugin); - components.remove(componentClass); + if (register) { + component.plugin = plugin; + var compconf = plugin.getConfig().getConfigurationSection("components"); + if (compconf == null) compconf = plugin.getConfig().createSection("components"); + component.config = compconf.getConfigurationSection(component.getClassName()); + if (component.config == null) component.config = compconf.createSection(component.getClassName()); + component.register(plugin); + components.put(component.getClass(), component); + } else { + component.unregister(plugin); + components.remove(component.getClass()); + } } /** - * This is used to send a warning if there are registered components on shutdown.
+ * Registers a component checking it's dependencies and calling {@link #register(JavaPlugin)}.
+ * Make sure to register the dependencies first. * - * @return If there are any registered components + * @param component The component to register */ - public static boolean haveRegisteredComponents() { - return components.size() > 0; + public static void setComponentEnabled(Component component, boolean enabled) throws UnregisteredComponentException { + if (!components.containsKey(component.getClass())) + throw new UnregisteredComponentException(component); + if (component.enabled = enabled) + component.enable(); + else + component.disable(); + } + + /** + * Returns the currently registered components
+ * + * @return The currently registered components + */ + public static Map, Component> getComponents() { + return Collections.unmodifiableMap(components); } /** @@ -73,7 +149,7 @@ public abstract class Component { * * @param plugin Plugin class called to register commands and listeners */ - public abstract void register(JavaPlugin plugin); + protected abstract void register(JavaPlugin plugin); /** * Unregisters the module, when called by the JavaPlugin class. Do @@ -81,7 +157,21 @@ public abstract class Component { * * @param plugin Plugin class called to register commands and listeners */ - public abstract void unregister(JavaPlugin plugin); + protected abstract void unregister(JavaPlugin plugin); + + /** + * Enables the module, when called by the JavaPlugin class. Call + * registerCommand() and registerListener() within this method.
+ * To access the plugin, use {@link #getPlugin()}. + */ + protected abstract void enable(); + + /** + * Disables the module, when called by the JavaPlugin class. Do + * any cleanups needed within this method. + * To access the plugin, use {@link #getPlugin()}. + */ + protected abstract void disable(); /** * Registers a TBMCCommand to the plugin. Make sure to add it to plugin.yml and use {@link buttondevteam.lib.chat.CommandClass}. diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java new file mode 100644 index 0000000..829ea2b --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java @@ -0,0 +1,43 @@ +package buttondevteam.lib.architecture; + +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.util.function.Function; + +/** + * Use the getter/setter constructor if {@link T} isn't a primitive type or String. + */ +@RequiredArgsConstructor +@AllArgsConstructor +public class ConfigData { //TODO: Save after a while + private final ConfigurationSection config; + private final String path; + private final T def; + /** + * The parameter is of a primitive type as returned by {@link YamlConfiguration#get(String)} + */ + private Function getter; + /** + * The result should be a primitive type or string that can be retrieved correctly later + */ + private Function setter; + + @SuppressWarnings("unchecked") + public T get() { + Object val = config.get(path, def); + if (getter != null) + return getter.apply(val); + return (T) val; + } + + public void set(T value) { + Object val; + if (setter != null) + val = setter.apply(value); + else val = value; + config.set(path, val); + } +} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/exceptions/UnregisteredComponentException.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/exceptions/UnregisteredComponentException.java new file mode 100644 index 0000000..e86c302 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/exceptions/UnregisteredComponentException.java @@ -0,0 +1,10 @@ +package buttondevteam.lib.architecture.exceptions; + +import buttondevteam.lib.architecture.Component; + +public class UnregisteredComponentException extends Throwable { + + public UnregisteredComponentException(Component component) { + super("The component '" + component.getClass().getSimpleName() + "' isn't registered!"); + } +}