From e9080595c6bc7cc8169777be6597d1539bd72052 Mon Sep 17 00:00:00 2001 From: ThisTestUser Date: Wed, 18 Sep 2024 21:17:35 +0000 Subject: [PATCH] Merge changes from magma branch (except downgrade) --- .../api/agent/legacyagent/EnumTargetGoal.java | 2 + .../api/agent/legacyagent/LegacyAgent.java | 27 +- .../agent/legacyagent/LegacyBlockCheck.java | 4 +- .../api/agent/legacyagent/LegacyMats.java | 15 +- .../nuggetmc/tplus/api/utils/PlayerUtils.java | 6 +- .../main/java/net/nuggetmc/tplus/bot/Bot.java | 12 +- .../tplus/command/CommandHandler.java | 4 +- .../tplus/command/CommandInstance.java | 16 +- .../tplus/command/commands/BotCommand.java | 8 +- .../commands/BotEnvironmentCommand.java | 431 ++++++++++++++++++ .../net/nuggetmc/tplus/utils/Debugger.java | 35 ++ 11 files changed, 539 insertions(+), 21 deletions(-) create mode 100644 TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/commands/BotEnvironmentCommand.java diff --git a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/EnumTargetGoal.java b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/EnumTargetGoal.java index 02eb72f..61f86eb 100644 --- a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/EnumTargetGoal.java +++ b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/EnumTargetGoal.java @@ -12,6 +12,7 @@ public enum EnumTargetGoal { NEAREST_BOT("Locate the nearest bot."), NEAREST_BOT_DIFFER("Locate the nearest bot with a different username."), NEAREST_BOT_DIFFER_ALPHA("Locate the nearest bot with a different username after filtering out non-alpha characters."), + CUSTOM_LIST("Locate only the mob types specified in the custom list of mobs"), PLAYER("Target a single player. Defaults to NEAREST_VULNERABLE_PLAYER if no player found."), NONE("No target goal."); @@ -26,6 +27,7 @@ public enum EnumTargetGoal { this.put("nearestbot", NEAREST_BOT); this.put("nearestbotdiffer", NEAREST_BOT_DIFFER); this.put("nearestbotdifferalpha", NEAREST_BOT_DIFFER_ALPHA); + this.put("customlist", CUSTOM_LIST); this.put("player", PLAYER); } }; diff --git a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyAgent.java b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyAgent.java index 15794ab..53258f6 100644 --- a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyAgent.java +++ b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyAgent.java @@ -56,6 +56,9 @@ public class LegacyAgent extends Agent { private double regionWeightX; private double regionWeightY; private double regionWeightZ; + + public static final Set CUSTOM_TYPES_LIST = new HashSet<>(); + public static boolean areCustomTypesHostile = false; public LegacyAgent(BotManager manager, Plugin plugin) { super(manager, plugin); @@ -1456,7 +1459,7 @@ public class LegacyAgent extends Agent { case NEAREST_HOSTILE: { for (LivingEntity entity : bot.getBukkitEntity().getWorld().getLivingEntities()) { - if (entity instanceof Monster && validateCloserEntity(entity, loc, result)) { + if ((entity instanceof Monster || (areCustomTypesHostile && CUSTOM_TYPES_LIST.contains(entity.getType()))) && validateCloserEntity(entity, loc, result)) { result = entity; } } @@ -1476,7 +1479,7 @@ public class LegacyAgent extends Agent { case NEAREST_MOB: { for (LivingEntity entity : bot.getBukkitEntity().getWorld().getLivingEntities()) { - if (entity instanceof Mob && validateCloserEntity(entity, loc, result)) { + if ((entity instanceof Mob || CUSTOM_TYPES_LIST.contains(entity.getType())) && validateCloserEntity(entity, loc, result)) { result = entity; } } @@ -1526,15 +1529,29 @@ public class LegacyAgent extends Agent { } } } + + break; } - case PLAYER: { //Target a single player. Defaults to NEAREST_VULNERABLE_PLAYER if no player found. + + case CUSTOM_LIST: { + for (LivingEntity entity : bot.getBukkitEntity().getWorld().getLivingEntities()) { + if (CUSTOM_TYPES_LIST.contains(entity.getType()) && validateCloserEntity(entity, loc, result)) { + result = entity; + } + } + + break; + } + + case PLAYER: { if (bot.getTargetPlayer() != null) { Player player = Bukkit.getPlayer(bot.getTargetPlayer()); if (player != null && !botsInPlayerList.contains(player) && validateCloserEntity(player, loc, null)) { - return player; + result = player; } } - return locateTarget(bot, loc, EnumTargetGoal.NEAREST_VULNERABLE_PLAYER); + + break; } } TerminatorLocateTargetEvent event = new TerminatorLocateTargetEvent(bot, result); diff --git a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyBlockCheck.java b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyBlockCheck.java index 3fffacc..3b61e59 100644 --- a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyBlockCheck.java +++ b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyBlockCheck.java @@ -176,7 +176,7 @@ public class LegacyBlockCheck { // Blocks before must all be pass-through Material type = below.getBlock().getType(); - if (type.isSolid() || LegacyMats.canStandOn(type)) + if (LegacyMats.isSolid(type) || LegacyMats.canStandOn(type)) return false; below = below.clone(); } @@ -192,7 +192,7 @@ public class LegacyBlockCheck { Block next = itr.next().getBlock(); boolean placeable = nether ? LegacyMats.canPlaceTwistingVines(next) : LegacyMats.canPlaceWater(next, Optional.absent()); - if (placeable || (!next.getType().isSolid() && !LegacyMats.canStandOn(next.getType()))) + if (placeable || (!LegacyMats.isSolid(next.getType()) && !LegacyMats.canStandOn(next.getType()))) itr.remove(); } diff --git a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyMats.java b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyMats.java index 0311cb2..132c61e 100644 --- a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyMats.java +++ b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/agent/legacyagent/LegacyMats.java @@ -85,7 +85,7 @@ public class LegacyMats { Material.JUNGLE_SIGN, Material.JUNGLE_SLAB, Material.JUNGLE_STAIRS, Material.JUNGLE_TRAPDOOR, Material.JUNGLE_WALL_SIGN, Material.JUNGLE_WOOD, Material.SPRUCE_PLANKS, Material.SPRUCE_DOOR, Material.SPRUCE_FENCE, Material.SPRUCE_FENCE_GATE, Material.SPRUCE_LOG, Material.SPRUCE_SIGN, Material.SPRUCE_SLAB, Material.SPRUCE_STAIRS, Material.SPRUCE_TRAPDOOR, Material.SPRUCE_WALL_SIGN, Material.SPRUCE_WOOD, - Material.MANGROVE_PLANKS, Material.MANGROVE_DOOR, Material.MANGROVE_FENCE, Material.MANGROVE_FENCE_GATE, Material.MANGROVE_LOG, + Material.MANGROVE_PLANKS, Material.MANGROVE_DOOR, Material.MANGROVE_FENCE, Material.MANGROVE_FENCE_GATE, Material.MANGROVE_LOG, Material.MANGROVE_SIGN, Material.MANGROVE_SLAB, Material.MANGROVE_STAIRS, Material.MANGROVE_TRAPDOOR, Material.MANGROVE_WALL_SIGN, Material.MANGROVE_WOOD, Material.CRIMSON_PLANKS, Material.CRIMSON_DOOR, Material.CRIMSON_FENCE, Material.CRIMSON_FENCE_GATE, Material.CRIMSON_STEM, Material.CRIMSON_SIGN, Material.CRIMSON_SLAB, Material.CRIMSON_STAIRS, Material.CRIMSON_TRAPDOOR, Material.CRIMSON_WALL_SIGN, @@ -319,7 +319,7 @@ public class LegacyMats { } public static boolean canPlaceWater(Block block, Optional entityYPos) { - if (block.getType().isSolid()) { + if (isSolid(block.getType())) { if (block.getType() == Material.CHAIN && ((Chain)block.getBlockData()).getAxis() == Axis.Y && !((Chain)block.getBlockData()).isWaterlogged()) return false; @@ -381,7 +381,7 @@ public class LegacyMats { } public static boolean canPlaceTwistingVines(Block block) { - if (block.getType().isSolid()) { + if (isSolid(block.getType())) { if (block.getType().data == Leaves.class) return false; if (block.getType().name().endsWith("_CORAL_FAN") || block.getType().name().endsWith("_CORAL") @@ -515,4 +515,13 @@ public class LegacyMats { return false; } } + + /** + * This set stores solid materials that are added by mods. + */ + public static final Set SOLID_MATERIALS = new HashSet<>(); + + public static boolean isSolid(Material mat) { + return mat.isSolid() || SOLID_MATERIALS.contains(mat); + } } diff --git a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/utils/PlayerUtils.java b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/utils/PlayerUtils.java index 909bdd9..1b5fc7a 100644 --- a/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/utils/PlayerUtils.java +++ b/TerminatorPlus-API/src/main/java/net/nuggetmc/tplus/api/utils/PlayerUtils.java @@ -8,6 +8,8 @@ import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; +import net.nuggetmc.tplus.api.agent.legacyagent.LegacyMats; + import java.io.FileReader; import java.io.IOException; import java.util.HashSet; @@ -53,7 +55,7 @@ public class PlayerUtils { boolean check = false; for (int i = 0; i <= amount; i++) { - if (loc.clone().add(0, i, 0).getBlock().getType().isSolid()) { + if (LegacyMats.isSolid(loc.clone().add(0, i, 0).getBlock().getType())) { check = true; break; } @@ -76,7 +78,7 @@ public class PlayerUtils { break; } - if (check.getBlock().getType().isSolid()) { + if (LegacyMats.isSolid(check.getBlock().getType())) { return check.add(0, 1, 0); } } diff --git a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/bot/Bot.java b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/bot/Bot.java index aec6633..c53f235 100644 --- a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/bot/Bot.java +++ b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/bot/Bot.java @@ -93,6 +93,11 @@ public class Bot extends ServerPlayer implements Terminator { inPlayerList = true; } + // Magma fix - In case a mod causes the Bukkit entity to be created too early + try { + getClass().getMethod("resetBukkitEntity").invoke(this); + } catch (ReflectiveOperationException e) {} + //this.entityData.set(new EntityDataAccessor<>(16, EntityDataSerializers.BYTE), (byte) 0xFF); } @@ -544,7 +549,7 @@ public class Bot extends ServerPlayer implements Terminator { Location loc = new Location(world, x, position().y - 0.01, z); Block block = world.getBlockAt(loc); - if ((block.getType().isSolid() || LegacyMats.canStandOn(block.getType())) && BotUtils.overlaps(playerBox, block.getBoundingBox())) { + if ((LegacyMats.isSolid(block.getType()) || LegacyMats.canStandOn(block.getType())) && BotUtils.overlaps(playerBox, block.getBoundingBox())) { if (!locations.contains(block.getLocation())) { standingOn.add(block); locations.add(block.getLocation()); @@ -563,7 +568,7 @@ public class Bot extends ServerPlayer implements Terminator { blockBox.getMinY() + 1.5, blockBox.getMaxZ()); if ((LegacyMats.FENCE.contains(block.getType()) || LegacyMats.GATES.contains(block.getType())) - && block.getType().isSolid() && BotUtils.overlaps(playerBox, modifiedBox)) { + && LegacyMats.isSolid(block.getType()) && BotUtils.overlaps(playerBox, modifiedBox)) { if (!locations.contains(block.getLocation())) { standingOn.add(block); locations.add(block.getLocation()); @@ -815,7 +820,7 @@ public class Bot extends ServerPlayer implements Terminator { Block block = loc.getBlock(); World world = loc.getWorld(); - if (!block.getType().isSolid()) { + if (!LegacyMats.isSolid(block.getType())) { block.setType(type); if (world != null) world.playSound(loc, Sound.BLOCK_STONE_PLACE, SoundCategory.BLOCKS, 1, 1); } @@ -882,6 +887,7 @@ public class Bot extends ServerPlayer implements Terminator { @Override public void doTick() { + //detectEquipmentUpdatesPublic(); baseTick(); } diff --git a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/CommandHandler.java b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/CommandHandler.java index 0a7bb3d..7bc1d2c 100644 --- a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/CommandHandler.java +++ b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/CommandHandler.java @@ -8,6 +8,7 @@ import net.nuggetmc.tplus.command.annotation.Command; import net.nuggetmc.tplus.command.annotation.Require; import net.nuggetmc.tplus.command.commands.AICommand; import net.nuggetmc.tplus.command.commands.BotCommand; +import net.nuggetmc.tplus.command.commands.BotEnvironmentCommand; import net.nuggetmc.tplus.command.commands.MainCommand; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -43,7 +44,8 @@ public class CommandHandler { registerCommands( new MainCommand(this, "terminatorplus", "The TerminatorPlus main command.", "tplus"), new BotCommand(this, "bot", "The root command for bot management.", "npc"), - new AICommand(this, "ai", "The root command for bot AI training.") + new AICommand(this, "ai", "The root command for bot AI training."), + new BotEnvironmentCommand(this, "botenvironment", "Do /botenvironment help for more information.", "botenv") ); } diff --git a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/CommandInstance.java b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/CommandInstance.java index 216dbeb..3ecd585 100644 --- a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/CommandInstance.java +++ b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/CommandInstance.java @@ -62,9 +62,9 @@ public abstract class CommandInstance extends BukkitCommand { protected void addMethod(String name, CommandMethod method) { methods.put(name, method); } - + protected void addAlias(String alias, String name) { - aliasesToNames.put(alias, name); + aliasesToNames.put(alias, name); } @Override @@ -235,17 +235,25 @@ public abstract class CommandInstance extends BukkitCommand { @SuppressWarnings("unchecked") public List tabComplete(@Nonnull CommandSender sender, @Nonnull String label, @Nonnull String[] args) { if (args.length == 1) { - return methods.keySet().stream().filter(c -> !c.isEmpty()).collect(Collectors.toList()); + List result = methods.keySet().stream().filter(c -> !c.isEmpty() && c.contains(args[0])).collect(Collectors.toList()); + if (result.isEmpty()) { + // Add aliases also + methods.forEach((s, m) -> result.addAll(m.getAliases())); + return result.stream().filter(c -> c.contains(args[0])).collect(Collectors.toList()); + } + return result; } if (args.length > 1) { CommandMethod commandMethod = methods.get(args[0]); + if (commandMethod == null) + commandMethod = methods.values().stream().filter(m -> m.getAliases().contains(args[0])).findFirst().orElse(null); if (commandMethod == null) return new ArrayList<>(); Method autofiller = commandMethod.getAutofiller(); if (autofiller != null) { try { - return (List) autofiller.invoke(commandMethod.getHandler(), sender, args); + return ((List) autofiller.invoke(commandMethod.getHandler(), sender, args)).stream().filter(c -> c.contains(args[args.length - 1])).collect(Collectors.toList()); } catch (InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); } diff --git a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/commands/BotCommand.java b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/commands/BotCommand.java index 1e362ea..f0cf3c8 100644 --- a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/commands/BotCommand.java +++ b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/commands/BotCommand.java @@ -520,11 +520,17 @@ public class BotCommand extends CommandInstance { @Command( name = "debug", desc = "Debug plugin code.", - visible = false + visible = false, + autofill = "debugAutofill" ) public void debug(CommandSender sender, @Arg("expression") String expression) { new Debugger(sender).execute(expression); } + + @Autofill + public List debugAutofill(CommandSender sender, String[] args) { + return args.length == 2 ? new ArrayList<>(Debugger.AUTOFILL_METHODS) : new ArrayList<>(); + } private double parseDoubleOrRelative(String pos, Location loc, int type) { if (loc == null || pos.length() == 0 || pos.charAt(0) != '~') diff --git a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/commands/BotEnvironmentCommand.java b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/commands/BotEnvironmentCommand.java new file mode 100644 index 0000000..9974852 --- /dev/null +++ b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/command/commands/BotEnvironmentCommand.java @@ -0,0 +1,431 @@ +package net.nuggetmc.tplus.command.commands; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; + +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.nuggetmc.tplus.api.agent.legacyagent.LegacyAgent; +import net.nuggetmc.tplus.api.agent.legacyagent.LegacyMats; +import net.nuggetmc.tplus.api.utils.ChatUtils; +import net.nuggetmc.tplus.command.CommandHandler; +import net.nuggetmc.tplus.command.CommandInstance; +import net.nuggetmc.tplus.command.annotation.Arg; +import net.nuggetmc.tplus.command.annotation.Autofill; +import net.nuggetmc.tplus.command.annotation.Command; +import net.nuggetmc.tplus.command.annotation.OptArg; + +public class BotEnvironmentCommand extends CommandInstance { + + private static final Set LOADED_MODS = new HashSet<>(); + private static boolean loaded; + + public BotEnvironmentCommand(CommandHandler handler, String name, String description, String... aliases) { + super(handler, name, description, aliases); + } + + @Command + public void root(CommandSender sender, List args) { + commandHandler.sendRootInfo(this, sender); + } + + @Command( + name = "help", + desc = "Help for /botenvironment.", + autofill = "autofill" + ) + public void help(CommandSender sender, List args) { + if (args.size() > 0 && args.get(0).equals("blocks")) { + sender.sendMessage(ChatUtils.LINE); + sender.sendMessage("If you are running this plugin on a Magma server, keep in mind that blocks added by mods are not considered solid."); + sender.sendMessage("You must manually add solid blocks added by mods with " + ChatColor.YELLOW + "/botenvironment addSolid " + ChatColor.RESET + "."); + sender.sendMessage("The material name is the mod ID and the block name concatted with a \"_\", converted to uppercase."); + sender.sendMessage("For example, if mod \"examplemod\" adds a block \"custom_block\", the material name is EXAMPLEMOD_CUSTOM_BLOCK."); + sender.sendMessage("Additionally, you may use " + ChatColor.YELLOW + "/botenvironment addSolidGroup " + ChatColor.RESET + ", where modid is the uppercase MODID plus a \"_\""); + sender.sendMessage(ChatUtils.LINE); + } else if (args.size() > 0 && args.get(0).equals("mobs")) { + sender.sendMessage(ChatUtils.LINE); + sender.sendMessage("Sometimes, you may want to have a pre-set list of mob types that the bot will target."); + sender.sendMessage("Additionally, some mobs (especially bosses) may not be considered as hostile."); + sender.sendMessage("To resolve this, use " + ChatColor.YELLOW + "/botenvironment addCustomMob " + ChatColor.RESET + " to add mob types to a list."); + sender.sendMessage(ChatColor.YELLOW + "/botenvironment mobListType" + ChatColor.RESET + " changes if the nearest hostile targeting option should consider this list."); + sender.sendMessage("The nearest mob and custom list targeting options will always include mobs in this list."); + sender.sendMessage(ChatUtils.LINE); + } else { + sender.sendMessage("Do " + ChatColor.YELLOW + "/botenvironment help blocks " + ChatColor.RESET + "for more information on adding solid blocks."); + sender.sendMessage("Do " + ChatColor.YELLOW + "/botenvironment help mobs " + ChatColor.RESET + "for more information on adding custom mobs."); + } + } + + @Command( + name = "getMaterial", + desc = "Prints out the current material at the specified location.", + aliases = {"getmat", "getMat", "getmaterial"} + ) + public void getMaterial(Player sender, @Arg("x") String x, @Arg("y") String y, @Arg("z") String z) { + Location loc = sender.getLocation().clone(); + try { + loc.setX(parseDoubleOrRelative(x, loc, 0)); + loc.setY(parseDoubleOrRelative(y, loc, 1)); + loc.setZ(parseDoubleOrRelative(z, loc, 2)); + } catch (NumberFormatException e) { + sender.sendMessage("A valid location must be provided!"); + return; + } + if (!isLocationLoaded(loc)) { + sender.sendMessage(String.format("The location at " + ChatColor.BLUE + "(%d, %d, %d)" + ChatColor.RESET + " is not loaded.", + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + return; + } + if (Math.abs(loc.getX() - sender.getLocation().getX()) > 250 || Math.abs(loc.getZ() - sender.getLocation().getZ()) > 250) { + sender.sendMessage(String.format("The location at " + ChatColor.BLUE + "(%d, %d, %d)" + ChatColor.RESET + " is too far away.", + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + return; + } + Material mat = loc.getBlock().getType(); + sender.sendMessage(String.format("Material at " + ChatColor.BLUE + "(%d, %d, %d)" + ChatColor.RESET + ": " + ChatColor.GREEN + "%s" + ChatColor.RESET, + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), mat.name())); + } + + @Command( + name = "addSolidGroup", + desc = "Adds every block starting with a prefix to the list of solid materials.", + aliases = {"addsolidgroup"}, + autofill = "autofill" + ) + public void addSolidGroup(CommandSender sender, @Arg("prefix") String prefix, @OptArg("includeNonSolid") boolean includeNonSolid) { + try { + Field byName = Material.class.getDeclaredField("BY_NAME"); + byName.setAccessible(true); + Map map = (Map) byName.get(null); + Map materialsToBlocks = new HashMap<>(); + if (!includeNonSolid) { + // Build material -> block map using ForgeRegistries + Object blocksRegistry = Class.forName("net.minecraftforge.registries.ForgeRegistries").getDeclaredField("BLOCKS").get(null); + Set, Block>> blockSet = (Set, Block>>) Class.forName("net.minecraftforge.registries.IForgeRegistry").getMethod("getEntries").invoke(blocksRegistry); + + for (Entry, Block> entry : blockSet) { + String result = (String) Class.forName("org.magmafoundation.magma.util.ResourceLocationUtil").getMethod("standardize", ResourceLocation.class).invoke(null, entry.getKey().location()); + Material material = Material.getMaterial(result); + if (material != null) + materialsToBlocks.put(material, entry.getValue()); + } + } + int added = 0; + for (Entry entry : map.entrySet()) { + boolean valid = entry.getValue().isBlock() && entry.getKey().startsWith(prefix); + if (valid && !includeNonSolid) + if (!materialsToBlocks.containsKey(entry.getValue())) { + sender.sendMessage("Warning: The material " + ChatColor.GREEN + entry.getValue().name() + ChatColor.RESET + + " was not found in the Forge registries, this should not happen!"); + } else { + // Check if block is solid + Block block = materialsToBlocks.get(entry.getValue()); + valid = false; //TODO: BROKEN + } + if (valid && LegacyMats.SOLID_MATERIALS.add(entry.getValue())) + added++; + } + sender.sendMessage("Successfully added " + ChatColor.BLUE + added + ChatColor.RESET + " materials with prefix " + ChatColor.GREEN + prefix + ChatColor.RESET); + } catch(ReflectiveOperationException e) { + sender.sendMessage("This command only works on Magma servers!"); + } + } + + @Command( + name = "addSolid", + desc = "Adds a material to the list of solid materials.", + aliases = {"addsolid"}, + autofill = "autofill" + ) + public void addSolid(CommandSender sender, List args) { + Material mat; + if (args.size() == 1) + mat = Material.getMaterial(args.get(0)); + else if (args.size() == 3) { + if (!(sender instanceof Player)) { + sender.sendMessage("You must be a player to specify coordinates!"); + return; + } + Location loc = ((Player)sender).getLocation().clone(); + try { + loc.setX(parseDoubleOrRelative(args.get(0), loc, 0)); + loc.setY(parseDoubleOrRelative(args.get(1), loc, 1)); + loc.setZ(parseDoubleOrRelative(args.get(2), loc, 2)); + } catch (NumberFormatException e) { + sender.sendMessage("A valid location must be provided! " + ChatColor.YELLOW + "/bot addSolid " + ChatColor.RESET); + return; + } + if (!isLocationLoaded(loc)) { + sender.sendMessage(String.format("The location at " + ChatColor.BLUE + "(%d, %d, %d)" + ChatColor.RESET + " is not loaded.", + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + return; + } + if (Math.abs(loc.getX() - ((Player)sender).getLocation().getX()) > 250 || Math.abs(loc.getZ() - ((Player)sender).getLocation().getZ()) > 250) { + sender.sendMessage(String.format("The location at " + ChatColor.BLUE + "(%d, %d, %d)" + ChatColor.RESET + " is too far away.", + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + return; + } + mat = loc.getBlock().getType(); + } else { + sender.sendMessage("Invalid syntax!"); + sender.sendMessage("To specify a material: " + ChatColor.YELLOW + "/bot addSolid " + ChatColor.RESET); + sender.sendMessage("To specify a location containing a material: " + ChatColor.YELLOW + "/bot addSolid " + ChatColor.RESET); + return; + } + if (mat == null) { + sender.sendMessage("The material you specified does not exist!"); + return; + } + if (LegacyMats.SOLID_MATERIALS.add(mat)) + sender.sendMessage("Successfully added " + ChatColor.BLUE + mat.name() + ChatColor.RESET + " to the list."); + else + sender.sendMessage(ChatColor.BLUE + mat.name() + ChatColor.RESET + " already exists in the list!"); + } + + @Command( + name = "removeSolid", + desc = "Removes a material from the list of solid materials.", + aliases = {"removesolid"}, + autofill = "autofill" + ) + public void removeSolid(CommandSender sender, List args) { + Material mat; + if (args.size() == 1) + mat = Material.getMaterial(args.get(0)); + else if (args.size() == 3) { + if (!(sender instanceof Player)) { + sender.sendMessage("You must be a player to specify coordinates!"); + return; + } + Location loc = ((Player)sender).getLocation().clone(); + try { + loc.setX(parseDoubleOrRelative(args.get(0), loc, 0)); + loc.setY(parseDoubleOrRelative(args.get(1), loc, 1)); + loc.setZ(parseDoubleOrRelative(args.get(2), loc, 2)); + } catch (NumberFormatException e) { + sender.sendMessage("A valid location must be provided! " + ChatColor.YELLOW + "/bot removeSolid " + ChatColor.RESET); + return; + } + if (!isLocationLoaded(loc)) { + sender.sendMessage(String.format("The location at " + ChatColor.BLUE + "(%d, %d, %d)" + ChatColor.RESET + " is not loaded.", + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + return; + } + if (Math.abs(loc.getX() - ((Player)sender).getLocation().getX()) > 250 || Math.abs(loc.getZ() - ((Player)sender).getLocation().getZ()) > 250) { + sender.sendMessage(String.format("The location at " + ChatColor.BLUE + "(%d, %d, %d)" + ChatColor.RESET + " is too far away.", + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + return; + } + mat = loc.getBlock().getType(); + } else { + sender.sendMessage("Invalid syntax!"); + sender.sendMessage("To specify a material: " + ChatColor.YELLOW + "/bot removeSolid " + ChatColor.RESET); + sender.sendMessage("To specify a location containing a material: " + ChatColor.YELLOW + "/bot removeSolid " + ChatColor.RESET); + return; + } + if (mat == null) { + sender.sendMessage("The material you specified does not exist!"); + return; + } + if (LegacyMats.SOLID_MATERIALS.remove(mat)) + sender.sendMessage("Successfully removed " + ChatColor.BLUE + mat.name() + ChatColor.RESET + " from the list."); + else + sender.sendMessage(ChatColor.BLUE + mat.name() + ChatColor.RESET + " does not exist in the list!"); + } + + @Command( + name = "listSolids", + desc = "Displays the list of solid materials manually added.", + aliases = {"listsolids"} + ) + public void listSolids(CommandSender sender) { + sender.sendMessage(ChatUtils.LINE); + for (Material mat : LegacyMats.SOLID_MATERIALS) + sender.sendMessage(ChatColor.GREEN + mat.name() + ChatColor.RESET); + sender.sendMessage("Total items: " + ChatColor.BLUE + LegacyMats.SOLID_MATERIALS.size() + ChatColor.RESET); + sender.sendMessage(ChatUtils.LINE); + } + + @Command( + name = "clearSolids", + desc = "Clears the list of solid materials manually added.", + aliases = {"clearsolids"} + ) + public void clearSolids(CommandSender sender) { + int size = LegacyMats.SOLID_MATERIALS.size(); + LegacyMats.SOLID_MATERIALS.clear(); + sender.sendMessage("Removed all " + ChatColor.BLUE + size + ChatColor.RESET + " item(s) from the list."); + } + + @Command( + name = "addCustomMob", + desc = "Adds a mob type to the list of custom mobs.", + aliases = {"addcustommob"}, + autofill = "autofill" + ) + public void addCustomMob(CommandSender sender, @Arg("mobName") String mobName) { + EntityType type = EntityType.fromName(mobName); + if (type == null) { + sender.sendMessage("The entity type you specified does not exist!"); + return; + } + if (LegacyAgent.CUSTOM_TYPES_LIST.add(type)) + sender.sendMessage("Successfully added " + ChatColor.BLUE + type.name() + ChatColor.RESET + " to the list."); + else + sender.sendMessage(ChatColor.BLUE + type.name() + ChatColor.RESET + " already exists in the list!"); + } + + @Command( + name = "removeCustomMob", + desc = "Removes a mob type to the list of custom mobs.", + aliases = {"removecustommob"}, + autofill = "autofill" + ) + public void removeCustomMob(CommandSender sender, @Arg("mobName") String mobName) { + EntityType type = EntityType.fromName(mobName); + if (type == null) { + sender.sendMessage("The entity type you specified does not exist!"); + return; + } + if (LegacyAgent.CUSTOM_TYPES_LIST.remove(type)) + sender.sendMessage("Successfully removed " + ChatColor.BLUE + type.name() + ChatColor.RESET + " from the list."); + else + sender.sendMessage(ChatColor.BLUE + type.name() + ChatColor.RESET + " does not exist in the list!"); + } + + @Command( + name = "listCustomMobs", + desc = "Displays the list of custom mobs manually added.", + aliases = {"listcustommobs"} + ) + public void listCustomMobs(CommandSender sender) { + sender.sendMessage(ChatUtils.LINE); + for (EntityType type : LegacyAgent.CUSTOM_TYPES_LIST) + sender.sendMessage(ChatColor.GREEN + type.name() + ChatColor.RESET); + sender.sendMessage("Total items: " + ChatColor.BLUE + LegacyAgent.CUSTOM_TYPES_LIST.size() + ChatColor.RESET); + sender.sendMessage(ChatUtils.LINE); + } + + @Command( + name = "clearCustomMobs", + desc = "Clears the list of custom mobs manually added.", + aliases = {"clearcustommobs"} + ) + public void clearCustomMobs(CommandSender sender) { + int size = LegacyAgent.CUSTOM_TYPES_LIST.size(); + LegacyAgent.CUSTOM_TYPES_LIST.clear(); + sender.sendMessage("Removed all " + ChatColor.BLUE + size + ChatColor.RESET + " item(s) from the list."); + } + + @Command( + name = "mobListType", + desc = "Changes the custom mob list type to hostile or passive.", + aliases = {"moblisttype"}, + autofill = "autofill" + ) + public void mobListType(CommandSender sender, List args) { + if (args.isEmpty()) { + String type = LegacyAgent.areCustomTypesHostile ? "hostile" : "passive"; + sender.sendMessage("The custom mob list type is " + ChatColor.BLUE + type + ChatColor.RESET + "."); + } else if (args.size() > 0 && args.get(0).equals("hostile")) { + LegacyAgent.areCustomTypesHostile = true; + sender.sendMessage("The custom mob list type has been set to " + ChatColor.BLUE + "hostile" + ChatColor.RESET + "."); + } else if (args.size() > 0 && args.get(0).equals("passive")) { + LegacyAgent.areCustomTypesHostile = false; + sender.sendMessage("The custom mob list type has been set to " + ChatColor.BLUE + "passive" + ChatColor.RESET + "."); + } else + sender.sendMessage("Usage: " + ChatColor.YELLOW + "/botenvironment mobListType (hostile|passive)" + ChatColor.RESET); + } + + @Autofill + public List autofill(CommandSender sender, String[] args) { + List output = new ArrayList<>(); + if (args.length == 2) { + if (args[0].equals("help")) { + output.add("blocks"); + output.add("mobs"); + } else if (matches(args[0], "addSolidGroup")) { + output.addAll(getLoadedMods()); + } else if (matches(args[0], "addSolid") || matches(args[0], "removeSolid")) { + for (Material mat : Material.values()) + if (!mat.isLegacy()) + output.add(mat.name()); + } else if (matches(args[0], "addCustomMob") || matches(args[0], "removeCustomMob")) { + for (EntityType type : EntityType.values()) + if (type != EntityType.UNKNOWN) + output.add(type.name()); + } else if (matches(args[0], "mobListType")) { + output.add("hostile"); + output.add("passive"); + } + } + return output; + } + + private boolean matches(String input, String check) { + return input.equals(check) || input.equals(check.toLowerCase(Locale.ENGLISH)); + } + + private double parseDoubleOrRelative(String pos, Location loc, int type) { + if (loc == null || pos.length() == 0 || pos.charAt(0) != '~') + return Double.parseDouble(pos); + double relative = pos.length() == 1 ? 0 : Double.parseDouble(pos.substring(1)); + switch (type) { + case 0: + return relative + Math.round(loc.getX() * 1000) / 1000D; + case 1: + return relative + Math.round(loc.getY() * 1000) / 1000D; + case 2: + return relative + Math.round(loc.getZ() * 1000) / 1000D; + default: + return 0; + } + } + + private boolean isLocationLoaded(Location loc) { + return loc.getWorld().isChunkLoaded(Location.locToBlock(loc.getX()) >> 4, Location.locToBlock(loc.getZ()) >> 4); + } + + private static Set getLoadedMods() { + if (!loaded) { + try { + Object blocksRegistry = Class.forName("net.minecraftforge.registries.ForgeRegistries").getDeclaredField("BLOCKS").get(null); + Set, Block>> blockSet = (Set, Block>>) Class.forName("net.minecraftforge.registries.IForgeRegistry").getMethod("getEntries").invoke(blocksRegistry); + for (Entry, Block> entry : blockSet) { + String namespace = entry.getKey().location().getNamespace(); + if (!namespace.equals(NamespacedKey.MINECRAFT)) + LOADED_MODS.add(namespace.toUpperCase() + "_"); + } + + Object itemsRegistry = Class.forName("net.minecraftforge.registries.ForgeRegistries").getDeclaredField("ITEMS").get(null); + Set, Item>> itemSet = (Set, Item>>) Class.forName("net.minecraftforge.registries.IForgeRegistry").getMethod("getEntries").invoke(itemsRegistry); + for (Entry, Item> entry : itemSet) { + String namespace = entry.getKey().location().getNamespace(); + if (!namespace.equals(NamespacedKey.MINECRAFT)) + LOADED_MODS.add(namespace.toUpperCase() + "_"); + } + } catch (ReflectiveOperationException e) {} + loaded = true; + } + return LOADED_MODS; + } +} diff --git a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/utils/Debugger.java b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/utils/Debugger.java index 2466e30..046e934 100644 --- a/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/utils/Debugger.java +++ b/TerminatorPlus-Plugin/src/main/java/net/nuggetmc/tplus/utils/Debugger.java @@ -16,6 +16,7 @@ import net.nuggetmc.tplus.command.commands.AICommand; import org.bukkit.*; import org.bukkit.command.CommandSender; import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -23,12 +24,30 @@ import org.bukkit.permissions.ServerOperator; import org.bukkit.util.Vector; import java.beans.Statement; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.*; import java.util.stream.Collectors; public class Debugger { private final CommandSender sender; + public static final Set AUTOFILL_METHODS = new HashSet<>(); + + static { + for (Method method : Debugger.class.getDeclaredMethods()) { + if (!method.getName().equals("print") && !method.getName().equals("execute") && !method.getName().equals("buildObjects") + && !method.getName().startsWith("lambda$")) { + String autofill = method.getName() + "("; + for (Parameter par : method.getParameters()) { + autofill += par.getType().getSimpleName() + ","; + } + autofill = method.getParameters().length > 0 ? autofill.substring(0, autofill.length() - 1) : autofill; + autofill += ")"; + AUTOFILL_METHODS.add(autofill); + } + } + } public Debugger(CommandSender sender) { this.sender = sender; @@ -447,4 +466,20 @@ public class Debugger { print("The Bot Agent is now " + (b ? ChatColor.RED + "DISABLED" : ChatColor.GREEN + "ENABLED") + ChatColor.RESET + "."); } + + public void printSurroundingMobs(double dist) { + if (!(sender instanceof Player)) { + print("You must be a player to call this."); + return; + } + + Player player = (Player) sender; + double distSq = Math.pow(dist, 2); + for (Entity en : player.getWorld().getEntities()) { + Location loc = en.getLocation(); + if (loc.distanceSquared(player.getLocation()) < distSq) + print(String.format("Entity at " + ChatColor.BLUE + "(%d, %d, %d)" + ChatColor.RESET + ": Type " + ChatColor.GREEN + "%s" + ChatColor.RESET, + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), en.getType().toString())); + } + } }