diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index 8d30120..c4e7ce1 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -9,6 +9,11 @@ import lombok.Getter; import lombok.experimental.var; import org.bukkit.plugin.java.JavaPlugin; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Optional; import java.util.Stack; @HasConfig @@ -42,12 +47,13 @@ public abstract class ButtonPlugin extends JavaPlugin { @Override public final void onEnable() { loadConfig(); - IHaveConfig.pregenConfig(this, null); try { pluginEnable(); } catch (Exception e) { TBMCCoreAPI.SendException("Error while enabling plugin " + getName() + "!", e); } + if (configGenAllowed(this)) //If it's not disabled (by default it's not) + IHaveConfig.pregenConfig(this, null); } private void loadConfig() { @@ -91,4 +97,15 @@ public abstract class ButtonPlugin extends JavaPlugin { loaded = true; //Needed because for the first time it uses reloadConfig() to load it return true; } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface ConfigOpts { + boolean disableConfigGen() default false; + } + + public static boolean configGenAllowed(Object obj) { + return !Optional.ofNullable(obj.getClass().getAnnotation(ConfigOpts.class)) + .map(ConfigOpts::disableConfigGen).orElse(false); + } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 2385195..b98466b 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -45,7 +45,7 @@ public abstract class Component { * Registers a component checking it's dependencies and calling {@link #register(JavaPlugin)}.
* Make sure to register the dependencies first.
* The component will be enabled automatically, regardless of when it was registered.
- * If not using {@link ButtonPlugin}, call {@link ComponentManager#unregComponents(ButtonPlugin)} on plugin disable. + * If not using {@link ButtonPlugin}, call {@link ComponentManager#unregComponents(ButtonPlugin)} on plugin disable. * * @param component The component to register * @return Whether the component is registered successfully (it may have failed to enable) @@ -57,7 +57,7 @@ public abstract class Component { /** * Unregisters a component by calling {@link #unregister(JavaPlugin)}.
* Make sure to unregister the dependencies last.
- * Components will be unregistered in opposite order of registering by default by {@link ButtonPlugin} or {@link ComponentManager#unregComponents(ButtonPlugin)}. + * Components will be unregistered in opposite order of registering by default by {@link ButtonPlugin} or {@link ComponentManager#unregComponents(ButtonPlugin)}. * * @param component The component to unregister * @return Whether the component is unregistered successfully (it also got disabled) @@ -85,7 +85,6 @@ public abstract class Component { } component.plugin = plugin; updateConfig(plugin, component); - IHaveConfig.pregenConfig(component, null); component.register(plugin); components.put(component.getClass(), component); if (plugin instanceof ButtonPlugin) @@ -134,6 +133,8 @@ public abstract class Component { if (component.enabled = enabled) { updateConfig(component.getPlugin(), component); component.enable(); + if (ButtonPlugin.configGenAllowed(component)) + IHaveConfig.pregenConfig(component, null); } else { component.disable(); component.plugin.saveConfig(); @@ -193,7 +194,7 @@ public abstract class Component { /** * Disables the module, when called by the JavaPlugin class. Do * any cleanups needed within this method. - * To access the plugin, use {@link #getPlugin()}. + * To access the plugin, use {@link #getPlugin()}. */ protected abstract void disable(); @@ -229,14 +230,15 @@ public abstract class Component { /** * Returns a map of configs that are under the given key. - * @param key The key to use + * + * @param key The key to use * @param defaultProvider A mapping between config paths and config generators * @return A map containing configs */ protected Map getConfigMap(String key, Map> defaultProvider) { - val c=getConfig().getConfig(); - var cs=c.getConfigurationSection(key); - if(cs==null) cs=c.createSection(key); + val c = getConfig().getConfig(); + var cs = c.getConfigurationSection(key); + if (cs == null) cs = c.createSection(key); val res = cs.getValues(false).entrySet().stream().filter(e -> e.getValue() instanceof ConfigurationSection) .collect(Collectors.toMap(Map.Entry::getKey, kv -> new IHaveConfig((ConfigurationSection) kv.getValue(), getPlugin()::saveConfig))); if (res.size() == 0) { diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 9d2212c..8f41b3c 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -105,7 +105,7 @@ public abstract class Command2 sender.sendMessage(sd.helpText); return true; } - if (!hasPermission(sender, sd.command)) { + if (!hasPermission(sender, sd.command, sd.method)) { sender.sendMessage("§cYou don't have permission to use this command"); return true; } @@ -283,7 +283,7 @@ public abstract class Command2 return ht; } - public abstract boolean hasPermission(TP sender, TC command); + public abstract boolean hasPermission(TP sender, TC command, Method subcommand); public String[] getCommandsText() { return commandHelp.toArray(new String[0]); diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java index 82933cd..9dfb3b7 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -6,21 +6,27 @@ import org.bukkit.Bukkit; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.util.function.Function; public class Command2MC extends Command2 { @Override public void registerCommand(ICommand2MC command) { super.registerCommand(command, '/'); - Bukkit.getPluginManager().addPermission(new Permission("thorpe.command." + command.getCommandPath().replace(' ', '.'), - modOnly(command) ? PermissionDefault.OP : PermissionDefault.TRUE)); //Allow commands by default, unless it's mod only - TODO: Test + val perm = "thorpe.command." + command.getCommandPath().replace(' ', '.'); + if (Bukkit.getPluginManager().getPermission(perm) == null) //Check needed for plugin reset + Bukkit.getPluginManager().addPermission(new Permission(perm, + modOnly(command) ? PermissionDefault.OP : PermissionDefault.TRUE)); //Allow commands by default, unless it's mod only - TODO: Test } @Override - public boolean hasPermission(Command2MCSender sender, ICommand2MC command) { + public boolean hasPermission(Command2MCSender sender, ICommand2MC command, Method method) { + String pg; return modOnly(command) - ? MainPlugin.permission.has(sender.getSender(), "tbmc.admin") //TODO: Change when groups are implemented - //: MainPlugin.permission.has(sender.getSender(), permGroup()) - TODO: Check for subcommands (permGroup) + ? MainPlugin.permission.has(sender.getSender(), "tbmc.admin") + : (pg = permGroup(command, method)) != null + ? MainPlugin.permission.has(sender.getSender(), pg) : MainPlugin.permission.has(sender.getSender(), "thorpe.command." + command.getCommandPath().replace(' ', '.')); } @@ -31,11 +37,39 @@ public class Command2MC extends Command2 { * @return Whether the command is mod only */ private boolean modOnly(ICommand2MC command) { - for (Class cl = command.getClass(); cl != null; cl = cl.getSuperclass()) { - val cc = command.getClass().getAnnotation(CommandClass.class); - if (cc != null && cc.modOnly()) return true; + return getAnnForValue(command.getClass(), CommandClass.class, CommandClass::modOnly, false); + } + + /** + * Returns true if this class or any of the superclasses are mod only. + * + * @param method The subcommand to check + * @return The permission group for the subcommand or null + */ + private String permGroup(ICommand2MC command, Method method) { + val sc = method.getAnnotation(Subcommand.class); + if (sc != null && sc.permGroup().length() > 0) return sc.permGroup(); + return getAnnForValue(command.getClass(), CommandClass.class, CommandClass::permGroup, null); + } + + /** + * Loops until it finds a value that is not the same as def + * + * @param sourceCl The class which has the annotation + * @param annCl The annotation to get + * @param annMethod The annotation method to check + * @param def The value to ignore when looking for the result + * @param The annotation type + * @param The type of the value + * @return The value returned by the first superclass or def + */ + private V getAnnForValue(Class sourceCl, Class annCl, Function annMethod, V def) { + for (Class cl = sourceCl; cl != null; cl = cl.getSuperclass()) { + val cc = cl.getAnnotation(annCl); + V r; + if (cc != null && (r = annMethod.apply(cc)) != def) return r; } - return false; + return def; } /**