diff --git a/.gitignore b/.gitignore index 7219eb8..5bf6210 100755 --- a/.gitignore +++ b/.gitignore @@ -218,7 +218,7 @@ pip-log.txt .mr.developer.cfg .metadata/* TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar -#*.iml +*.iml *.name .idea dependency-reduced-pom.xml diff --git a/.idea/ButtonCore.iml b/.idea/ButtonCore.iml deleted file mode 100755 index c32b2ad..0000000 --- a/.idea/ButtonCore.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index a55e7a1..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100755 index b5342db..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100755 index adcb5b6..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 14d4bba..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_projectlombok_lombok_1_16_16.xml b/.idea/libraries/Maven__org_projectlombok_lombok_1_16_16.xml deleted file mode 100755 index d846a35..0000000 --- a/.idea/libraries/Maven__org_projectlombok_lombok_1_16_16.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/markdown-exported-files.xml b/.idea/markdown-exported-files.xml deleted file mode 100644 index 5d1f129..0000000 --- a/.idea/markdown-exported-files.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/markdown-navigator.xml b/.idea/markdown-navigator.xml deleted file mode 100644 index a280ac6..0000000 --- a/.idea/markdown-navigator.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/markdown-navigator/profiles_settings.xml b/.idea/markdown-navigator/profiles_settings.xml deleted file mode 100644 index 57927c5..0000000 --- a/.idea/markdown-navigator/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100755 index 1014481..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100755 index 8c958b0..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100755 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml deleted file mode 100644 index 781a0fd..0000000 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml deleted file mode 100755 index 6a0a7be..0000000 --- a/ButtonProcessor/ButtonProcessor.iml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Chroma-Core/Chroma-Core.iml b/Chroma-Core/Chroma-Core.iml deleted file mode 100644 index 112e8d8..0000000 --- a/Chroma-Core/Chroma-Core.iml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.java b/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.java index 7557932..b450bf4 100755 --- a/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.java @@ -117,8 +117,8 @@ public class MainPlugin extends ButtonPlugin { if (Bukkit.getPluginManager().isPluginEnabled("Votifier") && economy != null) Component.registerComponent(this, new VotifierComponent(economy)); ComponentManager.enableComponents(); - getCommand2MC().registerCommand(new ComponentCommand()); - getCommand2MC().registerCommand(new ChromaCommand()); + registerCommand(new ComponentCommand()); + registerCommand(new ChromaCommand()); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); TBMCCoreAPI.RegisterEventsForExceptions(getCommand2MC(), this); ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberCommand.java b/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberCommand.java index 395b71c..207e182 100644 --- a/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberCommand.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberCommand.java @@ -9,13 +9,9 @@ import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Date; +import java.util.concurrent.TimeUnit; -import static buttondevteam.core.MainPlugin.permission; - -@CommandClass(modOnly = true, path = "member", helpText = { // +@CommandClass(path = "member", helpText = { // "Member command", // "Add or remove server members.", // }) @@ -27,12 +23,12 @@ public class MemberCommand extends ICommand2MC { this.component = component; } - @Command2.Subcommand + @Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP) public boolean add(CommandSender sender, OfflinePlayer player) { return addRemove(sender, player, true); } - @Command2.Subcommand + @Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP) public boolean remove(CommandSender sender, OfflinePlayer player) { return addRemove(sender, player, false); } @@ -53,17 +49,25 @@ public class MemberCommand extends ICommand2MC { } @Command2.Subcommand - public void def(CommandSender sender) { - if(!(sender instanceof Player)) { - sender.sendMessage("§cYou need to be a player to use this command."); - return; - } - Player player= (Player) sender; + public void def(Player player) { String msg; - if (component.checkMember(player)) - msg="You are a member."; + if (!component.checkNotMember(player)) + msg = "You are a member."; else { - component.getRegTime(player); + double pt = component.getPlayTime(player); + long rt = component.getRegTime(player); + if (pt == -1 || rt == -1) { + Boolean result = component.addPlayerAsMember(player); + if (result == null) + msg = "Can't assign member group because groups are not supported by the permissions plugin."; + else if (result) + msg = "You meet all the requirements."; + else + msg = "You should be a member but failed to add you to the group."; + } else + msg = String.format("You need to play for %.2f hours total or play for %d more days to become a member.", + pt, TimeUnit.MILLISECONDS.toDays(rt)); } + player.sendMessage(msg); } } diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberComponent.java b/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberComponent.java index d003526..8151d2e 100644 --- a/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberComponent.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberComponent.java @@ -62,37 +62,60 @@ public class MemberComponent extends Component implements Listener { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { - if (checkMember(event.getPlayer()) && (checkRegTime(event.getPlayer()) || checkPlayTime(event.getPlayer()))) { - try { - if (permission.playerAddGroup(null, event.getPlayer(), memberGroup().get())) { - event.getPlayer().sendMessage("§bYou are a member now. YEEHAW"); - MainPlugin.Instance.getLogger().info("Added " + event.getPlayer().getName() + " as a member."); - } else { - MainPlugin.Instance.getLogger().warning("Failed to assign the member role! Please make sure the member group exists or disable the component if it's unused."); - } - } catch (UnsupportedOperationException e) { - MainPlugin.Instance.getLogger().warning("Failed to assign the member role! Groups are not supported by the permissions implementation."); - } + if (checkNotMember(event.getPlayer()) && (checkRegTime(event.getPlayer()) || checkPlayTime(event.getPlayer()))) { + addPlayerAsMember(event.getPlayer()); } } - public boolean checkMember(Player player) { + public Boolean addPlayerAsMember(Player player) { + try { + if (permission.playerAddGroup(null, player, memberGroup().get())) { + player.sendMessage("§bYou are a member now!"); + MainPlugin.Instance.getLogger().info("Added " + player.getName() + " as a member."); + return true; + } else { + MainPlugin.Instance.getLogger().warning("Failed to assign the member role! Please make sure the member group exists or disable the component if it's unused."); + return false; + } + } catch (UnsupportedOperationException e) { + MainPlugin.Instance.getLogger().warning("Failed to assign the member role! Groups are not supported by the permissions implementation."); + return null; + } + } + + public boolean checkNotMember(Player player) { return permission != null && !permission.playerInGroup(player, memberGroup().get()); } public boolean checkRegTime(Player player) { - return new Date(player.getFirstPlayed()).toInstant().plus(registeredForDays().get(), ChronoUnit.DAYS).isBefore(Instant.now()); + return getRegTime(player) == -1; } public boolean checkPlayTime(Player player) { - return player.getStatistic(playtime.getKey()) > playtime.getValue() * playedHours().get(); + return getPlayTime(player) > playtime.getValue() * playedHours().get(); } + /** + * Returns milliseconds + */ public long getRegTime(Player player) { Instant date = new Date(player.getFirstPlayed()).toInstant().plus(registeredForDays().get(), ChronoUnit.DAYS); - if(date.isBefore(Instant.now())) - return date.toEpochMilli()-Instant.now().toEpochMilli(); + if (date.isAfter(Instant.now())) + return date.toEpochMilli() - Instant.now().toEpochMilli(); return -1; } + public int getPlayTimeTotal(Player player) { + return player.getStatistic(playtime.getKey()); + } + + /** + * Returns hours + */ + public double getPlayTime(Player player) { + double pt = playedHours().get() - (double) getPlayTimeTotal(player) / playtime.getValue(); + if (pt < 0) return -1; + return pt; + } + } diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java b/Chroma-Core/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java index e9fd7c0..1182629 100755 --- a/Chroma-Core/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java @@ -18,6 +18,8 @@ import org.bukkit.boss.BossBar; import org.bukkit.command.CommandSender; import org.bukkit.scheduler.BukkitTask; +import javax.annotation.Nonnull; + @CommandClass(modOnly = true, path = "schrestart", helpText = { "Scheduled restart", // "This command restarts the server 1 minute after it's executed, warning players every 10 seconds.", // @@ -31,6 +33,7 @@ public class ScheduledRestartCommand extends ICommand2MC { private BukkitTask restarttask; private volatile BossBar restartbar; @Getter + @Nonnull private final RestartComponent component; @Command2.Subcommand diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index b16b447..cf7db91 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -4,6 +4,7 @@ import buttondevteam.buttonproc.HasConfig; import buttondevteam.core.ComponentManager; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.Command2MC; +import buttondevteam.lib.chat.ICommand2MC; import lombok.AccessLevel; import lombok.Getter; import org.bukkit.configuration.InvalidConfigurationException; @@ -23,7 +24,7 @@ import java.util.Stack; @HasConfig(global = true) public abstract class ButtonPlugin extends JavaPlugin { - @Getter + @Getter //Needs to be static as we don't know the plugin when a command is handled private static Command2MC command2MC = new Command2MC(); @Getter(AccessLevel.PROTECTED) private IHaveConfig iConfig; @@ -84,7 +85,7 @@ public abstract class ButtonPlugin extends JavaPlugin { if (ConfigData.saveNow(getConfig())) getLogger().info("Saved configuration changes."); iConfig = null; //Clearing the hashmap is not enough, we need to update the section as well - //TBMCChatAPI.RemoveCommands(this); - TODO + getCommand2MC().unregisterCommands(this); } catch (Exception e) { TBMCCoreAPI.SendException("Error while disabling plugin " + getName() + "!", e); } @@ -147,6 +148,16 @@ public abstract class ButtonPlugin extends JavaPlugin { } } + /** + * Registers command and sets its plugin. + * + * @param command The command to register + */ + protected void registerCommand(ICommand2MC command) { + command.registerToPlugin(this); + getCommand2MC().registerCommand(command); + } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface ConfigOpts { diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.java b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.java index c0b7b63..ba9925f 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.java @@ -24,7 +24,7 @@ import java.util.stream.Collectors; */ @HasConfig(global = false) //Used for obtaining javadoc public abstract class Component { - private static HashMap, Component> components = new HashMap<>(); + @SuppressWarnings("rawtypes") private static HashMap, Component> components = new HashMap<>(); @Getter private boolean enabled = false; @@ -61,7 +61,7 @@ public abstract class Component { * @param component The component to unregister * @return Whether the component is unregistered successfully (it also got disabled) */ - public static boolean unregisterComponent(T plugin, Component component) { + public static boolean unregisterComponent(T plugin, Component component) { return registerUnregisterComponent(plugin, component, false); } @@ -69,7 +69,7 @@ public abstract class Component { try { val metaAnn = component.getClass().getAnnotation(ComponentMetadata.class); if (metaAnn != null) { - Class[] dependencies = metaAnn.depends(); + @SuppressWarnings("rawtypes") Class[] dependencies = metaAnn.depends(); for (val dep : dependencies) { //TODO: Support dependencies at enable/disable as well if (!components.containsKey(dep)) { plugin.getLogger().warning("Failed to " + (register ? "" : "un") + "register component " + component.getClassName() + " as a required dependency is missing/disabled: " + dep.getSimpleName()); @@ -97,7 +97,6 @@ public abstract class Component { return true; } } - return true; //Component shouldn't be enabled } else { if (!components.containsKey(component.getClass())) return true; //Already unregistered @@ -111,8 +110,8 @@ public abstract class Component { } component.unregister(plugin); components.remove(component.getClass()); - return true; } + return true; } catch (Exception e) { TBMCCoreAPI.SendException("Failed to " + (register ? "" : "un") + "register component " + component.getClassName() + "!", e); return false; @@ -125,7 +124,7 @@ public abstract class Component { * * @param component The component to register */ - public static void setComponentEnabled(Component component, boolean enabled) throws UnregisteredComponentException { + public static void setComponentEnabled(Component component, boolean enabled) throws UnregisteredComponentException { if (!components.containsKey(component.getClass())) throw new UnregisteredComponentException(component); if (component.enabled == enabled) return; //Don't do anything @@ -141,7 +140,7 @@ public abstract class Component { //System.out.println("Done enabling "+component.getClassName()); } else { component.disable(); - //TBMCChatAPI.RemoveCommands(component); - TODO + ButtonPlugin.getCommand2MC().unregisterCommands(component); } } @@ -162,6 +161,7 @@ public abstract class Component { * * @return The currently registered components */ + @SuppressWarnings("rawtypes") public static Map, Component> getComponents() { return Collections.unmodifiableMap(components); } @@ -202,13 +202,16 @@ public abstract class Component { protected abstract void disable(); /** - * Registers a TBMCCommand to the component. Make sure to use {@link buttondevteam.lib.chat.CommandClass} and {@link buttondevteam.lib.chat.Command2.Subcommand}. + * Registers a command to the component. Make sure to use {@link buttondevteam.lib.chat.CommandClass} and {@link buttondevteam.lib.chat.Command2.Subcommand}. * You don't need to register the command in plugin.yml. * - * @param commandBase Custom coded command class + * @param command Custom coded command class */ - protected final void registerCommand(ICommand2MC commandBase) { - ButtonPlugin.getCommand2MC().registerCommand(commandBase); + protected final void registerCommand(ICommand2MC command) { + if (plugin instanceof ButtonPlugin) + command.registerToPlugin((ButtonPlugin) plugin); + command.registerToComponent(this); + ButtonPlugin.getCommand2MC().registerCommand(command); } /** diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java index 3983f61..1d20d08 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java @@ -12,6 +12,7 @@ import lombok.val; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; import java.io.InputStreamReader; import java.lang.annotation.ElementType; @@ -113,6 +114,8 @@ public abstract class Command2 private ArrayList commandHelp = new ArrayList<>(); //Mainly needed by Discord + private char commandChar; + /** * Adds a param converter that obtains a specific object from a string parameter. * The converter may return null. @@ -183,6 +186,7 @@ public abstract class Command2 params.add(cg); else { sender.sendMessage("§cYou need to be a " + sendertype.getSimpleName() + " to use this command."); + sender.sendMessage(sd.helpText); //Send what the command is about, could be useful for commands like /member where some subcommands aren't player-only return; } val paramArr = sd.method.getParameters(); @@ -259,6 +263,7 @@ public abstract class Command2 public abstract void registerCommand(TC command); protected void registerCommand(TC command, @SuppressWarnings("SameParameterValue") char commandChar) { + this.commandChar = commandChar; val path = command.getCommandPath(); int x = path.indexOf(' '); val mainPath = commandChar + path.substring(0, x == -1 ? path.length() : x); @@ -287,7 +292,7 @@ public abstract class Command2 var ht = command.getHelpText(method, ann); if (ht != null) { val subcommand = commandChar + path + //Add command path (class name by default) - (method.getName().equals("def") ? "" : " " + method.getName().replace('_', ' ').toLowerCase()); //Add method name, unless it's 'def' + getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def' ht = getParameterHelp(method, ht, subcommand); subcommands.put(subcommand, new SubcommandData<>(method, command, ht)); //Result of the above (def) is that it will show the help text scmdHelpList.add(subcommand); @@ -355,4 +360,31 @@ public abstract class Command2 /*public Set getAllSubcommands() { return Collections.unmodifiableSet(subcommands.keySet()); }*/ + + /** + * Unregisters all of the subcommands in the given command. + * + * @param command The command object + */ + public void unregisterCommand(ICommand2 command) { + var path = command.getCommandPath(); + for (val method : command.getClass().getMethods()) { + val ann = method.getAnnotation(Subcommand.class); + if (ann == null) continue; + val subcommand = commandChar + path + getCommandPath(method.getName(), ' '); + subcommands.remove(subcommand); + } + } + + /** + * It will start with the given replace char. + * + * @param methodName The method's name, method.getName() + * @param replaceChar The character to use between subcommands + * @return The command path starting with the replace char. + */ + @NotNull + public String getCommandPath(String methodName, char replaceChar) { + return methodName.equals("def") ? "" : replaceChar + methodName.replace('_', replaceChar).toLowerCase(); + } } diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java index 2f52c69..ff4b7f4 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -1,6 +1,8 @@ package buttondevteam.lib.chat; import buttondevteam.core.MainPlugin; +import buttondevteam.lib.architecture.ButtonPlugin; +import buttondevteam.lib.architecture.Component; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; @@ -17,9 +19,15 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; +import java.util.Optional; import java.util.function.Function; public class Command2MC extends Command2 implements Listener { + /** + * Don't use directly, use the method in Component and ButtonPlugin to automatically unregister the command when needed. + * + * @param command The command to register + */ @Override public void registerCommand(ICommand2MC command) { super.registerCommand(command, '/'); @@ -29,6 +37,13 @@ public class Command2MC extends Command2 implemen PermissionDefault.TRUE)); //Allow commands by default, it will check mod-only for (val method : command.getClass().getMethods()) { if (!method.isAnnotationPresent(Subcommand.class)) continue; + var path = getCommandPath(method.getName(), '.'); + if (path.length() > 0) { + var subperm = perm + path; + if (Bukkit.getPluginManager().getPermission(subperm) == null) //Check needed for plugin reset + Bukkit.getPluginManager().addPermission(new Permission(subperm, + PermissionDefault.TRUE)); //Allow commands by default, it will check mod-only + } String pg = permGroup(command, method); if (pg.length() == 0) continue; perm = "chroma." + pg; @@ -45,10 +60,14 @@ public class Command2MC extends Command2 implemen public boolean hasPermission(CommandSender sender, ICommand2MC command, Method method) { if (sender instanceof ConsoleCommandSender) return true; //Always allow the console + if (command == null) return true; //Allow viewing the command - it doesn't do anything anyway String pg; boolean p = true; + var cmdperm = "chroma.command." + command.getCommandPath().replace(' ', '.'); + var path = getCommandPath(method.getName(), '.'); String[] perms = { - "chroma.command." + command.getCommandPath().replace(' ', '.'), + path.length() > 0 ? cmdperm + path : null, + cmdperm, (pg = permGroup(command, method)).length() > 0 ? "chroma." + pg : null }; for (String perm : perms) { @@ -74,9 +93,11 @@ public class Command2MC extends Command2 implemen * @return The permission group for the subcommand or empty string */ private String permGroup(ICommand2MC command, Method method) { - val sc = method.getAnnotation(Subcommand.class); - if (sc != null && sc.permGroup().length() > 0) { - return sc.permGroup(); + if (method != null) { + val sc = method.getAnnotation(Subcommand.class); + if (sc != null && sc.permGroup().length() > 0) { + return sc.permGroup(); + } } if (getAnnForValue(command.getClass(), CommandClass.class, CommandClass::modOnly, false)) return Subcommand.MOD_GROUP; @@ -112,6 +133,21 @@ public class Command2MC extends Command2 implemen super.addParamConverter(cl, converter, "§c" + errormsg); } + public void unregisterCommands(ButtonPlugin plugin) { + /*var cmds = subcommands.values().stream().map(sd -> sd.command).filter(cmd -> plugin.equals(cmd.getPlugin())).toArray(ICommand2MC[]::new); + for (var cmd : cmds) + unregisterCommand(cmd);*/ + subcommands.values().removeIf(sd -> Optional.ofNullable(sd.command).map(ICommand2MC::getPlugin).map(plugin::equals).orElse(false)); + } + + public void unregisterCommands(Component component) { + /*var cmds = subcommands.values().stream().map(sd -> sd.command).filter(cmd -> component.equals(cmd.getComponent())).toArray(ICommand2MC[]::new); + for (var cmd : cmds) + unregisterCommand(cmd);*/ + subcommands.values().removeIf(sd -> Optional.ofNullable(sd.command).map(ICommand2MC::getComponent) + .map(comp -> component.getClass().getSimpleName().equals(comp.getClass().getSimpleName())).orElse(false)); + } + @EventHandler private void handleTabComplete(TabCompleteEvent event) { String commandline = event.getBuffer(); diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2.java index d0a202a..fc49c75 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -47,7 +47,7 @@ public abstract class ICommand2 { @Getter private final Command2 manager; //TIL that if I use a raw type on a variable then none of the type args will work (including what's defined on a method, not on the type) - public ICommand2(Command2 manager) { + public > ICommand2(Command2 manager) { path = getcmdpath(); this.manager = manager; } diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2MC.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2MC.java index 566285d..af12d61 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2MC.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/ICommand2MC.java @@ -1,9 +1,46 @@ package buttondevteam.lib.chat; import buttondevteam.lib.architecture.ButtonPlugin; +import buttondevteam.lib.architecture.Component; +import lombok.Getter; +import javax.annotation.Nullable; + +@SuppressWarnings("JavadocReference") public abstract class ICommand2MC extends ICommand2 { + @Getter + private ButtonPlugin plugin; + @Getter + @Nullable + private Component component; + public ICommand2MC() { super(ButtonPlugin.getCommand2MC()); } + + /** + * Called from {@link buttondevteam.lib.architecture.Component#registerCommand(ICommand2MC)} and {@link ButtonPlugin#registerCommand(ICommand2MC)} + */ + public void registerToPlugin(ButtonPlugin plugin) { + if (this.plugin == null) + this.plugin = plugin; + else + throw new IllegalStateException("The command is already assigned to a plugin!"); + } + + /** + * Called from {@link buttondevteam.lib.architecture.Component#registerCommand(ICommand2MC)} + */ + public void registerToComponent(Component component) { + if (this.component == null) + this.component = component; + else + throw new IllegalStateException("The command is already assigned to a component!"); + } + + /*@Override + public > void onRegister(Command2 manager) { + super.onRegister(manager); + onRegister((Command2MC) manager); //If ICommand2 is inherited with the same type arg, this would fail but I don't want to add another type param to ICommand2 + } //For example: class IOffender extends ICommand2*/ } diff --git a/CorePOM/CorePOM.iml b/CorePOM/CorePOM.iml deleted file mode 100644 index de84cf2..0000000 --- a/CorePOM/CorePOM.iml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file