From 66708ac3146f114b95e899a45ff7484b28445cb7 Mon Sep 17 00:00:00 2001 From: fullwall Date: Mon, 5 Feb 2024 00:05:51 +0800 Subject: [PATCH] Add /npc command cycle --- .../citizensnpcs/commands/NPCCommands.java | 18 +++++++--- .../citizensnpcs/npc/CitizensNPCRegistry.java | 4 +-- .../npc/ai/AStarNavigationStrategy.java | 8 ++--- .../npc/ai/CitizensNavigator.java | 14 ++++---- .../ai/StraightLineNavigationStrategy.java | 7 ++-- .../net/citizensnpcs/trait/CommandTrait.java | 14 ++++++-- .../net/citizensnpcs/trait/ShopTrait.java | 36 +++++-------------- .../waypoint/GuidedWaypointProvider.java | 13 +++---- .../java/net/citizensnpcs/util/Messages.java | 2 ++ main/src/main/resources/en.json | 4 ++- 10 files changed, 64 insertions(+), 56 deletions(-) diff --git a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java index dd760e007..13d7b019c 100644 --- a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java +++ b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java @@ -455,7 +455,7 @@ public class NPCCommands { @Command( aliases = { "npc" }, - usage = "command|cmd (add [command] | remove [id|all] | permissions [permissions] | sequential | random | clearerror [type] (name|uuid) | errormsg [type] [msg] | persistsequence [true|false] | cost [cost] (id) | expcost [cost] (id) | itemcost (id)) (-s(hift)) (-l[eft]/-r[ight]) (-p[layer] -o[p]), --cooldown --gcooldown [seconds] --delay [ticks] --permissions [perms] --n [max # of uses]", + usage = "command|cmd (add [command] | remove [id|all] | permissions [permissions] | sequential | cycle | random | clearerror [type] (name|uuid) | errormsg [type] [msg] | persistsequence [true|false] | cost [cost] (id) | expcost [cost] (id) | itemcost (id)) (-s(hift)) (-l[eft]/-r[ight]) (-p[layer] -o[p]), --cooldown --gcooldown [seconds] --delay [ticks] --permissions [perms] --n [max # of uses]", desc = "Controls commands which will be run when clicking on an NPC", help = Messages.NPC_COMMAND_HELP, modifiers = { "command", "cmd" }, @@ -469,7 +469,7 @@ public class NPCCommands { @Flag(value = "delay", defValue = "0") Duration delay, @Arg( value = 1, - completions = { "add", "remove", "permissions", "persistsequence", "sequential", "random", + completions = { "add", "remove", "permissions", "persistsequence", "sequential", "cycle", "random", "hideerrors", "errormsg", "clearerror", "expcost", "itemcost", "cost" }) String action) throws CommandException { CommandTrait commands = npc.getOrAddTrait(CommandTrait.class); @@ -521,6 +521,11 @@ public class NPCCommands { Messaging.sendTr(sender, commands.getExecutionMode() == ExecutionMode.SEQUENTIAL ? Messages.COMMANDS_SEQUENTIAL_SET : Messages.COMMANDS_SEQUENTIAL_UNSET); + } else if (action.equalsIgnoreCase("cycle")) { + commands.setExecutionMode( + commands.getExecutionMode() == ExecutionMode.CYCLE ? ExecutionMode.LINEAR : ExecutionMode.CYCLE); + Messaging.sendTr(sender, commands.getExecutionMode() == ExecutionMode.CYCLE ? Messages.COMMANDS_CYCLE_SET + : Messages.COMMANDS_CYCLE_UNSET); } else if (action.equalsIgnoreCase("persistsequence")) { if (args.argsLength() == 2) { commands.setPersistSequence(!commands.persistSequence()); @@ -2078,11 +2083,12 @@ public class NPCCommands { @Command( aliases = { "npc" }, - usage = "pathto me | here | cursor | [x] [y] [z] (--margin [distance margin])", + usage = "pathto me | here | cursor | [x] [y] [z] (--margin [distance margin]) (-s[traight line])", desc = "Starts pathfinding to a certain location", modifiers = { "pathto" }, min = 2, max = 4, + flags = "s", permission = "citizens.npc.pathto") public void pathto(CommandContext args, CommandSender sender, NPC npc, @Arg(value = 1, completions = { "me", "here", "cursor" }) String option, @Flag("margin") Double margin) @@ -2100,7 +2106,11 @@ public class NPCCommands { loc.setY(args.getDouble(2)); loc.setZ(args.getDouble(3)); } - npc.getNavigator().setTarget(loc); + if (args.hasFlag('s')) { + npc.getNavigator().setStraightLineTarget(loc); + } else { + npc.getNavigator().setTarget(loc); + } if (margin != null) { npc.getNavigator().getLocalParameters().distanceMargin(margin); } diff --git a/main/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java b/main/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java index 726a47d18..44bb5292b 100644 --- a/main/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java +++ b/main/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java @@ -191,9 +191,7 @@ public class CitizensNPCRegistry implements NPCRegistry { public NPC getNPC(Entity entity) { if (entity == null) return null; - if (entity instanceof NPCHolder) - return ((NPCHolder) entity).getNPC(); - return NMS.getNPC(entity); + return entity instanceof NPCHolder ? ((NPCHolder) entity).getNPC() : NMS.getNPC(entity); } @Override diff --git a/main/src/main/java/net/citizensnpcs/npc/ai/AStarNavigationStrategy.java b/main/src/main/java/net/citizensnpcs/npc/ai/AStarNavigationStrategy.java index fa9444789..d33d928ed 100644 --- a/main/src/main/java/net/citizensnpcs/npc/ai/AStarNavigationStrategy.java +++ b/main/src/main/java/net/citizensnpcs/npc/ai/AStarNavigationStrategy.java @@ -98,7 +98,7 @@ public class AStarNavigationStrategy extends AbstractPathStrategy { } Location loc = npc.getEntity().getLocation(); /* Proper door movement - gets stuck on corners at times - + Block block = currLoc.getWorld().getBlockAt(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); if (MinecraftBlockExaminer.isDoor(block.getType())) { Door door = (Door) block.getState().getData(); @@ -112,8 +112,8 @@ public class AStarNavigationStrategy extends AbstractPathStrategy { double dX = dest.getX() - loc.getX(); double dZ = dest.getZ() - loc.getZ(); double dY = dest.getY() - loc.getY(); - double xzDistance = dX * dX + dZ * dZ; - if (Math.abs(dY) < 1 && Math.sqrt(xzDistance) <= params.distanceMargin()) { + double xzDistance = Math.sqrt(dX * dX + dZ * dZ); + if (Math.abs(dY) < 1 && xzDistance <= params.distanceMargin()) { plan.update(npc); if (plan.isComplete()) return true; @@ -128,7 +128,7 @@ public class AStarNavigationStrategy extends AbstractPathStrategy { } else { Vector dir = dest.toVector().subtract(npc.getEntity().getLocation().toVector()).normalize().multiply(0.2); boolean liquidOrInLiquid = MinecraftBlockExaminer.isLiquidOrInLiquid(loc.getBlock()); - if (dY >= 1 && Math.sqrt(xzDistance) <= 0.4 || dY >= 0.2 && liquidOrInLiquid) { + if (dY >= 1 && xzDistance <= 0.4 || dY >= 0.2 && liquidOrInLiquid) { dir.add(new Vector(0, 0.75, 0)); } npc.getEntity().setVelocity(dir); diff --git a/main/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java b/main/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java index 097947b23..6eb764705 100644 --- a/main/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java +++ b/main/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java @@ -334,12 +334,13 @@ public class CitizensNavigator implements Navigator, Runnable { return; } setTarget(params -> { - if (npc.isFlyable()) + if (npc.isFlyable()) { return new FlyingAStarNavigationStrategy(npc, path, params); - else if (params.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity)) + } else if (params.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity)) { return new AStarNavigationStrategy(npc, path, params); - else + } else { return new MCNavigationStrategy(npc, path, params); + } }); } @@ -353,12 +354,13 @@ public class CitizensNavigator implements Navigator, Runnable { } Location target = targetIn.clone(); setTarget(params -> { - if (npc.isFlyable()) + if (npc.isFlyable()) { return new FlyingAStarNavigationStrategy(npc, target, params); - else if (params.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity)) + } else if (params.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity)) { return new AStarNavigationStrategy(npc, target, params); - else + } else { return new MCNavigationStrategy(npc, target, params); + } }); } diff --git a/main/src/main/java/net/citizensnpcs/npc/ai/StraightLineNavigationStrategy.java b/main/src/main/java/net/citizensnpcs/npc/ai/StraightLineNavigationStrategy.java index c40de4d2c..5e434b4bc 100644 --- a/main/src/main/java/net/citizensnpcs/npc/ai/StraightLineNavigationStrategy.java +++ b/main/src/main/java/net/citizensnpcs/npc/ai/StraightLineNavigationStrategy.java @@ -62,9 +62,12 @@ public class StraightLineNavigationStrategy extends AbstractPathStrategy { return true; Location currLoc = npc.getEntity().getLocation(); - if (currLoc.distance(destination) <= params.distanceMargin()) + if (currLoc.distance(destination) <= params.distanceMargin()) { + if (npc.isFlyable()) { + npc.getEntity().setVelocity(new Vector(0, 0, 0)); + } return true; - + } if (target != null) { destination = params.entityTargetLocationMapper().apply(target); } diff --git a/main/src/main/java/net/citizensnpcs/trait/CommandTrait.java b/main/src/main/java/net/citizensnpcs/trait/CommandTrait.java index e4eb7bdec..9b680d7cf 100644 --- a/main/src/main/java/net/citizensnpcs/trait/CommandTrait.java +++ b/main/src/main/java/net/citizensnpcs/trait/CommandTrait.java @@ -77,6 +77,7 @@ public class CommandTrait extends Trait { private boolean hideErrorMessages; @Persist private final List itemRequirements = Lists.newArrayList(); + private int lastUsedId = -1; @Persist private boolean persistSequence = false; @Persist(keyType = UUID.class, reify = true, value = "cooldowns") @@ -278,7 +279,7 @@ public class CommandTrait extends Trait { return; } int max = -1; - if (executionMode == ExecutionMode.SEQUENTIAL) { + if (executionMode == ExecutionMode.SEQUENTIAL || executionMode == ExecutionMode.CYCLE) { Collections.sort(commandList, Comparator.comparing(o1 -> o1.id)); max = commandList.size() > 0 ? commandList.get(commandList.size() - 1).id : -1; } @@ -287,6 +288,13 @@ public class CommandTrait extends Trait { } for (NPCCommand command : commandList) { PlayerNPCCommand info = null; + if (executionMode == ExecutionMode.CYCLE) { + if (command.id <= lastUsedId) { + if (lastUsedId != max) + continue; + lastUsedId = -1; + } + } if (executionMode == ExecutionMode.SEQUENTIAL && (info = playerTracking.get(player.getUniqueId())) != null) { if (info.lastUsedHand != hand) { @@ -300,7 +308,8 @@ public class CommandTrait extends Trait { } } runCommand(player, hand, command); - if (executionMode == ExecutionMode.SEQUENTIAL || (charged != null && !charged)) + if (executionMode == ExecutionMode.SEQUENTIAL || executionMode == ExecutionMode.CYCLE + || (charged != null && !charged)) break; } } @@ -508,6 +517,7 @@ public class CommandTrait extends Trait { } public enum ExecutionMode { + CYCLE, LINEAR, RANDOM, SEQUENTIAL; diff --git a/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java b/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java index 986dfe145..6ab3c990c 100644 --- a/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java +++ b/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java @@ -31,7 +31,6 @@ import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.gui.CitizensInventoryClickEvent; import net.citizensnpcs.api.gui.ClickHandler; import net.citizensnpcs.api.gui.InputMenus; -import net.citizensnpcs.api.gui.InputMenus.Choice; import net.citizensnpcs.api.gui.InventoryMenu; import net.citizensnpcs.api.gui.InventoryMenuPage; import net.citizensnpcs.api.gui.InventoryMenuPattern; @@ -114,8 +113,6 @@ public class ShopTrait extends Trait { @Persist private String title; @Persist - private ShopType type = ShopType.COMMAND; - @Persist private String viewPermission; private NPCShop() { @@ -712,42 +709,31 @@ public class ShopTrait extends Trait { @Override public void initialise(MenuContext ctx) { this.ctx = ctx; - ctx.getSlot(2) + ctx.getSlot(0) .setDescription("Edit permission required to view shop
" + shop.getRequiredPermission()); - ctx.getSlot(6).setDescription("Edit shop title
" + shop.title); + ctx.getSlot(4).setDescription("Edit shop title
" + shop.title); if (trait != null) { - ctx.getSlot(8).setDescription( + ctx.getSlot(6).setDescription( "Show shop on right click
" + shop.getName().equals(trait.rightClickShop)); } } - @MenuSlot(slot = { 0, 4 }, material = Material.FEATHER, amount = 1, title = "Edit shop items") + @MenuSlot(slot = { 0, 2 }, material = Material.FEATHER, amount = 1, title = "Edit shop items") public void onEditItems(InventoryMenuSlot slot, CitizensInventoryClickEvent event) { ctx.getMenu().transition(new NPCShopContentsEditor(shop)); } - @MenuSlot(slot = { 0, 2 }, compatMaterial = { "OAK_SIGN", "SIGN" }, amount = 1) + @MenuSlot(slot = { 0, 0 }, compatMaterial = { "OAK_SIGN", "SIGN" }, amount = 1) public void onPermissionChange(InventoryMenuSlot slot, CitizensInventoryClickEvent event) { ctx.getMenu().transition(InputMenus.stringSetter(shop::getRequiredPermission, shop::setPermission)); } - @MenuSlot(slot = { 0, 6 }, material = Material.NAME_TAG, amount = 1) + @MenuSlot(slot = { 0, 4 }, material = Material.NAME_TAG, amount = 1) public void onSetTitle(InventoryMenuSlot slot, CitizensInventoryClickEvent event) { ctx.getMenu().transition(InputMenus.stringSetter(() -> shop.title, newTitle -> shop.title = newTitle)); } - @MenuSlot(slot = { 0, 0 }, material = Material.BOOK, amount = 1, title = "Edit shop type") - public void onShopTypeChange(InventoryMenuSlot slot, CitizensInventoryClickEvent event) { - ctx.getMenu().transition(InputMenus. picker("Edit shop type", - chosen -> shop.type = chosen.getValue(), - Choice. of(ShopType.BUY, Material.DIAMOND, "Players buy items", - shop.type == ShopType.BUY), - Choice.of(ShopType.SELL, Material.EMERALD, "Players sell items", shop.type == ShopType.SELL), - Choice.of(ShopType.COMMAND, Util.getFallbackMaterial("ENDER_EYE", "ENDER_PEARL"), - "Clicks trigger commands only", shop.type == ShopType.COMMAND))); - } - - @MenuSlot(slot = { 0, 8 }, compatMaterial = { "COMMAND_BLOCK", "COMMAND" }, amount = 1) + @MenuSlot(slot = { 0, 6 }, compatMaterial = { "COMMAND_BLOCK", "COMMAND" }, amount = 1) public void onToggleRightClick(InventoryMenuSlot slot, CitizensInventoryClickEvent event) { event.setCancelled(true); if (trait == null) @@ -758,7 +744,7 @@ public class ShopTrait extends Trait { } else { trait.rightClickShop = shop.name; } - ctx.getSlot(8) + ctx.getSlot(6) .setDescription("Show shop on right click
" + shop.getName().equals(trait.rightClickShop)); } } @@ -830,12 +816,6 @@ public class ShopTrait extends Trait { } } - public enum ShopType { - BUY, - COMMAND, - SELL; - } - static { NPCShopAction.register(ItemAction.class, "items", new ItemActionGUI()); NPCShopAction.register(PermissionAction.class, "permissions", new PermissionActionGUI()); diff --git a/main/src/main/java/net/citizensnpcs/trait/waypoint/GuidedWaypointProvider.java b/main/src/main/java/net/citizensnpcs/trait/waypoint/GuidedWaypointProvider.java index e98221a83..f3b90d581 100644 --- a/main/src/main/java/net/citizensnpcs/trait/waypoint/GuidedWaypointProvider.java +++ b/main/src/main/java/net/citizensnpcs/trait/waypoint/GuidedWaypointProvider.java @@ -271,14 +271,15 @@ public class GuidedWaypointProvider implements EnumerableWaypointProvider { tree.clear(); treePlusDestinations.clear(); for (Waypoint waypoint : guides) { - tree.put(new long[] { waypoint.getLocation().getBlockX(), waypoint.getLocation().getBlockY(), - waypoint.getLocation().getBlockZ() }, waypoint); - treePlusDestinations.put(new long[] { waypoint.getLocation().getBlockX(), - waypoint.getLocation().getBlockY(), waypoint.getLocation().getBlockZ() }, waypoint); + Location location = waypoint.getLocation(); + tree.put(new long[] { location.getBlockX(), location.getBlockY(), location.getBlockZ() }, waypoint); + treePlusDestinations.put(new long[] { location.getBlockX(), location.getBlockY(), location.getBlockZ() }, + waypoint); } for (Waypoint waypoint : destinations) { - treePlusDestinations.put(new long[] { waypoint.getLocation().getBlockX(), - waypoint.getLocation().getBlockY(), waypoint.getLocation().getBlockZ() }, waypoint); + Location location = waypoint.getLocation(); + treePlusDestinations.put(new long[] { location.getBlockX(), location.getBlockY(), location.getBlockZ() }, + waypoint); } if (currentGoal != null) { currentGoal.onProviderChanged(); diff --git a/main/src/main/java/net/citizensnpcs/util/Messages.java b/main/src/main/java/net/citizensnpcs/util/Messages.java index 33f0148b5..1993e18f0 100644 --- a/main/src/main/java/net/citizensnpcs/util/Messages.java +++ b/main/src/main/java/net/citizensnpcs/util/Messages.java @@ -79,6 +79,8 @@ public class Messages { public static final String COMMAND_TRIGGER_PROMPT = "citizens.editors.waypoints.triggers.command.prompt"; public static final String COMMAND_UNKNOWN_COMMAND_ID = "citizens.commands.npc.command.unknown-id"; public static final String COMMANDS_CLEARED = "citizens.commands.npc.command.cleared"; + public static final String COMMANDS_CYCLE_SET = "citizens.commands.npc.command.cycle-set"; + public static final String COMMANDS_CYCLE_UNSET = "citizens.commands.npc.command.cycle-unset"; public static final String COMMANDS_PERSIST_SEQUENCE_SET = "citizens.commands.npc.command.persist-sequence-set"; public static final String COMMANDS_PERSIST_SEQUENCE_UNSET = "citizens.commands.npc.command.persist-sequence-unset"; public static final String COMMANDS_RANDOM_SET = "citizens.commands.npc.commands.random-set"; diff --git a/main/src/main/resources/en.json b/main/src/main/resources/en.json index 38a508072..e5f1b7738 100644 --- a/main/src/main/resources/en.json +++ b/main/src/main/resources/en.json @@ -52,6 +52,8 @@ "citizens.commands.npc.chunkload.unset" : "[[{0}]] will no longer force chunks to be loaded.", "citizens.commands.npc.collidable.set" : "[[{0}]] will now collide with entities.", "citizens.commands.npc.collidable.unset" : "[[{0}]] will no longer collide with entities.", + "citizens.commands.npc.command.cycle-set": "[[{0}]] will now cycle through commands on player click", + "citizens.commands.npc.command.cycle-unset": "[[{0}]] will no longer cycle through commands on player click", "citizens.commands.npc.command.command-added" : "Command [[{0}]] added with id [[{1}]].", "citizens.commands.npc.command.command-removed" : "Command [[{0}]] removed.", "citizens.commands.npc.command.cleared" : "[[{0}]]''s commands cleared.", @@ -60,7 +62,7 @@ "citizens.commands.npc.command.describe-format" : "
- {0} [{1}s] [cost:{2}] [exp:{3}] [-]", "citizens.commands.npc.command.errors-cleared" : "Errors cleared for [[{0}]].", "citizens.commands.npc.command.experience-cost-set" : "Set xp level cost per click to [[{0}]].", - "citizens.commands.npc.command.help" : "
Use the [[-l]] flag to make the command run on left click, [[-r]] on right click (default).
Set the per-player cooldown before the command can be used again using [[--cooldown]] (in [[seconds]]).
Set the server-wide cooldown in seconds using [[--gcooldown]].
[[--delay]] will wait the specified amount in [[ticks]] before executing the command.
[[--permissions]] will set the command to require specific permissions (separate multiple with commas).
[[--n]] will only let the player run the command that number of times.
Use [[-o]] to temporarily execute the command as an op and [[-p]] to run the command as the clicking player instead of the server.
To give the player temporary permissions instead of op, use [[/npc command permissions]].
Set the cost of each click with [[/npc command cost/expcost/itemcost]].
Commands can be executed one by one instead of all at once by using [[/npc command sequential]].", + "citizens.commands.npc.command.help" : "
Use the [[-l]] flag to make the command run on left click, [[-r]] on right click (default).
Set the per-player cooldown before the command can be used again using [[--cooldown]] (in [[seconds]]).
Set the server-wide cooldown in seconds using [[--gcooldown]].
[[--delay]] will wait the specified amount in [[ticks]] before executing the command.
[[--permissions]] will set the command to require specific permissions (separate multiple with commas).
[[--n]] will only let the player run the command that number of times.
Use [[-o]] to temporarily execute the command as an op and [[-p]] to run the command as the clicking player instead of the server.
To give the player temporary permissions instead of op, use [[/npc command permissions]].
Set the cost of each click with [[/npc command cost/expcost/itemcost]].
Commands can be executed one by one instead of all at once by using [[/npc command sequential]] or [[/npc command cycle]].", "citizens.commands.npc.command.hide-error-messages-set" : "Now hiding error messages.", "citizens.commands.npc.command.hide-error-messages-unset" : "No longer hiding error messages.", "citizens.commands.npc.command.individual-cost-set" : "Set cost per click to [[{0}]] for command id [[{1}]].",