diff --git a/src/main/java/me/xginko/villageroptimizer/commands/optimizevillagers/OptVillagersRadius.java b/src/main/java/me/xginko/villageroptimizer/commands/optimizevillagers/OptVillagersRadius.java index 0549675..594313e 100644 --- a/src/main/java/me/xginko/villageroptimizer/commands/optimizevillagers/OptVillagersRadius.java +++ b/src/main/java/me/xginko/villageroptimizer/commands/optimizevillagers/OptVillagersRadius.java @@ -3,6 +3,7 @@ package me.xginko.villageroptimizer.commands.optimizevillagers; import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerCache; import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand; +import me.xginko.villageroptimizer.config.Config; import me.xginko.villageroptimizer.enums.OptimizationType; import me.xginko.villageroptimizer.enums.Permissions; import me.xginko.villageroptimizer.WrappedVillager; @@ -25,12 +26,17 @@ import java.util.List; public class OptVillagersRadius implements VillagerOptimizerCommand, TabCompleter { - /* - * TODO: Radius limit, Cooldown, Compatibility with other types - * - * */ - private final List tabCompletes = List.of("5", "10", "25", "50"); + private final long cooldown; + private final int maxRadius; + + public OptVillagersRadius() { + Config config = VillagerOptimizer.getConfiguration(); + this.maxRadius = config.getInt("optimization-methods.command.optimizevillagers.max-block-radius", 100); + this.cooldown = config.getInt("optimization-methods.command.optimizevillagers.cooldown-seconds", 600, """ + Cooldown in seconds until a villager can be optimized again using the command.\s + Here for configuration freedom. Recommended to leave as is to not enable any exploitable behavior.""") * 1000L; + } @Override public String label() { @@ -44,20 +50,28 @@ public class OptVillagersRadius implements VillagerOptimizerCommand, TabComplete @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 by a player.") - .color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); - return true; - } + if (!(sender instanceof Player player)) { + sender.sendMessage(Component.text("This command can only be executed by a player.") + .color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); + return true; + } + if (sender.hasPermission(Permissions.Commands.OPTIMIZE_RADIUS.get())) { 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 specifiedRadius = Integer.parseInt(args[0]); + + if (specifiedRadius > maxRadius) { + final String maxRadiusStr = Integer.toString(maxRadius); + VillagerOptimizer.getLang(player.locale()).command_radius_limit_exceed.forEach(line -> player.sendMessage(line + .replaceText(TextReplacementConfig.builder().matchLiteral("%distance%").replacement(maxRadiusStr).build()) + )); + return true; + } VillagerCache villagerCache = VillagerOptimizer.getCache(); int successCount = 0; @@ -71,7 +85,7 @@ public class OptVillagersRadius implements VillagerOptimizerCommand, TabComplete WrappedVillager wVillager = villagerCache.getOrAdd(villager); - if (!wVillager.isOptimized()) { + if (wVillager.canOptimize(cooldown)) { wVillager.setOptimization(OptimizationType.COMMAND); wVillager.saveOptimizeTime(); successCount++; @@ -80,6 +94,14 @@ public class OptVillagersRadius implements VillagerOptimizerCommand, TabComplete } } + if (successCount <= 0 && failCount <= 0) { + final String radius = Integer.toString(specifiedRadius); + VillagerOptimizer.getLang(player.locale()).command_no_villagers_nearby.forEach(line -> player.sendMessage(line + .replaceText(TextReplacementConfig.builder().matchLiteral("%radius%").replacement(radius).build()) + )); + return true; + } + if (successCount > 0) { final String success = Integer.toString(successCount); final String radius = Integer.toString(specifiedRadius); @@ -100,6 +122,7 @@ public class OptVillagersRadius implements VillagerOptimizerCommand, TabComplete } 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 index 0613bec..38e3e31 100644 --- a/src/main/java/me/xginko/villageroptimizer/commands/unoptimizevillagers/UnOptVillagersRadius.java +++ b/src/main/java/me/xginko/villageroptimizer/commands/unoptimizevillagers/UnOptVillagersRadius.java @@ -1,11 +1,11 @@ package me.xginko.villageroptimizer.commands.unoptimizevillagers; -import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerCache; +import me.xginko.villageroptimizer.VillagerOptimizer; +import me.xginko.villageroptimizer.WrappedVillager; import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand; import me.xginko.villageroptimizer.enums.OptimizationType; import me.xginko.villageroptimizer.enums.Permissions; -import me.xginko.villageroptimizer.WrappedVillager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.format.NamedTextColor; @@ -25,12 +25,12 @@ import java.util.List; public class UnOptVillagersRadius implements VillagerOptimizerCommand, TabCompleter { - /* - * TODO: Radius limit, Cooldown, Compatibility with other types - * - * */ - private final List tabCompletes = List.of("5", "10", "25", "50"); + private final int maxRadius; + + public UnOptVillagersRadius() { + this.maxRadius = VillagerOptimizer.getConfiguration().getInt("optimization-methods.command.unoptimizevillagers.max-block-radius", 100); + } @Override public String label() { @@ -44,20 +44,28 @@ public class UnOptVillagersRadius implements VillagerOptimizerCommand, TabComple @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 by a player.") - .color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); - return true; - } + if (!(sender instanceof Player player)) { + sender.sendMessage(Component.text("This command can only be executed by a player.") + .color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); + return true; + } + if (sender.hasPermission(Permissions.Commands.UNOPTIMIZE_RADIUS.get())) { 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 specifiedRadius = Integer.parseInt(args[0]); + + if (specifiedRadius > maxRadius) { + final String maxRadiusStr = Integer.toString(maxRadius); + VillagerOptimizer.getLang(player.locale()).command_radius_limit_exceed.forEach(line -> player.sendMessage(line + .replaceText(TextReplacementConfig.builder().matchLiteral("%distance%").replacement(maxRadiusStr).build()) + )); + return true; + } VillagerCache villagerCache = VillagerOptimizer.getCache(); int successCount = 0; @@ -76,18 +84,26 @@ public class UnOptVillagersRadius implements VillagerOptimizerCommand, TabComple } } - final String successfullyUnoptimized = Integer.toString(successCount); - final String radius = Integer.toString(specifiedRadius); - VillagerOptimizer.getLang(player.locale()).command_unoptimize_success.forEach(line -> player.sendMessage(line - .replaceText(TextReplacementConfig.builder().matchLiteral("%amount%").replacement(successfullyUnoptimized).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%radius%").replacement(radius).build()) - )); + if (successCount <= 0) { + final String radius = Integer.toString(specifiedRadius); + VillagerOptimizer.getLang(player.locale()).command_no_villagers_nearby.forEach(line -> player.sendMessage(line + .replaceText(TextReplacementConfig.builder().matchLiteral("%radius%").replacement(radius).build()) + )); + } else { + final String successfullyUnoptimized = Integer.toString(successCount); + final String radius = Integer.toString(specifiedRadius); + VillagerOptimizer.getLang(player.locale()).command_unoptimize_success.forEach(line -> player.sendMessage(line + .replaceText(TextReplacementConfig.builder().matchLiteral("%amount%").replacement(successfullyUnoptimized).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/config/Config.java b/src/main/java/me/xginko/villageroptimizer/config/Config.java index d8e25e9..18c5f36 100644 --- a/src/main/java/me/xginko/villageroptimizer/config/Config.java +++ b/src/main/java/me/xginko/villageroptimizer/config/Config.java @@ -28,6 +28,7 @@ public class Config { "If set to true, will display messages based on client language"); this.cache_keep_time_seconds = getInt("general.cache-keep-time-seconds", 30, "The amount of time in seconds a villager will be kept in the plugin's cache."); + this.addComment("", ""); } private ConfigFile loadConfig(File ymlFile) throws Exception { @@ -51,6 +52,11 @@ public class Config { config.addDefault("config-version", 1.00); createTitledSection("General", "general"); createTitledSection("Optimization Methods", "optimization-methods"); + addComment("optimization-methods", """ + BE AWARE:\s + It is recommended to choose preferably one (no more than 2) of the below methods, as this can\s + get confusing and depending on your config exploitable otherwise. + """); config.addDefault("optimization-methods.nametag-optimization.enable", true); createTitledSection("Villager Chunk Limit", "villager-chunk-limit"); createTitledSection("Gameplay", "gameplay"); diff --git a/src/main/java/me/xginko/villageroptimizer/config/LanguageCache.java b/src/main/java/me/xginko/villageroptimizer/config/LanguageCache.java index ef5fa72..962b4c0 100644 --- a/src/main/java/me/xginko/villageroptimizer/config/LanguageCache.java +++ b/src/main/java/me/xginko/villageroptimizer/config/LanguageCache.java @@ -19,7 +19,8 @@ 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, - command_specify_radius, command_radius_invalid, trades_restocked, optimize_for_trading, villager_leveling_up; + command_specify_radius, command_radius_invalid, command_no_villagers_nearby, + 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")); @@ -68,6 +69,8 @@ public class LanguageCache { 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.")); + this.command_no_villagers_nearby = getListTranslation("messages.command.no-villagers-nearby", + List.of("Couldn't find any employed villagers within a radius of %radius%.")); saveLang(); } diff --git a/src/main/java/me/xginko/villageroptimizer/modules/VillagerOptimizerModule.java b/src/main/java/me/xginko/villageroptimizer/modules/VillagerOptimizerModule.java index 165e1aa..3f619ac 100644 --- a/src/main/java/me/xginko/villageroptimizer/modules/VillagerOptimizerModule.java +++ b/src/main/java/me/xginko/villageroptimizer/modules/VillagerOptimizerModule.java @@ -4,8 +4,8 @@ import me.xginko.villageroptimizer.modules.extras.PreventUnoptimizedTrading; import me.xginko.villageroptimizer.modules.extras.PreventVillagerDamage; import me.xginko.villageroptimizer.modules.extras.PreventVillagerTargetting; import me.xginko.villageroptimizer.modules.extras.MakeVillagersSpawnAdult; -import me.xginko.villageroptimizer.modules.fallback_mechanics.LevelVillagers; -import me.xginko.villageroptimizer.modules.fallback_mechanics.RestockTrades; +import me.xginko.villageroptimizer.modules.mechanics.LevelVillagers; +import me.xginko.villageroptimizer.modules.mechanics.RestockTrades; import me.xginko.villageroptimizer.modules.optimizations.OptimizeByBlock; import me.xginko.villageroptimizer.modules.optimizations.OptimizeByNametag; import me.xginko.villageroptimizer.modules.optimizations.OptimizeByWorkstation; diff --git a/src/main/java/me/xginko/villageroptimizer/modules/fallback_mechanics/LevelVillagers.java b/src/main/java/me/xginko/villageroptimizer/modules/mechanics/LevelVillagers.java similarity index 98% rename from src/main/java/me/xginko/villageroptimizer/modules/fallback_mechanics/LevelVillagers.java rename to src/main/java/me/xginko/villageroptimizer/modules/mechanics/LevelVillagers.java index 8297413..65c913b 100644 --- a/src/main/java/me/xginko/villageroptimizer/modules/fallback_mechanics/LevelVillagers.java +++ b/src/main/java/me/xginko/villageroptimizer/modules/mechanics/LevelVillagers.java @@ -1,4 +1,4 @@ -package me.xginko.villageroptimizer.modules.fallback_mechanics; +package me.xginko.villageroptimizer.modules.mechanics; import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerCache; diff --git a/src/main/java/me/xginko/villageroptimizer/modules/fallback_mechanics/RestockTrades.java b/src/main/java/me/xginko/villageroptimizer/modules/mechanics/RestockTrades.java similarity index 98% rename from src/main/java/me/xginko/villageroptimizer/modules/fallback_mechanics/RestockTrades.java rename to src/main/java/me/xginko/villageroptimizer/modules/mechanics/RestockTrades.java index e7d8d35..d2d700d 100644 --- a/src/main/java/me/xginko/villageroptimizer/modules/fallback_mechanics/RestockTrades.java +++ b/src/main/java/me/xginko/villageroptimizer/modules/mechanics/RestockTrades.java @@ -1,4 +1,4 @@ -package me.xginko.villageroptimizer.modules.fallback_mechanics; +package me.xginko.villageroptimizer.modules.mechanics; import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerCache; diff --git a/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByBlock.java b/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByBlock.java index 044c859..3123efc 100644 --- a/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByBlock.java +++ b/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByBlock.java @@ -103,12 +103,9 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener { WrappedVillager wVillager = villagerCache.getOrAdd(villager); final double distance = entity.getLocation().distance(blockLoc); - if (distance < closestDistance) { - final OptimizationType type = wVillager.getOptimizationType(); - if (type.equals(OptimizationType.NONE) || type.equals(OptimizationType.COMMAND)) { - closestOptimizableVillager = wVillager; - closestDistance = distance; - } + if (distance < closestDistance && wVillager.canOptimize(cooldown)) { + closestOptimizableVillager = wVillager; + closestDistance = distance; } } @@ -156,12 +153,9 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener { WrappedVillager wVillager = villagerCache.getOrAdd(villager); final double distance = entity.getLocation().distance(blockLoc); - if (distance < closestDistance) { - final OptimizationType type = wVillager.getOptimizationType(); - if (type.equals(OptimizationType.WORKSTATION) || type.equals(OptimizationType.COMMAND)) { - closestOptimizedVillager = wVillager; - closestDistance = distance; - } + if (distance < closestDistance && wVillager.isOptimized()) { + closestOptimizedVillager = wVillager; + closestDistance = distance; } } diff --git a/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByNametag.java b/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByNametag.java index 6a6844d..427274a 100644 --- a/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByNametag.java +++ b/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByNametag.java @@ -91,8 +91,6 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener { WrappedVillager wVillager = villagerCache.getOrAdd(villager); if (nametags.contains(nameTag.toLowerCase())) { - if (wVillager.isOptimized()) return; - if (wVillager.canOptimize(cooldown) || player.hasPermission(Permissions.Bypass.NAMETAG_COOLDOWN.get())) { wVillager.setOptimization(OptimizationType.NAMETAG); wVillager.saveOptimizeTime(); @@ -111,7 +109,7 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener { } } } else { - if (wVillager.getOptimizationType().equals(OptimizationType.NAMETAG)) { + if (wVillager.isOptimized()) { wVillager.setOptimization(OptimizationType.NONE); if (shouldNotifyPlayer) VillagerOptimizer.getLang(player.locale()).nametag_unoptimize_success.forEach(player::sendMessage); diff --git a/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByWorkstation.java b/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByWorkstation.java index e85a555..242ab37 100644 --- a/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByWorkstation.java +++ b/src/main/java/me/xginko/villageroptimizer/modules/optimizations/OptimizeByWorkstation.java @@ -87,12 +87,9 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener WrappedVillager wVillager = villagerCache.getOrAdd(villager); final double distance = entity.getLocation().distance(workstationLoc); - if (distance < closestDistance) { - final OptimizationType type = wVillager.getOptimizationType(); - if (type.equals(OptimizationType.NONE) || type.equals(OptimizationType.COMMAND)) { - closestOptimizableVillager = wVillager; - closestDistance = distance; - } + if (distance < closestDistance && wVillager.canOptimize(cooldown)) { + closestOptimizableVillager = wVillager; + closestDistance = distance; } } @@ -143,12 +140,9 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener WrappedVillager wVillager = villagerCache.getOrAdd(villager); final double distance = entity.getLocation().distance(workstationLoc); - if (distance < closestDistance) { - final OptimizationType type = wVillager.getOptimizationType(); - if (type.equals(OptimizationType.WORKSTATION) || type.equals(OptimizationType.COMMAND)) { - closestOptimizedVillager = wVillager; - closestDistance = distance; - } + if (distance < closestDistance && wVillager.canOptimize(cooldown)) { + closestOptimizedVillager = wVillager; + closestDistance = distance; } } diff --git a/src/main/resources/lang/en_us.yml b/src/main/resources/lang/en_us.yml index 59d35a7..44e663f 100644 --- a/src/main/resources/lang/en_us.yml +++ b/src/main/resources/lang/en_us.yml @@ -39,4 +39,6 @@ messages: 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 + - "The radius you entered is not a valid number. Try again." + no-villagers-nearby: + - "Couldn't find any employed villagers within a radius of %radius%." \ No newline at end of file