From 0e4c801617b44ba63a39c5a4710f8e4924424f01 Mon Sep 17 00:00:00 2001 From: xGinko Date: Sun, 10 Sep 2023 22:51:50 +0200 Subject: [PATCH] begin work on commands --- .../villageroptimizer/VillagerOptimizer.java | 4 + .../commands/SubCommand.java | 11 +++ .../commands/VillagerOptimizerCommand.java | 37 ++++++++ .../optimizevillagers/OptVillagersRadius.java | 86 +++++++++++++++++++ .../UnOptVillagersRadius.java | 41 +++++++++ .../VillagerOptimizerCmd.java | 83 ++++++++++++++++++ .../subcommands/ReloadSubCmd.java | 38 ++++++++ .../subcommands/VersionSubCmd.java | 44 ++++++++++ .../config/LanguageCache.java | 14 +-- src/main/resources/lang/en_us.yml | 6 +- src/main/resources/plugin.yml | 7 ++ 11 files changed, 365 insertions(+), 6 deletions(-) create mode 100644 src/main/java/me/xginko/villageroptimizer/commands/SubCommand.java create mode 100644 src/main/java/me/xginko/villageroptimizer/commands/VillagerOptimizerCommand.java create mode 100644 src/main/java/me/xginko/villageroptimizer/commands/optimizevillagers/OptVillagersRadius.java create mode 100644 src/main/java/me/xginko/villageroptimizer/commands/unoptimizevillagers/UnOptVillagersRadius.java create mode 100644 src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/VillagerOptimizerCmd.java create mode 100644 src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/subcommands/ReloadSubCmd.java create mode 100644 src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/subcommands/VersionSubCmd.java diff --git a/src/main/java/me/xginko/villageroptimizer/VillagerOptimizer.java b/src/main/java/me/xginko/villageroptimizer/VillagerOptimizer.java index c33d491..1e7b447 100644 --- a/src/main/java/me/xginko/villageroptimizer/VillagerOptimizer.java +++ b/src/main/java/me/xginko/villageroptimizer/VillagerOptimizer.java @@ -1,6 +1,7 @@ package me.xginko.villageroptimizer; import me.xginko.villageroptimizer.cache.VillagerManager; +import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand; import me.xginko.villageroptimizer.config.Config; import me.xginko.villageroptimizer.config.LanguageCache; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; @@ -37,6 +38,8 @@ public final class VillagerOptimizer extends JavaPlugin { reloadLang(); logger.info("Loading Config"); reloadConfiguration(); + logger.info("Registering Commands"); + VillagerOptimizerCommand.reloadCommands(); logger.info("Done."); } @@ -59,6 +62,7 @@ public final class VillagerOptimizer extends JavaPlugin { public void reloadPlugin() { reloadLang(); reloadConfiguration(); + VillagerOptimizerCommand.reloadCommands(); } private void reloadConfiguration() { diff --git a/src/main/java/me/xginko/villageroptimizer/commands/SubCommand.java b/src/main/java/me/xginko/villageroptimizer/commands/SubCommand.java new file mode 100644 index 0000000..4ce3d53 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/commands/SubCommand.java @@ -0,0 +1,11 @@ +package me.xginko.villageroptimizer.commands; + +import net.kyori.adventure.text.TextComponent; +import org.bukkit.command.CommandSender; + +public abstract class SubCommand { + public abstract String getLabel(); + public abstract TextComponent getDescription(); + public abstract TextComponent getSyntax(); + public abstract void perform(CommandSender sender, String[] args); +} diff --git a/src/main/java/me/xginko/villageroptimizer/commands/VillagerOptimizerCommand.java b/src/main/java/me/xginko/villageroptimizer/commands/VillagerOptimizerCommand.java new file mode 100644 index 0000000..0a1619c --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/commands/VillagerOptimizerCommand.java @@ -0,0 +1,37 @@ +package me.xginko.villageroptimizer.commands; + +import me.xginko.villageroptimizer.VillagerOptimizer; +import me.xginko.villageroptimizer.commands.optimizevillagers.OptVillagersRadius; +import me.xginko.villageroptimizer.commands.unoptimizevillagers.UnOptVillagersRadius; +import me.xginko.villageroptimizer.commands.villageroptimizer.VillagerOptimizerCmd; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandMap; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; + +public interface VillagerOptimizerCommand extends CommandExecutor { + + String label(); + + HashSet commands = new HashSet<>(); + static void reloadCommands() { + commands.clear(); + + commands.add(new VillagerOptimizerCmd()); + commands.add(new OptVillagersRadius()); + commands.add(new UnOptVillagersRadius()); + + VillagerOptimizer plugin = VillagerOptimizer.getInstance(); + CommandMap commandMap = plugin.getServer().getCommandMap(); + for (VillagerOptimizerCommand command : commands) { + plugin.getCommand(command.label()).unregister(commandMap); + plugin.getCommand(command.label()).setExecutor(command); + } + } + + @Override + boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args); +} diff --git a/src/main/java/me/xginko/villageroptimizer/commands/optimizevillagers/OptVillagersRadius.java b/src/main/java/me/xginko/villageroptimizer/commands/optimizevillagers/OptVillagersRadius.java new file mode 100644 index 0000000..0277e27 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/commands/optimizevillagers/OptVillagersRadius.java @@ -0,0 +1,86 @@ +package me.xginko.villageroptimizer.commands.optimizevillagers; + +import me.xginko.villageroptimizer.VillagerOptimizer; +import me.xginko.villageroptimizer.cache.VillagerManager; +import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand; +import me.xginko.villageroptimizer.enums.OptimizationType; +import me.xginko.villageroptimizer.enums.Permissions; +import me.xginko.villageroptimizer.models.WrappedVillager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextReplacementConfig; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class OptVillagersRadius implements VillagerOptimizerCommand, TabCompleter { + + @Override + public String label() { + return "optimizevillagers"; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + return List.of("5", "10", "25", "50"); + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + if (sender.hasPermission(Permissions.Commands.OPTIMIZE_RADIUS.get())) { + if (!(sender instanceof Player player)) { + sender.sendMessage(Component.text("This command can only be executed as a player.") + .color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); + return true; + } + + if (args.length != 1) { + VillagerOptimizer.getLang(player.locale()).command_specify_radius.forEach(player::sendMessage); + return true; + } + + try { + int specifiedRadius = Integer.parseInt(args[0]) / 2; + int successCount = 0; + int failCount = 0; + VillagerManager villagerManager = VillagerOptimizer.getVillagerManager(); + + for (Entity entity : player.getNearbyEntities(specifiedRadius, specifiedRadius, specifiedRadius)) { + if (!entity.getType().equals(EntityType.VILLAGER)) continue; + Villager villager = (Villager) entity; + Villager.Profession profession = villager.getProfession(); + if (profession.equals(Villager.Profession.NITWIT) || profession.equals(Villager.Profession.NONE)) continue; + + WrappedVillager wVillager = villagerManager.getOrAdd(villager); + + if (!wVillager.isOptimized()) { + wVillager.setOptimization(OptimizationType.COMMAND); + wVillager.saveOptimizeTime(); + successCount++; + } + } + + final String success = Integer.toString(successCount); + final String radius = Integer.toString(specifiedRadius); + VillagerOptimizer.getLang(player.locale()).command_optimize_success.forEach(line -> player.sendMessage(line + .replaceText(TextReplacementConfig.builder().matchLiteral("%amount%").replacement(success).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%radius%").replacement(radius).build()) + )); + } catch (NumberFormatException e) { + VillagerOptimizer.getLang(player.locale()).command_radius_invalid.forEach(player::sendMessage); + } + } else { + sender.sendMessage(VillagerOptimizer.getLang(sender).no_permission); + } + return true; + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/commands/unoptimizevillagers/UnOptVillagersRadius.java b/src/main/java/me/xginko/villageroptimizer/commands/unoptimizevillagers/UnOptVillagersRadius.java new file mode 100644 index 0000000..94ee925 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/commands/unoptimizevillagers/UnOptVillagersRadius.java @@ -0,0 +1,41 @@ +package me.xginko.villageroptimizer.commands.unoptimizevillagers; + +import me.xginko.villageroptimizer.VillagerOptimizer; +import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand; +import me.xginko.villageroptimizer.enums.Permissions; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class UnOptVillagersRadius implements VillagerOptimizerCommand { + + @Override + public String label() { + return "unoptimizevillagers"; + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + if (sender.hasPermission(Permissions.Commands.UNOPTIMIZE_RADIUS.get())) { + if (!(sender instanceof Player player)) { + sender.sendMessage(Component.text("This command can only be executed as a player.") + .color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); + return true; + } + + if (args.length < 1) { + + return true; + } + + + } else { + sender.sendMessage(VillagerOptimizer.getLang(sender).no_permission); + } + return true; + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/VillagerOptimizerCmd.java b/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/VillagerOptimizerCmd.java new file mode 100644 index 0000000..f9d3eb6 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/VillagerOptimizerCmd.java @@ -0,0 +1,83 @@ +package me.xginko.villageroptimizer.commands.villageroptimizer; + +import me.xginko.villageroptimizer.commands.SubCommand; +import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand; +import me.xginko.villageroptimizer.commands.villageroptimizer.subcommands.ReloadSubCmd; +import me.xginko.villageroptimizer.commands.villageroptimizer.subcommands.VersionSubCmd; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class VillagerOptimizerCmd implements TabCompleter, VillagerOptimizerCommand { + + private final List subCommands = new ArrayList<>(7); + private final List tabCompleter = new ArrayList<>(7); + + public VillagerOptimizerCmd() { + subCommands.add(new ReloadSubCmd()); + subCommands.add(new VersionSubCmd()); + for (SubCommand subcommand : subCommands) { + tabCompleter.add(subcommand.getLabel()); + } + } + + @Override + public String label() { + return "villageroptimizer"; + } + + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + return args.length == 1 ? tabCompleter : Collections.emptyList(); + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + if (args.length > 0) { + boolean cmdExists = false; + for (SubCommand subCommand : subCommands) { + if (args[0].equalsIgnoreCase(subCommand.getLabel())) { + subCommand.perform(sender, args); + cmdExists = true; + break; + } + } + if (!cmdExists) sendCommandOverview(sender); + } else { + sendCommandOverview(sender); + } + return true; + } + + private void sendCommandOverview(CommandSender sender) { + if (!sender.hasPermission("anarchyexploitfixes.cmd.*")) return; + sender.sendMessage(Component.text("-----------------------------------------------------").color(NamedTextColor.GRAY)); + sender.sendMessage(Component.text("VillagerOptimizer Commands").color(NamedTextColor.BLUE)); + sender.sendMessage(Component.text("-----------------------------------------------------").color(NamedTextColor.GRAY)); + for (SubCommand subCommand : subCommands) { + sender.sendMessage( + subCommand.getSyntax() + .append(Component.text(" - ").color(NamedTextColor.DARK_GRAY)) + .append(subCommand.getDescription()) + ); + } + sender.sendMessage( + Component.text("/optimizevillagers ").color(NamedTextColor.BLUE) + .append(Component.text(" - ").color(NamedTextColor.DARK_GRAY)) + .append(Component.text("Optimize villagers in a radius").color(NamedTextColor.GRAY)) + ); + sender.sendMessage( + Component.text("/unoptmizevillagers").color(NamedTextColor.BLUE) + .append(Component.text(" - ").color(NamedTextColor.DARK_GRAY)) + .append(Component.text("Unoptimize villagers in a radius").color(NamedTextColor.GRAY)) + ); + sender.sendMessage(Component.text("-----------------------------------------------------").color(NamedTextColor.GRAY)); + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/subcommands/ReloadSubCmd.java b/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/subcommands/ReloadSubCmd.java new file mode 100644 index 0000000..7d375b9 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/subcommands/ReloadSubCmd.java @@ -0,0 +1,38 @@ +package me.xginko.villageroptimizer.commands.villageroptimizer.subcommands; + +import me.xginko.villageroptimizer.VillagerOptimizer; +import me.xginko.villageroptimizer.commands.SubCommand; +import me.xginko.villageroptimizer.enums.Permissions; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.command.CommandSender; + +public class ReloadSubCmd extends SubCommand { + @Override + public String getLabel() { + return "reload"; + } + @Override + public TextComponent getDescription() { + return Component.text("Reload the plugin configuration.").color(NamedTextColor.GRAY); + } + @Override + public TextComponent getSyntax() { + return Component.text("/villageroptimizer reload").color(NamedTextColor.GOLD); + } + + @Override + public void perform(CommandSender sender, String[] args) { + if (sender.hasPermission(Permissions.Commands.RELOAD.get())) { + sender.sendMessage(Component.text("Reloading VillagerOptimizer...").color(NamedTextColor.WHITE)); + VillagerOptimizer plugin = VillagerOptimizer.getInstance(); + plugin.getServer().getAsyncScheduler().runNow(plugin, reloadPlugin -> { + plugin.reloadPlugin(); + sender.sendMessage(Component.text("Reload complete.").color(NamedTextColor.GREEN)); + }); + } else { + sender.sendMessage(VillagerOptimizer.getLang(sender).no_permission); + } + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/subcommands/VersionSubCmd.java b/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/subcommands/VersionSubCmd.java new file mode 100644 index 0000000..2b0da8c --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/commands/villageroptimizer/subcommands/VersionSubCmd.java @@ -0,0 +1,44 @@ +package me.xginko.villageroptimizer.commands.villageroptimizer.subcommands; + +import io.papermc.paper.plugin.configuration.PluginMeta; +import me.xginko.villageroptimizer.VillagerOptimizer; +import me.xginko.villageroptimizer.commands.SubCommand; +import me.xginko.villageroptimizer.enums.Permissions; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.command.CommandSender; + +public class VersionSubCmd extends SubCommand { + @Override + public String getLabel() { + return "version"; + } + @Override + public TextComponent getDescription() { + return Component.text("Show the plugin version.").color(NamedTextColor.GRAY); + } + @Override + public TextComponent getSyntax() { + return Component.text("/villageroptimizer version").color(NamedTextColor.GOLD); + } + + @Override + public void perform(CommandSender sender, String[] args) { + if (sender.hasPermission(Permissions.Commands.VERSION.get())) { + PluginMeta pluginMeta = VillagerOptimizer.getInstance().getPluginMeta(); + sender.sendMessage( + Component.newline() + .append(Component.text(pluginMeta.getName()+" "+pluginMeta.getVersion()).color(NamedTextColor.BLUE).decorate(TextDecoration.BOLD) + .append(Component.text(" by ").color(NamedTextColor.GRAY)) + .append(Component.text(pluginMeta.getAuthors().get(0)).color(NamedTextColor.DARK_AQUA)) + .clickEvent(ClickEvent.openUrl(pluginMeta.getWebsite()))) + .append(Component.newline()) + ); + } else { + sender.sendMessage(VillagerOptimizer.getLang(sender).no_permission); + } + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/config/LanguageCache.java b/src/main/java/me/xginko/villageroptimizer/config/LanguageCache.java index 7742e72..fcf1045 100644 --- a/src/main/java/me/xginko/villageroptimizer/config/LanguageCache.java +++ b/src/main/java/me/xginko/villageroptimizer/config/LanguageCache.java @@ -18,7 +18,7 @@ public class LanguageCache { block_optimize_success, block_on_optimize_cooldown, block_unoptimize_success, workstation_optimize_success, workstation_on_optimize_cooldown, workstation_unoptimize_success, command_optimize_success, command_radius_limit_exceed, command_optimize_fail, command_unoptimize_success, - trades_restocked, optimize_for_trading, villager_leveling_up; + command_specify_radius, command_radius_invalid, trades_restocked, optimize_for_trading, villager_leveling_up; public LanguageCache(String lang) throws Exception { this.lang = loadLang(new File(VillagerOptimizer.getInstance().getDataFolder() + File.separator + "lang", lang + ".yml")); @@ -55,14 +55,18 @@ public class LanguageCache { this.workstation_unoptimize_success = getListTranslation("messages.workstation.unoptimize-success", List.of("Successfully unoptimized %villagertype% villager by removing workstation block %workstation%.")); // Command - this.command_optimize_success = getListTranslation("messages.workstation.optimize-success", + this.command_optimize_success = getListTranslation("messages.command.optimize-success", List.of("Successfully optimized %amount% villager(s) in a radius of %radius% blocks.")); - this.command_radius_limit_exceed = getListTranslation("messages.workstation.radius-limit-exceed", + this.command_radius_limit_exceed = getListTranslation("messages.command.radius-limit-exceed", List.of("The radius you entered exceeds the limit of %distance% blocks.")); - this.command_optimize_fail = getListTranslation("messages.workstation.optimize-fail", + this.command_optimize_fail = getListTranslation("messages.command.optimize-fail", List.of("%amount% villagers couldn't be optimized because they have recently been optimized.")); - this.command_unoptimize_success = getListTranslation("messages.workstation.unoptimize-success", + this.command_unoptimize_success = getListTranslation("messages.command.unoptimize-success", List.of("Successfully unoptimized %amount% villager(s) in a radius of %radius% blocks.")); + this.command_specify_radius = getListTranslation("messages.command.specify-radius", + List.of("Please specify a radius.")); + this.command_radius_invalid = getListTranslation("messages.command.radius-invalid", + List.of("The radius you entered is not a valid number. Try again.")); saveLang(); } diff --git a/src/main/resources/lang/en_us.yml b/src/main/resources/lang/en_us.yml index d921e28..add0df3 100644 --- a/src/main/resources/lang/en_us.yml +++ b/src/main/resources/lang/en_us.yml @@ -35,4 +35,8 @@ messages: radius-limit-exceed: - "The radius you entered exceeds the limit of %distance% blocks." unoptimize-success: - - "Successfully unoptimized %amount% villager(s) in a radius of %radius% blocks." \ No newline at end of file + - "Successfully unoptimized %amount% villager(s) in a radius of %radius% blocks." + specify-radius: + - "Please specify a radius." + radius-invalid: + - "The radius you entered is not a valid number. Try again." \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e70512e..2f6b041 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -10,12 +10,19 @@ commands: villageroptimizer: usage: /villageroptimizer [ reload, version ] description: VillagerOptimizer admin commands + aliases: + - voptimizer + - vo optimizevillagers: usage: /optimizevillagers description: Optmize villagers in a radius around you + aliases: + - optvils unoptmizevillagers: usage: /unoptimizevillagers description: Unoptmize villagers in a radius around you + aliases: + - unoptvils permissions: villageroptimizer.ignore: description: Players with this permission won't be able to use the plugin features