From ce33d6e38e03a0fb31460fed25aa0b27ede8f069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:19:19 +0100 Subject: [PATCH 01/94] improve output messages in majority of commands (still wip) 1. This commit also includes paginated `/npc help` command. 2. Some messages have not been updated yet. 3. Some messages are no longer used - marked as `N/A` and will be removed later down the line. --- .../fancynpcs/commands/npc/CollidableCMD.java | 6 +- .../fancynpcs/commands/npc/CopyCMD.java | 4 +- .../fancynpcs/commands/npc/CreateCMD.java | 8 +- .../commands/npc/DisplayNameCMD.java | 2 +- .../fancynpcs/commands/npc/EquipmentCMD.java | 4 +- .../fancynpcs/commands/npc/GlowingCMD.java | 4 +- .../commands/npc/GlowingColorCMD.java | 4 +- .../fancynpcs/commands/npc/MessageCMD.java | 16 +- .../fancynpcs/commands/npc/MirrorSkinCMD.java | 6 +- .../fancynpcs/commands/npc/MoveHereCMD.java | 4 +- .../oliver/fancynpcs/commands/npc/NpcCMD.java | 59 ++++--- .../commands/npc/PlayerCommandCMD.java | 12 +- .../fancynpcs/commands/npc/RemoveCMD.java | 4 +- .../commands/npc/ServerCommandCMD.java | 2 +- .../fancynpcs/commands/npc/ShowInTabCMD.java | 11 +- .../fancynpcs/commands/npc/SkinCMD.java | 4 +- .../commands/npc/TurnToPlayerCMD.java | 4 +- .../fancynpcs/commands/npc/TypeCMD.java | 4 +- src/main/resources/lang.yml | 159 +++++++++--------- 19 files changed, 164 insertions(+), 153 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java index 009619b4..ae675bb4 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java @@ -57,12 +57,12 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.updateForAll(); if (collidable) { - MessageHelper.success(receiver, lang.get("npc-command-collidable-true")); + MessageHelper.success(receiver, lang.get("npc-command-collidable-true", "npc", npc.getData().getName())); } else { - MessageHelper.success(receiver, lang.get("npc-command-collidable-false")); + MessageHelper.success(receiver, lang.get("npc-command-collidable-false", "npc", npc.getData().getName())); } } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled", "npc", npc.getData().getName())); } return true; diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java index 59e85fe1..8a5acb8f 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java @@ -76,9 +76,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(copied); copied.spawnForAll(); - MessageHelper.success(receiver, lang.get("npc-command-copy-success")); + MessageHelper.success(receiver, lang.get("npc-command-copy-success", "npc", npc.getData().getName())); } else { - MessageHelper.error(receiver, lang.get("npc-command-copy-cancelled")); + MessageHelper.error(receiver, lang.get("npc-command-copy-cancelled", "npc", npc.getData().getName())); } return true; diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index 645eef8a..a56dd813 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -34,12 +34,12 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled()) { if (FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name, player.getUniqueId()) != null) { - MessageHelper.error(receiver, lang.get("npc-command-create-name-already-exists")); + MessageHelper.error(receiver, lang.get("npc-command-create-name-already-exists", "npc", name)); return false; } } else { if (FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name) != null) { - MessageHelper.error(receiver, lang.get("npc-command-create-name-already-exists")); + MessageHelper.error(receiver, lang.get("npc-command-create-name-already-exists", "npc", name)); return false; } } @@ -59,9 +59,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(createdNpc); createdNpc.spawnForAll(); - MessageHelper.success(receiver, lang.get("npc-command-create-created")); + MessageHelper.success(receiver, lang.get("npc-command-create-created", "npc", name)); } else { - MessageHelper.error(receiver, lang.get("npc-command-create-cancelled")); + MessageHelper.error(receiver, lang.get("npc-command-create-cancelled", "npc", name)); } return true; diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java index 1c78fd06..1d1df264 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java @@ -52,7 +52,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull if (!npcModifyEvent.isCancelled()) { npc.getData().setDisplayName(displayName.toString()); npc.updateForAll(); - MessageHelper.success(receiver, lang.get("npc-command-displayName-updated")); + MessageHelper.success(receiver, lang.get("npc-command-displayName-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java index 9a68c441..0013853b 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java @@ -53,7 +53,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull NpcEquipmentSlot equipmentSlot = NpcEquipmentSlot.parse(slot); if (equipmentSlot == null) { - MessageHelper.error(receiver, lang.get("npc-command-equipment-invalid-slot")); + MessageHelper.error(receiver, lang.get("npc-command-equipment-invalid-slot", "input", slot)); return false; } @@ -65,7 +65,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull if (!npcModifyEvent.isCancelled()) { npc.getData().addEquipment(equipmentSlot, item); npc.updateForAll(); - MessageHelper.success(receiver, lang.get("npc-command-equipment-updated")); + MessageHelper.success(receiver, lang.get("npc-command-equipment-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java index 366ab2ef..659dee12 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java @@ -58,9 +58,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.updateForAll(); if (glowing) { - MessageHelper.success(receiver, lang.get("npc-command-glowing-true")); + MessageHelper.success(receiver, lang.get("npc-command-glowing-true", "npc", npc.getData().getName())); } else { - MessageHelper.success(receiver, lang.get("npc-command-glowing-false")); + MessageHelper.success(receiver, lang.get("npc-command-glowing-false", "npc", npc.getData().getName())); } } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java index 82d6e321..6010e3f3 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java @@ -44,7 +44,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull NamedTextColor color = NamedTextColor.NAMES.value(args[2]); if (color == null) { - MessageHelper.error(receiver, lang.get("npc-command-glowingColor-invalid")); + MessageHelper.error(receiver, lang.get("npc-command-glowingColor-invalid", "input", args[2])); return false; } @@ -54,7 +54,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull if (!npcModifyEvent.isCancelled()) { npc.getData().setGlowingColor(color); npc.updateForAll(); - MessageHelper.success(receiver, lang.get("npc-command-glowingColor-updated")); + MessageHelper.success(receiver, lang.get("npc-command-glowingColor-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index 0cc95a78..fbd2cee1 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -115,9 +115,9 @@ private boolean sendMessagesRandomly(CommandSender receiver, Npc npc, String[] a npc.getData().setSendMessagesRandomly(sendMessagesRandomly); if (sendMessagesRandomly) { - MessageHelper.success(receiver, lang.get("npc-command-message-sendMessagesRandomly-true")); + MessageHelper.success(receiver, lang.get("npc-command-message-sendMessagesRandomly-true", "npc", npc.getData().getName())); } else { - MessageHelper.success(receiver, lang.get("npc-command-message-sendMessagesRandomly-false")); + MessageHelper.success(receiver, lang.get("npc-command-message-sendMessagesRandomly-false", "npc", npc.getData().getName())); npc.updateForAll(); // move to default pos } } else { @@ -154,7 +154,7 @@ private boolean addMessage(CommandSender receiver, Npc npc, String[] args) { if (!npcModifyEvent.isCancelled()) { npc.getData().addMessage(message); - MessageHelper.success(receiver, lang.get("npc-command-message-updated")); + MessageHelper.success(receiver, lang.get("npc-command-message-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } @@ -177,7 +177,7 @@ private boolean setMessage(CommandSender receiver, Npc npc, String[] args) { } if (index < 1 || index > npc.getData().getMessages().size()) { - MessageHelper.error(receiver, lang.get("npc-command-message-invalid-index")); + MessageHelper.error(receiver, lang.get("npc-command-message-invalid-index", "input", String.valueOf(index))); return false; } @@ -202,7 +202,7 @@ private boolean setMessage(CommandSender receiver, Npc npc, String[] args) { if (!npcModifyEvent.isCancelled()) { npc.getData().getMessages().set(index - 1, message); - MessageHelper.success(receiver, lang.get("npc-command-message-updated")); + MessageHelper.success(receiver, lang.get("npc-command-message-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } @@ -225,7 +225,7 @@ private boolean removeMessage(CommandSender receiver, Npc npc, String[] args) { } if (index < 1 || index > npc.getData().getMessages().size()) { - MessageHelper.error(receiver, lang.get("npc-command-message-invalid-index")); + MessageHelper.error(receiver, lang.get("npc-command-message-invalid-index", "input", String.valueOf(index))); return false; } @@ -234,7 +234,7 @@ private boolean removeMessage(CommandSender receiver, Npc npc, String[] args) { if (!npcModifyEvent.isCancelled()) { npc.getData().removeMessage(index - 1); - MessageHelper.success(receiver, lang.get("npc-command-message-updated")); + MessageHelper.success(receiver, lang.get("npc-command-message-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } @@ -253,7 +253,7 @@ private boolean clearMessages(CommandSender receiver, Npc npc, String[] args) { if (!npcModifyEvent.isCancelled()) { npc.getData().getMessages().clear(); - MessageHelper.success(receiver, lang.get("npc-command-message-updated")); + MessageHelper.success(receiver, lang.get("npc-command-message-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java index d1acd79f..d6918f65 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java @@ -60,12 +60,12 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.spawnForAll(); if (mirrorSkin) { - MessageHelper.success(receiver, lang.get("npc-command-mirrorSkin-true")); + MessageHelper.success(receiver, lang.get("npc-command-mirrorSkin-true", "npc", npc.getData().getName())); } else { - MessageHelper.success(receiver, lang.get("npc-command-mirrorSkin-false")); + MessageHelper.success(receiver, lang.get("npc-command-mirrorSkin-false", "npc", npc.getData().getName())); } } else { - MessageHelper.error(receiver, lang.get("npc-command-mirrorSkin-cancelled")); + MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } return true; diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java index cc772e94..b0058fbb 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java @@ -52,9 +52,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.spawnForAll(); } - MessageHelper.success(receiver, lang.get("npc-command-moveHere-moved")); + MessageHelper.success(receiver, lang.get("npc-command-moveHere-moved", "npc", npc.getData().getName())); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled", "npc", npc.getData().getName())); } return true; diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java index 03144b67..eef62b6c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java @@ -106,30 +106,41 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No MessageHelper.error(sender, lang.get("no-permission-subcommand")); return false; } - - MessageHelper.info(sender, lang.get("npc-command-help-header")); - MessageHelper.info(sender, lang.get("npc-command-help-create")); - MessageHelper.info(sender, lang.get("npc-command-help-remove")); - MessageHelper.info(sender, lang.get("npc-command-help-copy")); - MessageHelper.info(sender, lang.get("npc-command-help-list")); - MessageHelper.info(sender, lang.get("npc-command-help-skin")); - MessageHelper.info(sender, lang.get("npc-command-help-type")); - MessageHelper.info(sender, lang.get("npc-command-help-moveHere")); - MessageHelper.info(sender, lang.get("npc-command-help-teleport")); - MessageHelper.info(sender, lang.get("npc-command-help-displayName")); - MessageHelper.info(sender, lang.get("npc-command-help-equipment")); - MessageHelper.info(sender, lang.get("npc-command-help-message")); - MessageHelper.info(sender, lang.get("npc-command-help-playerCommand")); - MessageHelper.info(sender, lang.get("npc-command-help-serverCommand")); - MessageHelper.info(sender, lang.get("npc-command-help-showInTab")); - MessageHelper.info(sender, lang.get("npc-command-help-glowing")); - MessageHelper.info(sender, lang.get("npc-command-help-glowingColor")); - MessageHelper.info(sender, lang.get("npc-command-help-collidable")); - MessageHelper.info(sender, lang.get("npc-command-help-turnToPlayer")); - MessageHelper.info(sender, lang.get("npc-command-help-attribute")); - MessageHelper.info(sender, lang.get("npc-command-help-interactionCooldown")); - MessageHelper.info(sender, lang.get("npc-command-help-mirrorSkin")); - + // TO-DO: Replace with automatic pagination once better configuration system is in place. + final String maxPages = "3"; + if (args.length == 1 || args[1].equals("1")) { + MessageHelper.info(sender, lang.get("npc-command-help-header").replace("{page}", "1").replace("{max_pages}", maxPages)); + MessageHelper.info(sender, lang.get("npc-command-help-create")); + MessageHelper.info(sender, lang.get("npc-command-help-remove")); + MessageHelper.info(sender, lang.get("npc-command-help-copy")); + MessageHelper.info(sender, lang.get("npc-command-help-list")); + MessageHelper.info(sender, lang.get("npc-command-help-skin")); + MessageHelper.info(sender, lang.get("npc-command-help-type")); + MessageHelper.info(sender, lang.get("npc-command-help-moveHere")); + MessageHelper.info(sender, lang.get("npc-command-help-teleport")); + MessageHelper.info(sender, lang.get("npc-command-help-footer").replace("{page}", "1").replace("{max_pages}", maxPages)); + } + else if (args[1].equals("2")) { + MessageHelper.info(sender, lang.get("npc-command-help-header").replace("{page}", "2").replace("{max_pages}", maxPages)); + MessageHelper.info(sender, lang.get("npc-command-help-displayName")); + MessageHelper.info(sender, lang.get("npc-command-help-equipment")); + MessageHelper.info(sender, lang.get("npc-command-help-message")); + MessageHelper.info(sender, lang.get("npc-command-help-playerCommand")); + MessageHelper.info(sender, lang.get("npc-command-help-serverCommand")); + MessageHelper.info(sender, lang.get("npc-command-help-showInTab")); + MessageHelper.info(sender, lang.get("npc-command-help-glowing")); + MessageHelper.info(sender, lang.get("npc-command-help-glowingColor")); + MessageHelper.info(sender, lang.get("npc-command-help-footer").replace("{page}", "2").replace("{max_pages}", maxPages)); + } + else if (args[1].equals("3")) { + MessageHelper.info(sender, lang.get("npc-command-help-header").replace("{page}", "3").replace("{max_pages}", maxPages)); + MessageHelper.info(sender, lang.get("npc-command-help-collidable")); + MessageHelper.info(sender, lang.get("npc-command-help-turnToPlayer")); + MessageHelper.info(sender, lang.get("npc-command-help-attribute")); + MessageHelper.info(sender, lang.get("npc-command-help-interactionCooldown")); + MessageHelper.info(sender, lang.get("npc-command-help-mirrorSkin")); + MessageHelper.info(sender, lang.get("npc-command-help-footer").replace("{page}", "3").replace("{max_pages}", maxPages)); + } return true; } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java index b3d98098..a51c86bd 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java @@ -109,7 +109,7 @@ private boolean addCommand(CommandSender receiver, Npc npc, String[] args) { if (!npcModifyEvent.isCancelled()) { npc.getData().addPlayerCommand(command); - MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated")); + MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } @@ -132,7 +132,7 @@ private boolean setCommand(CommandSender receiver, Npc npc, String[] args) { } if (index < 1 || index > npc.getData().getPlayerCommands().size()) { - MessageHelper.error(receiver, lang.get("npc-command-playercommand-invalid-index")); + MessageHelper.error(receiver, lang.get("npc-command-playercommand-invalid-index", "input", String.valueOf(index))); return false; } @@ -157,7 +157,7 @@ private boolean setCommand(CommandSender receiver, Npc npc, String[] args) { if (!npcModifyEvent.isCancelled()) { npc.getData().getPlayerCommands().set(index - 1, command); - MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated")); + MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } @@ -180,7 +180,7 @@ private boolean removeCommand(CommandSender receiver, Npc npc, String[] args) { } if (index < 1 || index > npc.getData().getPlayerCommands().size()) { - MessageHelper.error(receiver, lang.get("npc-command-playercommand-invalid-index")); + MessageHelper.error(receiver, lang.get("npc-command-playercommand-invalid-index", "input", String.valueOf(index))); return false; } @@ -189,7 +189,7 @@ private boolean removeCommand(CommandSender receiver, Npc npc, String[] args) { if (!npcModifyEvent.isCancelled()) { npc.getData().removePlayerCommand(index - 1); - MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated")); + MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } @@ -208,7 +208,7 @@ private boolean clearCommand(CommandSender receiver, Npc npc, String[] args) { if (!npcModifyEvent.isCancelled()) { npc.getData().getPlayerCommands().clear(); - MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated")); + MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java index a0886396..c098cfb6 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java @@ -45,9 +45,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull } } FancyNpcs.getInstance().getNpcManagerImpl().removeNpc(npc); - MessageHelper.success(receiver, lang.get("npc-command-remove-removed")); + MessageHelper.success(receiver, lang.get("npc-command-remove-removed", "npc", npc.getData().getName())); } else { - MessageHelper.error(receiver, lang.get("npc-command-remove-cancelled")); + MessageHelper.error(receiver, lang.get("npc-command-remove-cancelled", "npc", npc.getData().getName())); } return false; diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java index 0ef13755..5bccb9b1 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java @@ -64,7 +64,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull if (!npcModifyEvent.isCancelled()) { npc.getData().setServerCommand(cmd); - MessageHelper.success(receiver, lang.get("npc-command-serverCommand-updated")); + MessageHelper.success(receiver, lang.get("npc-command-serverCommand-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java index 42fa9da3..80404478 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java @@ -53,7 +53,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull case "true" -> showInTab = true; case "false" -> showInTab = false; default -> { - MessageHelper.error(receiver, lang.get("npc-command-showInTab-invalid-argument")); + MessageHelper.error(receiver, lang.get("npc-command-showInTab-invalid-argument", "input", args[2].toLowerCase())); return false; } } @@ -61,11 +61,6 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SHOW_IN_TAB, showInTab, receiver); npcModifyEvent.callEvent(); - if (showInTab == npc.getData().isShowInTab()) { - MessageHelper.warning(receiver, lang.get("npc-command-showInTab-same")); - return false; - } - if (!npcModifyEvent.isCancelled()) { npc.getData().setShowInTab(showInTab); @@ -77,9 +72,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull } if (showInTab) { - MessageHelper.success(receiver, lang.get("npc-command-showInTab-true")); + MessageHelper.success(receiver, lang.get("npc-command-showInTab-true", "npc", npc.getData().getName())); } else { - MessageHelper.success(receiver, lang.get("npc-command-showInTab-false")); + MessageHelper.success(receiver, lang.get("npc-command-showInTab-false", "npc", npc.getData().getName())); } } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java index d66370ab..206338a7 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java @@ -49,7 +49,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull if (SkinFetcher.SkinType.getType(skinName) == SkinFetcher.SkinType.UUID) { UUID uuid = UUIDFetcher.getUUID(skinName); if (uuid == null) { - MessageHelper.error(receiver, lang.get("npc-command-skin-invalid")); + MessageHelper.error(receiver, lang.get("npc-command-skin-invalid", "input", args[2])); return false; } skinName = uuid.toString(); @@ -72,7 +72,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.removeForAll(); npc.create(); npc.spawnForAll(); - MessageHelper.success(receiver, lang.get("npc-command-skin-updated")); + MessageHelper.success(receiver, lang.get("npc-command-skin-updated", "npc", npc.getData().getName())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java index add66e57..d5531be9 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java @@ -57,9 +57,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.getData().setTurnToPlayer(turnToPlayer); if (turnToPlayer) { - MessageHelper.success(receiver, lang.get("npc-command-turnToPlayer-true")); + MessageHelper.success(receiver, lang.get("npc-command-turnToPlayer-true", "npc", npc.getData().getName())); } else { - MessageHelper.success(receiver, lang.get("npc-command-turnToPlayer-false")); + MessageHelper.success(receiver, lang.get("npc-command-turnToPlayer-false", "npc", npc.getData().getName())); npc.updateForAll(); // move to default pos } } else { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java index 39a34d89..2dca3a4f 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java @@ -46,7 +46,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull EntityType type = EntityType.fromName(args[2].toLowerCase()); if (type == null) { - MessageHelper.error(receiver, lang.get("npc-command-type-invalid")); + MessageHelper.error(receiver, lang.get("npc-command-type-invalid", "input", args[2].toLowerCase())); return false; } @@ -67,7 +67,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.removeForAll(); npc.create(); npc.spawnForAll(); - MessageHelper.success(receiver, lang.get("npc-command-type-updated")); + MessageHelper.success(receiver, lang.get("npc-command-type-updated", "npc", npc.getData().getName(), "type", type.name().toLowerCase())); } else { MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml index a92ec4c1..83e2f3b0 100644 --- a/src/main/resources/lang.yml +++ b/src/main/resources/lang.yml @@ -8,84 +8,89 @@ messages: wrong-usage: 'Wrong usage: /npc help' could-not-parse-number: Could not parse number world-not-found: Could not find world - npc-not-found: Could not find NPC - npc-must-be-player: Npc's type must be Player to do this - on-interaction-cooldown: You need to wait {time} seconds until you can interact with this npc again - npc-command-help-header: 'FancyNpcs Plugin help:' - npc-command-help-create: ' - /npc create (name) - Creates a new npc at your location' - npc-command-help-remove: ' - /npc remove (name) - Removes an npc' - npc-command-help-copy: ' - /npc copy (name) (new name) - Copies an npc' - npc-command-help-list: ' - /npc list - Summary of all npcs' - npc-command-help-skin: ' - /npc skin (name) [(skin)] - Sets the skin for an npc' - npc-command-help-type: ' - /npc type (name) (type) - Sets the entity type for an npc' - npc-command-help-moveHere: ' - /npc movehere (name) - Teleports an npc to your location' - npc-command-help-teleport: ' - /npc teleport (name) (x) (y) (z) [world] - Teleports the npc to the provided location' - npc-command-help-displayName: ' - /npc displayName (name) (displayName ...) - Sets the displayname for an npc' - npc-command-help-equipment: ' - /npc equipment (name) (slot) - Equips the npc with the item you are holding' - npc-command-help-message: ' - /npc message (name) (none|message) - Set NPC message' - npc-command-help-playerCommand: ' - /npc playerCommand (name) (none|command ...) - Executes the command on a player when interacting' - npc-command-help-serverCommand: ' - /npc serverCommand (name) (none|command ...) - The command will be executed by the console when someone interacts with the npc' - npc-command-help-showInTab: ' - /npc showInTab (name) (true|false) - Whether the NPC will be shown in tab-list or not' - npc-command-help-glowing: ' - /npc glowing (name) (true|false) - Whether the NPC will glow or not' - npc-command-help-glowingColor: ' - /npc glowingColor (name) (color) - The color of the glowing effect' - npc-command-help-collidable: ' - /npc collidable (name) (true|false) - Whether the NPC will be collidable or not' - npc-command-help-turnToPlayer: ' - /npc turnToPlayer (name) (true|false) - Whether the NPC will turn to you or not' - npc-command-help-attribute: ' - /npc attribute (name) (attribute) (value) - Set certain npc attributes' - npc-command-help-interactionCooldown: ' - /npc interactionCooldown (name) (seconds) - Set the interaction cooldown (0 = disabled)' - npc_command-help-mirrorSkin: ' - /npc mirrorSkin (name) (true|false) - Whether the NPC will mirror the skin of the viewing player' - npc-command-list-header: All NPCs: - npc-command-list-no-npcs: There are no NPCs. Use '/npc create' to create one + npc-not-found: This feature is only available for player-type NPCs. + npc-must-be-player: This feature is only available for player-type NPCs. + on-interaction-cooldown: You need to wait {time} seconds uasdsssssssssssssssssssssssssssssssssssssssssssssssssss + npc-command-help-header: 'Commands for FancyNpcs plugin: ({page}/{max_pages})' + npc-command-help-footer: Full command reference available here. + npc-command-help-create: /npc create (npc) - Creates a new NPC at your location. + npc-command-help-remove: /npc remove (npc) - Removes specified NPC. + npc-command-help-copy: /npc copy (npc) (new_name) - Copies/clones specified NPC. + npc-command-help-list: /npc list - Lists all loaded NPCs. + npc-command-help-skin: /npc skin (skin) - Changes skin of an NPC. + npc-command-help-type: /npc type (npc) (type) - Changes entity type of an NPC. + npc-command-help-moveHere: /npc movehere (npc) - Teleports NPC to your location. + npc-command-help-teleport: /npc teleport (npc) (x) (y) (z) [world] - Teleports NPC. + npc-command-help-displayName: /npc displayname (npc) (name) - Changes NPC's displayname. + npc-command-help-equipment: /npc equipment (npc) (slot) - Changes equipement of an NPC. + npc-command-help-message: /npc message (npc) (...) - Changes click message(s). + npc-command-help-playerCommand: /npc playerCommand (npc) (...) - Changes click command(s). + npc-command-help-serverCommand: /npc serverCommand (npc) (...) - Changes click command(s). + npc-command-help-showInTab: /npc showInTab (npc) (state) - Changes tab-list visibility. + npc-command-help-glowing: /npc glowing (npc) (state) - Changes glowing effect state. + npc-command-help-glowingColor: /npc glowingColor (npc) (color) - Changes glowing color. + npc-command-help-collidable: /npc collidable (npc) (state) - Changes collidable state. + npc-command-help-turnToPlayer: /npc turnToPlayer (npc) (state) - Changes turning state. + npc-command-help-attribute: /npc attribute (npc) (attr) (value) - Sets entity attribute. + npc-command-help-interactionCooldown: /npc interactionCooldown (npc) (sec) - Sets inter. cooldown. + npc-command-help-mirrorSkin: /npc mirrorSkin (npc) (state) - Changes skin mirroring state. + npc-command-list-header: All NPCs: # todo + npc-command-list-no-npcs: No NPCs found, use /npc create (npc) to create one. npc-command-list-tp-hover: Click to teleport'> - {name} ({x}/{y}/{z}) - npc-command-create-name-already-exists: An npc with that name already exists - npc-command-create-created: Created new NPC - npc-command-create-cancelled: Creation has been cancelled - npc-command-collidable-true: NPC will now be collidable - npc-command-collidable-false: NPC will no longer be collidable - npc-command-copy-success: Copied NPC - npc-command-copy-cancelled: Copying has been cancelled - npc-command-remove-removed: Removed NPC - npc-command-remove-cancelled: Removing has been cancelled - npc-command-moveHere-moved: Moved NPC to your location - npc-command-message-updated: Updated message - npc-command-message-removed: Removed message - npc-command-message-invalid: Invalid message - npc-command-message-invalid-index: Invalid index - npc-command-message-cancelled: Updating message has been cancelled - npc-command-message-sendMessagesRandomly-true: NPC will now send messages randomly - npc-command-message-sendMessagesRandomly-false: NPC will no longer send messages randomly - npc-command-skin-invalid: Invalid username or url - npc-command-skin-failed_header: 'Could not load skin. Possible causes:' - npc-command-skin-failed_url: ' - Invalid URL (check the url)' - npc-command-skin-failed_limited: ' - Rate limit reached (try again later)' - npc-command-skin-updated: Updated skin - npc-command-displayName-updated: Updated display name - npc-command-equipment-invalid-slot: Invalid equipment slot - npc-command-equipment-updated: Updated equipment - npc-command-serverCommand-updated: Updated server command to be executed - npc-command-playercommand-updated: Updated playerCommand - npc-command-playercommand-removed: Removed playerCommand - npc-command-playercommand-invalid: Invalid playerCommand - npc-command-playercommand-invalid-index: Invalid index - npc-command-playercommand-cancelled: Updating playerCommands has been cancelled - npc-command-showInTab-invalid-argument: 'Invalid argument (expected: ''true'' or ''false'')' - npc-command-showInTab-same: Nothing has changed - npc-command-showInTab-true: NPC will now be shown in tab - npc-command-showInTab-false: NPC will no longer be shown in tab - npc-command-glowing-true: NPC will now glow - npc-command-glowing-false: NPC will no longer glow - npc-command-glowingColor-invalid: Invalid color - npc-command-glowingColor-updated: Updated glowing color - npc-command-turnToPlayer-true: NPC will now turn to the players - npc-command-turnToPlayer-false: NPC will no longer turn to the players - npc-command-type-invalid: Invalid type - npc-command-type-updated: Updated entity type + npc-command-create-name-already-exists: NPC named {npc} already exists. + npc-command-create-created: NPC named {npc} has been created. + npc-command-create-cancelled: Creation of NPC named {npc} has been cancelled by the API. + npc-command-collidable-true: NPC named {npc} is now collidable. + npc-command-collidable-false: NPC named {npc} is no longer collidable. + npc-command-copy-success: NPC named {npc} has been copied to {new_npc}. + npc-command-copy-cancelled: Copying of NPC named {npc} has been cancelled by the API. + npc-command-remove-removed: NPC named {npc} has been removed. + npc-command-remove-cancelled: Removal of NPC named {npc} has been cancelled by the API. + npc-command-moveHere-moved: NPC named {npc} has been moved to your location. + npc-command-message-updated: NPC named {npc} has had their message(s) updated. + npc-command-message-removed: NPC named {npc} has had their message(s) removed. + npc-command-message-invalid: N/A + npc-command-message-invalid-index: Specified value {input} is not a valid index. + npc-command-message-cancelled: N/A + npc-command-message-sendMessagesRandomly-true: NPC named {npc} is now sending messages randomly. + npc-command-message-sendMessagesRandomly-false: NPC named {npc} is no longer sending messages randomly. + npc-command-skin-invalid: Specified value {input} is not a valid player name or URL. + npc-command-skin-failed_header: 'Could not load skin. Possible causes:' # todo + npc-command-skin-failed_url: ' - Invalid URL (check the url)' # todo + npc-command-skin-failed_limited: ' - Rate limit reached (try again later)' # todo + npc-command-skin-updated: NPC named {npc} has had their skin updated. + npc-command-displayName-updated: NPC named {npc} has had their display-name updated. + npc-command-equipment-invalid-slot: Specified value {input} is not a valid equipment slot. + npc-command-equipment-updated: NPC named {npc} has had their equipment updated. + npc-command-serverCommand-updated: NPC named {npc} has had their command(s) updated. + npc-command-playercommand-updated: NPC named {npc} has had their command(s) updated. + npc-command-playercommand-removed: NPC named {npc} has had their command(s) removed. + npc-command-playercommand-invalid: N/A + npc-command-playercommand-invalid-index: Specified value {input} is not a valid index. + npc-command-playercommand-cancelled: N/A + + + npc-command-showInTab-invalid-argument: Specified value {input} is not a valid boolean. + npc-command-showInTab-same: N/A + npc-command-showInTab-true: NPC named {npc} is now shown in player-list. + npc-command-showInTab-false: NPC named {npc} is no longer shown in player-list. + npc-command-glowing-true: NPC named {npc} is now glowing. + npc-command-glowing-false: NPC named {npc} is no longer glowing. + npc-command-glowingColor-invalid: Specified value {input} is not a valid color. + npc-command-glowingColor-updated: NPC named {npc} has had their glowing color updated. + npc-command-turnToPlayer-true: NPC named {npc} is now turning to player. + npc-command-turnToPlayer-false: NPC named {npc} is no longer turning to player. + npc-command-type-invalid: Specified value {input} is not a valid entity type. + npc-command-type-updated: NPC named {npc} has had their type set to {type}. npc-command-attribute-attribute-not-found: Could not find attribute npc-command-attribute-wrong-entity-type: This attribute can not be applied to this entity type npc-command-attribute-invalid-value: Invalid attribute value - npc-command-attribute-success: Successfully set the attribute - npc-command-interactioncooldown-updated: Successfully updated the interaction cooldown - npc-command-teleport-success: Successfully teleported npc - npc-command-mirrorSkin-true: NPC will now mirror the skin of the viewer - npc-command-mirrorSkin-false: NPC will no longer mirror the skin of the viewer - npc-command-mirrorSkin-cancelled: Modification has been cancelled - npc-command-fix-success: Successfully tried to fixed the npc + npc-command-attribute-success: Attribute {attribute} set to {value} + + npc-command-interactioncooldown-updated: NPC named {npc} has had their interaction cooldown updated. + + npc-command-teleport-success: You have been teleported to NPC {npc}. + npc-command-mirrorSkin-true: NPC named {npc} is now mirroring player skin. + npc-command-mirrorSkin-false: NPC named {npc} is no longer mirroring player skin. + npc-command-mirrorSkin-cancelled: N/A + npc-command-fix-success: Trying to fix NPC named {npc}... \ No newline at end of file From 30f15763e00885965a8169ea5a73da0efaf98eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 30 Mar 2024 22:54:32 +0100 Subject: [PATCH 02/94] command: /fancynpcs (untested) --- .../fancynpcs/commands/FancyNpcsCMD.java | 59 ++++++++++--------- src/main/resources/languages/en.yml | 30 +++++++--- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java index 817172ce..af656d2e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java @@ -1,19 +1,19 @@ package de.oliver.fancynpcs.commands; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; + public class FancyNpcsCMD extends Command { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); public FancyNpcsCMD() { super("fancynpcs"); @@ -34,34 +34,37 @@ public FancyNpcsCMD() { @Override public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { - if (!testPermission(sender)) { + if (!testPermission(sender)) return false; - } - - FancyNpcs plugin = FancyNpcs.getInstance(); - - if (args.length >= 1 && args[0].equalsIgnoreCase("version")) { - FancyNpcs.getInstance().getVersionConfig().checkVersionAndDisplay(sender, false); - } else if (args.length >= 1 && args[0].equalsIgnoreCase("reload")) { - plugin.getLanguageConfig().load(); - plugin.getFancyNpcConfig().reload(); - plugin.getNpcManagerImpl().reloadNpcs(); - MessageHelper.success(sender, lang.get("reloaded-config")); + final FancyNpcs plugin = FancyNpcs.getInstance(); - } else if (args.length >= 1 && args[0].equalsIgnoreCase("save")) { - plugin.getNpcManagerImpl().saveNpcs(true); - MessageHelper.success(sender, lang.get("saved-npcs")); - - } else if (args.length >= 1 && args[0].equalsIgnoreCase("featureFlags")) { - MessageHelper.info(sender, "Feature flags:"); - MessageHelper.info(sender, " - player-npcs: " + FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled()); - - } else { - MessageHelper.info(sender, lang.get("fancynpcs-syntax")); - return false; + if (args.length >= 1) { + switch (args[0].toLowerCase()) { + case "version" -> FancyNpcs.getInstance().getVersionConfig().checkVersionAndDisplay(sender, false); + case "reload" -> { + translator.loadLanguages(plugin.getDataFolder().getAbsolutePath()); + plugin.getFancyNpcConfig().reload(); + plugin.getNpcManagerImpl().reloadNpcs(); + translator.translate("fancynpcs_reload_success").send(sender); + } + case "save" -> { + plugin.getNpcManagerImpl().saveNpcs(true); + translator.translate("fancynpcs_save_success").send(sender); + } + case "featureflags" -> { + translator.translate("Feature Flags:").send(sender); + translator.translate("› Player NPCs: " + getFormattedBoolean(FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled())).send(sender); + } + } + return true; } + translator.translate("fancynpcs_syntax:").send(sender); + return false; + } - return true; + private static @NotNull String getFormattedBoolean(final boolean bool) { + return (bool) ? "ON" : "OFF"; } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index d97e290e..4fa123fb 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -1,10 +1,24 @@ language_name: english + +# Messages support MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html messages: - test1: "This is a test message" - test2: "This is another test message" - lol: - test3: "This is a test message with a key" - test4: "This is another test message with a key" - third: - test5: "This is a test message with a key and a subkey" - test6: "This is another test message with a key and a subkey" \ No newline at end of file + # Common + interaction_on_cooldown: "" + # Commands (Common Replies) + command_missing_permissions: "" + command_wrong_usage: "" + command_player_only: "" + command_invalid_world: "" + command_invalid_npc: "" + command_unsupported_npc_type: "This NPC type does not support this feature." + # Commands + fancynpcs_syntax: "/fancynpcs (version|reload|save)" + fancynpcs_reload_success: "Plugin has been reloaded." + fancynpcs_save_success: "NPCs has been saved." + fancynpcs_version: "" # NOT CONFIGURABLE + fancynpcs_feature_flags_header: "" # NOT CONFIGURABLE + fancynpcs_feature_flags_entry: "" # NOT CONFIGURABLE + npc_attribute_set: "Attribute {attribute} has been set to {value}." + npc_attribute_invalid_attribute: "Specified value {input} is not a valid attribute." + npc_attribute_invalid_attribute_value: "Specified value {input} is not a valid attribute value." + npc_attribute_invalid_entity_type: "Specified value {input} is not a valid entity type." \ No newline at end of file From 77180a7ffea02b9db581b169d19f694a4cce424a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:08:33 +0200 Subject: [PATCH 03/94] fix translation key in /fancynpcs command --- src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java index af656d2e..e23bcb90 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java @@ -59,7 +59,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No } return true; } - translator.translate("fancynpcs_syntax:").send(sender); + translator.translate("fancynpcs_syntax").send(sender); return false; } From 3f0632a68a514bc7fe8429e6c0ec32c489867c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:08:50 +0200 Subject: [PATCH 04/94] command: /npc attribute --- .../fancynpcs/commands/npc/AttributeCMD.java | 30 +++++++++---------- src/main/resources/languages/en.yml | 14 +++++---- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java index 1f7999ae..5ed72834 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java @@ -1,7 +1,6 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.AttributeManagerImpl; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; @@ -10,14 +9,15 @@ import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class AttributeCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); private final AttributeManagerImpl attributeManager = FancyNpcs.getInstance().getAttributeManager(); @Override @@ -51,18 +51,18 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } if (args.length < 4) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_attribute_syntax").send(sender); return false; } - String attributeName = args[2]; + String attributeName = args[2].toLowerCase(); // note: forced lower-case for better command output String value = ""; for (int i = 3; i < args.length; i++) { @@ -72,32 +72,32 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull NpcAttribute attribute = attributeManager.getAttributeByName(npc.getData().getType(), attributeName); if (attribute == null) { - MessageHelper.error(receiver, lang.get("npc-command-attribute-attribute-not-found")); + translator.translate("npc_attribute_invalid_attribute").replace("input", attributeName).send(sender); return false; } if (!attribute.getTypes().contains(npc.getData().getType())) { - MessageHelper.error(receiver, lang.get("npc-command-attribute-wrong-entity-type")); + translator.translate("npc_attribute_invalid_attribute_value").replace("input", attributeName).send(sender); return false; } if (!attribute.isValidValue(value)) { - MessageHelper.error(receiver, lang.get("npc-command-attribute-invalid-value")); + translator.translate("npc_attribute_invalid_entity_type").replace("input", value).send(sender); return false; } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.ATTRIBUTE, new Object[]{attribute, value}, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.ATTRIBUTE, new Object[]{attribute, value}, sender); npcModifyEvent.callEvent(); if (npcModifyEvent.isCancelled()) { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); return false; } npc.getData().addAttribute(attribute, value); npc.updateForAll(); - MessageHelper.success(receiver, lang.get("npc-command-attribute-success")); + translator.translate("npc_attribute_set").replace("attribute", attributeName).replace("value", value).send(sender); return false; } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 4fa123fb..57c1b588 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -8,17 +8,19 @@ messages: command_missing_permissions: "" command_wrong_usage: "" command_player_only: "" - command_invalid_world: "" - command_invalid_npc: "" + command_invalid_world: "World named {npc} does not exist." + command_invalid_npc: "NPC named {npc} does not exist." command_unsupported_npc_type: "This NPC type does not support this feature." + command_npc_modification_cancelled: "NPC modification has been cancelled by the API." # Commands fancynpcs_syntax: "/fancynpcs (version|reload|save)" - fancynpcs_reload_success: "Plugin has been reloaded." - fancynpcs_save_success: "NPCs has been saved." + fancynpcs_reload_success: "Plugin has been reloaded." + fancynpcs_save_success: "NPCs has been saved." fancynpcs_version: "" # NOT CONFIGURABLE fancynpcs_feature_flags_header: "" # NOT CONFIGURABLE fancynpcs_feature_flags_entry: "" # NOT CONFIGURABLE + npc_attribute_syntax: "Syntax: /npc attribute (npc) (attribute) (value)" npc_attribute_set: "Attribute {attribute} has been set to {value}." npc_attribute_invalid_attribute: "Specified value {input} is not a valid attribute." - npc_attribute_invalid_attribute_value: "Specified value {input} is not a valid attribute value." - npc_attribute_invalid_entity_type: "Specified value {input} is not a valid entity type." \ No newline at end of file + npc_attribute_invalid_attribute_value: "Specified value {input} is not a valid value for this attribute." + npc_attribute_invalid_entity_type: "Attribute {input} is not a valid for this entity type." \ No newline at end of file From 672a329000092602f3c56099f2f2b640144fb151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 2 Apr 2024 22:48:37 +0200 Subject: [PATCH 05/94] colors --- src/main/java/de/oliver/fancynpcs/FancyNpcs.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index 3fe09414..e746aaca 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -1,6 +1,11 @@ package de.oliver.fancynpcs; -import de.oliver.fancylib.*; +import de.oliver.fancylib.FancyLib; +import de.oliver.fancylib.FileUtils; +import de.oliver.fancylib.LanguageConfig; +import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.Metrics; +import de.oliver.fancylib.VersionConfig; import de.oliver.fancylib.featureFlags.FeatureFlag; import de.oliver.fancylib.featureFlags.FeatureFlagConfig; import de.oliver.fancylib.serverSoftware.ServerSoftware; @@ -17,7 +22,12 @@ import de.oliver.fancynpcs.api.NpcManager; import de.oliver.fancynpcs.commands.FancyNpcsCMD; import de.oliver.fancynpcs.commands.npc.NpcCMD; -import de.oliver.fancynpcs.listeners.*; +import de.oliver.fancynpcs.listeners.PlayerChangedWorldListener; +import de.oliver.fancynpcs.listeners.PlayerJoinListener; +import de.oliver.fancynpcs.listeners.PlayerNpcsListener; +import de.oliver.fancynpcs.listeners.PlayerQuitListener; +import de.oliver.fancynpcs.listeners.PlayerTeleportListener; +import de.oliver.fancynpcs.listeners.PlayerUseUnknownEntityListener; import de.oliver.fancynpcs.tracker.TurnToPlayerTracker; import de.oliver.fancynpcs.tracker.VisibilityTracker; import de.oliver.fancynpcs.v1_19_4.Npc_1_19_4; @@ -141,7 +151,7 @@ public void onEnable() { } languageConfig.load(); - textConfig = new TextConfig("", "", "", "", "", ""); + textConfig = new TextConfig("#E33239", "#AD1D23", "#55FF55", "#FFFF55", "#FF5555", ""); translator = new Translator(textConfig); translator.loadLanguages(getDataFolder().getAbsolutePath()); translator.setSelectedLanguage(translator.getFallbackLanguage()); From 7d0db927f9c946c071fc551a9aa2847361e03ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:03:04 +0200 Subject: [PATCH 06/94] use correct translation key in /npc attribute command --- .../java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java index 5ed72834..f4d433a0 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java @@ -77,12 +77,12 @@ public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull St } if (!attribute.getTypes().contains(npc.getData().getType())) { - translator.translate("npc_attribute_invalid_attribute_value").replace("input", attributeName).send(sender); + translator.translate("npc_attribute_invalid_entity_type").replace("input", attributeName).send(sender); return false; } if (!attribute.isValidValue(value)) { - translator.translate("npc_attribute_invalid_entity_type").replace("input", value).send(sender); + translator.translate("npc_attribute_invalid_attribute_value").replace("input", value).send(sender); return false; } From dedeca0d77566b3950c09e5d1c3671835efea273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:03:15 +0200 Subject: [PATCH 07/94] FancyLib 1.0.14 --- gradle.properties | 2 +- src/main/resources/languages/en.yml | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/gradle.properties b/gradle.properties index 02a5ffb3..7c670937 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ minecraftVersion=1.20.4 -fancyLibVersion=1.0.13 +fancyLibVersion=1.0.14 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 \ No newline at end of file diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 57c1b588..5274dfd6 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -8,19 +8,19 @@ messages: command_missing_permissions: "" command_wrong_usage: "" command_player_only: "" - command_invalid_world: "World named {npc} does not exist." - command_invalid_npc: "NPC named {npc} does not exist." + command_invalid_world: "› {errorColor}World named {warningColor}{npc}{errorColor} does not exist." + command_invalid_npc: "› {errorColor}NPC named {warningColor}{npc}{errorColor} does not exist." command_unsupported_npc_type: "This NPC type does not support this feature." - command_npc_modification_cancelled: "NPC modification has been cancelled by the API." + command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." # Commands - fancynpcs_syntax: "/fancynpcs (version|reload|save)" - fancynpcs_reload_success: "Plugin has been reloaded." - fancynpcs_save_success: "NPCs has been saved." + fancynpcs_syntax: "{primaryColor}/fancynpcs {secondaryColor}(version|reload|save)" + fancynpcs_reload_success: "› {successColor}Plugin has been reloaded." + fancynpcs_save_success: "› {successColor}NPCs has been saved." fancynpcs_version: "" # NOT CONFIGURABLE fancynpcs_feature_flags_header: "" # NOT CONFIGURABLE fancynpcs_feature_flags_entry: "" # NOT CONFIGURABLE - npc_attribute_syntax: "Syntax: /npc attribute (npc) (attribute) (value)" - npc_attribute_set: "Attribute {attribute} has been set to {value}." - npc_attribute_invalid_attribute: "Specified value {input} is not a valid attribute." - npc_attribute_invalid_attribute_value: "Specified value {input} is not a valid value for this attribute." - npc_attribute_invalid_entity_type: "Attribute {input} is not a valid for this entity type." \ No newline at end of file + npc_attribute_syntax: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) (attribute) (value)" + npc_attribute_set: "Attribute {primaryColor}{attribute} has been set to {primaryColor}{value}." + npc_attribute_invalid_attribute: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid attribute." + npc_attribute_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." + npc_attribute_invalid_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not a valid for this entity type." \ No newline at end of file From 27b09c56f9405980fb3e7326b775969df937a846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 6 Apr 2024 19:19:43 +0200 Subject: [PATCH 08/94] FancyLib 1.0.15 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7c670937..d5dd926f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ minecraftVersion=1.20.4 -fancyLibVersion=1.0.14 +fancyLibVersion=1.0.15 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 \ No newline at end of file From 4efdaf5c707142462f88f7a4301e29c68c36e21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 6 Apr 2024 19:46:00 +0200 Subject: [PATCH 09/94] FancyLib 1.0.16 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d5dd926f..e1e51955 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ minecraftVersion=1.20.4 -fancyLibVersion=1.0.15 +fancyLibVersion=1.0.16 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 \ No newline at end of file From 560001119109a80c5f87a31b31e9e0236d21d88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 6 Apr 2024 19:57:01 +0200 Subject: [PATCH 10/94] FancyLib 1.0.17 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e1e51955..b5dce20d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ minecraftVersion=1.20.4 -fancyLibVersion=1.0.16 +fancyLibVersion=1.0.17 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 \ No newline at end of file From 10fbe9d195a254027e8a002b371f9a4e4bbb6bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 6 Apr 2024 20:57:34 +0200 Subject: [PATCH 11/94] FancyLib 1.0.18 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b5dce20d..861be4b8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ minecraftVersion=1.20.4 -fancyLibVersion=1.0.17 +fancyLibVersion=1.0.18 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 \ No newline at end of file From 0320837b81e2ab3bb16e013282d6a85cce0081b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 6 Apr 2024 21:31:24 +0200 Subject: [PATCH 12/94] /npc help --- .../oliver/fancynpcs/commands/npc/NpcCMD.java | 69 +++++++++---------- src/main/resources/languages/en.yml | 28 +++++++- 2 files changed, 60 insertions(+), 37 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java index eef62b6c..fe80974a 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java @@ -2,12 +2,19 @@ import de.oliver.fancylib.LanguageConfig; import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; +import de.oliver.fancylib.translations.message.MultiMessage; +import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.commands.Subcommand; +import net.kyori.adventure.text.Component; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import org.yaml.snakeyaml.Yaml; + import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -18,6 +25,7 @@ public class NpcCMD extends Command { private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); private final Subcommand attributeCMD = new AttributeCMD(); private final Subcommand collidableCMD = new CollidableCMD(); private final Subcommand displayNameCMD = new DisplayNameCMD(); @@ -103,44 +111,23 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No if (args.length >= 1 && args[0].equalsIgnoreCase("help")) { if (!sender.hasPermission("fancynpcs.npc.help") && !sender.hasPermission("fancynpcs.npc.*")) { - MessageHelper.error(sender, lang.get("no-permission-subcommand")); + translator.translate("command_missing_permissions").send(sender); return false; } - // TO-DO: Replace with automatic pagination once better configuration system is in place. - final String maxPages = "3"; - if (args.length == 1 || args[1].equals("1")) { - MessageHelper.info(sender, lang.get("npc-command-help-header").replace("{page}", "1").replace("{max_pages}", maxPages)); - MessageHelper.info(sender, lang.get("npc-command-help-create")); - MessageHelper.info(sender, lang.get("npc-command-help-remove")); - MessageHelper.info(sender, lang.get("npc-command-help-copy")); - MessageHelper.info(sender, lang.get("npc-command-help-list")); - MessageHelper.info(sender, lang.get("npc-command-help-skin")); - MessageHelper.info(sender, lang.get("npc-command-help-type")); - MessageHelper.info(sender, lang.get("npc-command-help-moveHere")); - MessageHelper.info(sender, lang.get("npc-command-help-teleport")); - MessageHelper.info(sender, lang.get("npc-command-help-footer").replace("{page}", "1").replace("{max_pages}", maxPages)); - } - else if (args[1].equals("2")) { - MessageHelper.info(sender, lang.get("npc-command-help-header").replace("{page}", "2").replace("{max_pages}", maxPages)); - MessageHelper.info(sender, lang.get("npc-command-help-displayName")); - MessageHelper.info(sender, lang.get("npc-command-help-equipment")); - MessageHelper.info(sender, lang.get("npc-command-help-message")); - MessageHelper.info(sender, lang.get("npc-command-help-playerCommand")); - MessageHelper.info(sender, lang.get("npc-command-help-serverCommand")); - MessageHelper.info(sender, lang.get("npc-command-help-showInTab")); - MessageHelper.info(sender, lang.get("npc-command-help-glowing")); - MessageHelper.info(sender, lang.get("npc-command-help-glowingColor")); - MessageHelper.info(sender, lang.get("npc-command-help-footer").replace("{page}", "2").replace("{max_pages}", maxPages)); - } - else if (args[1].equals("3")) { - MessageHelper.info(sender, lang.get("npc-command-help-header").replace("{page}", "3").replace("{max_pages}", maxPages)); - MessageHelper.info(sender, lang.get("npc-command-help-collidable")); - MessageHelper.info(sender, lang.get("npc-command-help-turnToPlayer")); - MessageHelper.info(sender, lang.get("npc-command-help-attribute")); - MessageHelper.info(sender, lang.get("npc-command-help-interactionCooldown")); - MessageHelper.info(sender, lang.get("npc-command-help-mirrorSkin")); - MessageHelper.info(sender, lang.get("npc-command-help-footer").replace("{page}", "3").replace("{max_pages}", maxPages)); - } + // Getting the (full) help contents. + final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); + // Calculating max page number. + final int maxPage = contents.getRawMessages().size() / 6 + 1; + // Getting the requested page. Defaults to 1 for invalid input and is capped by number of the last page. + final int page = Math.min(args.length == 2 ? parseIntOrDefault(args[1], 1) : 1, maxPage); + // Getting help contents for requested page, or defaulting to 1. + final MultiMessage requestedContents = contents.page(page, 6); + // Sending help header to the sender. + translator.translate("npc_help_page_header").replace("page", String.valueOf(page)).replace("max_page", String.valueOf(maxPage)).send(sender); + // Sending (requested) help contents to the sender. + requestedContents.send(sender); + // Sending help footer to the sender. + translator.translate("npc_help_page_footer").replace("page", String.valueOf(page)).replace("max_page", String.valueOf(maxPage)).send(sender); return true; } @@ -263,4 +250,14 @@ else if (args[1].equals("3")) { } } } + + // Parses String to Integer and returns it, or default if failed. + private static int parseIntOrDefault(final String str, final int def) { + try { + return Integer.parseInt(str); + } catch (final NumberFormatException e) { + return def; + } + } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 5274dfd6..4984e72b 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -19,8 +19,34 @@ messages: fancynpcs_version: "" # NOT CONFIGURABLE fancynpcs_feature_flags_header: "" # NOT CONFIGURABLE fancynpcs_feature_flags_entry: "" # NOT CONFIGURABLE + npc_help_page_header: "Commands for {primaryColor}FancyNpcs plugin: ({primaryColor}{page}/{primaryColor}{max_page})" + npc_help_page_footer: "Full command reference available {primaryColor}here." + npc_help_contents: + - "› {primaryColor}/npc create {secondaryColor}(npc) - Creates a new NPC at your location." + - "› {primaryColor}/npc remove {secondaryColor}(npc) - Removes specified NPC." + - "› {primaryColor}/npc copy {secondaryColor}(npc) (new_name) - Copies/clones specified NPC." + - "› {primaryColor}/npc list - Lists all loaded NPCs." + - "› {primaryColor}/npc skin {secondaryColor}(skin) - Changes skin of an NPC." + - "› {primaryColor}/npc type {secondaryColor}(npc) (type) - Changes entity type of an NPC." + - "› {primaryColor}/npc movehere {secondaryColor}(npc) - Teleports NPC to your location." + - "› {primaryColor}/npc teleport {secondaryColor}(npc) (x) (y) (z) [world] - Teleports NPC." + - "› {primaryColor}/npc displayname {secondaryColor}(npc) (name) - Changes NPC's displayname." + - "› {primaryColor}/npc equipment {secondaryColor}(npc) (slot) - Changes equipment of an NPC." + - "› {primaryColor}/npc message {secondaryColor}(npc) (...) - Changes click message(s)." + - "› {primaryColor}/npc playerCommand {secondaryColor}(npc) (...) - Changes click command(s)." + - "› {primaryColor}/npc serverCommand {secondaryColor}(npc) (...) - Changes click command(s)." + - "› {primaryColor}/npc showInTab {secondaryColor}(npc) (state) - Changes tab-list visibility." + - "› {primaryColor}/npc glowing {secondaryColor}(npc) (state) - Changes glowing effect state." + - "› {primaryColor}/npc glowingColor {secondaryColor}(npc) (color) - Changes glowing color." + - "› {primaryColor}/npc collidable {secondaryColor}(npc) (state) - Changes collidable state." + - "› {primaryColor}/npc turnToPlayer {secondaryColor}(npc) (state) - Changes turning state." + - "› {primaryColor}/npc attribute {secondaryColor}(npc) (attr) (value) - Sets entity attribute." + - "› {primaryColor}/npc interactionCooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." + - "› {primaryColor}/npc mirrorSkin {secondaryColor}(npc) (state) - Changes skin mirroring state." npc_attribute_syntax: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) (attribute) (value)" npc_attribute_set: "Attribute {primaryColor}{attribute} has been set to {primaryColor}{value}." npc_attribute_invalid_attribute: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid attribute." npc_attribute_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." - npc_attribute_invalid_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not a valid for this entity type." \ No newline at end of file + npc_attribute_invalid_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not a valid for this entity type." + + From 908c288b68191e6cfaacf86eabd889ed9102523f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 6 Apr 2024 21:46:45 +0200 Subject: [PATCH 13/94] command_wrong_usage, command_missing_permissions, command_player_only --- .../oliver/fancynpcs/commands/npc/NpcCMD.java | 21 +++++++------------ src/main/resources/languages/en.yml | 6 +++--- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java index fe80974a..5cedbab8 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java @@ -1,30 +1,23 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; import de.oliver.fancylib.translations.Translator; import de.oliver.fancylib.translations.message.MultiMessage; -import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.commands.Subcommand; -import net.kyori.adventure.text.Component; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; -import org.yaml.snakeyaml.Yaml; - -import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; + public class NpcCMD extends Command { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); private final Translator translator = FancyNpcs.getInstance().getTranslator(); private final Subcommand attributeCMD = new AttributeCMD(); private final Subcommand collidableCMD = new CollidableCMD(); @@ -50,7 +43,7 @@ public NpcCMD() { @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { if (!(sender instanceof Player p)) { - MessageHelper.error(sender, lang.get("only-players")); + translator.translate("command_player_only").send(sender); return null; } @@ -136,7 +129,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No } if (args.length < 2) { - MessageHelper.error(sender, lang.get("wrong-usage")); + translator.translate("command_wrong_usage").send(sender); return false; } @@ -151,7 +144,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No if (!sender.hasPermission("fancynpcs.npc." + subcommand) && !sender.hasPermission("fancynpcs.npc.*")) { - MessageHelper.error(sender, lang.get("no-permission-subcommand")); + translator.translate("command_missing_permissions").send(sender); return false; } @@ -245,13 +238,13 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No } default -> { - MessageHelper.error(sender, lang.get("wrong-usage")); + translator.translate("command_wrong_usage").send(sender); return false; } } } - // Parses String to Integer and returns it, or default if failed. + // Parses String to Integer and returns it, or default value if exception was caught. private static int parseIntOrDefault(final String str, final int def) { try { return Integer.parseInt(str); diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 4984e72b..6cfe1330 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -5,9 +5,9 @@ messages: # Common interaction_on_cooldown: "" # Commands (Common Replies) - command_missing_permissions: "" - command_wrong_usage: "" - command_player_only: "" + command_missing_permissions: "› {errorColor}Insufficient permissions. You cannot use this command." + command_wrong_usage: "› {errorColor}This sub-command does not exist. Use {warningColor}/npc help{errorColor} to view available commands." + command_player_only: "› {errorColor}This command can only be executed by in-game players." command_invalid_world: "› {errorColor}World named {warningColor}{npc}{errorColor} does not exist." command_invalid_npc: "› {errorColor}NPC named {warningColor}{npc}{errorColor} does not exist." command_unsupported_npc_type: "This NPC type does not support this feature." From 4ee68b3dddc021fb82b06a32afde9a3829b1df53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 6 Apr 2024 21:46:56 +0200 Subject: [PATCH 14/94] fix /fancynpcs reload (temporarily) --- src/main/java/de/oliver/fancynpcs/FancyNpcs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index e746aaca..31dcd281 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -154,7 +154,7 @@ public void onEnable() { textConfig = new TextConfig("#E33239", "#AD1D23", "#55FF55", "#FFFF55", "#FF5555", ""); translator = new Translator(textConfig); translator.loadLanguages(getDataFolder().getAbsolutePath()); - translator.setSelectedLanguage(translator.getFallbackLanguage()); + translator.setSelectedLanguage(translator.getFallbackLanguage()); // WIP: Make it configurable. versionConfig.load(); From 146cd53049baff2d60a44a3c91f0b4d969832431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 00:18:23 +0200 Subject: [PATCH 15/94] /npc collidable --- .../fancynpcs/commands/npc/CollidableCMD.java | 29 ++++++++----------- src/main/resources/languages/en.yml | 7 +++++ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java index ae675bb4..4e93c7e1 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java @@ -1,22 +1,22 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class CollidableCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -30,14 +30,14 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_collidable_syntax").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -45,24 +45,19 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull try { collidable = Boolean.parseBoolean(args[2]); } catch (Exception e) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("command_invalid_boolean").replace("input", args[2]).send(sender); return false; } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.COLLIDABLE, collidable, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.COLLIDABLE, collidable, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { npc.getData().setCollidable(collidable); npc.updateForAll(); - - if (collidable) { - MessageHelper.success(receiver, lang.get("npc-command-collidable-true", "npc", npc.getData().getName())); - } else { - MessageHelper.success(receiver, lang.get("npc-command-collidable-false", "npc", npc.getData().getName())); - } + translator.translate(collidable ? "npc_collidable_set_true" : "npc_collidable_set_false").replace("npc", npc.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled", "npc", npc.getData().getName())); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 6cfe1330..f0914058 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -8,6 +8,7 @@ messages: command_missing_permissions: "› {errorColor}Insufficient permissions. You cannot use this command." command_wrong_usage: "› {errorColor}This sub-command does not exist. Use {warningColor}/npc help{errorColor} to view available commands." command_player_only: "› {errorColor}This command can only be executed by in-game players." + command_invalid_boolean: "› {errorColor}Argument {warningColor}{input}{errorColor} must be either {warningColor}true{errorColor} or {warningColor}false{errorColor}." command_invalid_world: "› {errorColor}World named {warningColor}{npc}{errorColor} does not exist." command_invalid_npc: "› {errorColor}NPC named {warningColor}{npc}{errorColor} does not exist." command_unsupported_npc_type: "This NPC type does not support this feature." @@ -49,4 +50,10 @@ messages: npc_attribute_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." npc_attribute_invalid_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not a valid for this entity type." + npc_collidable_syntax: "Syntax: {primaryColor}/npc collidable {secondaryColor}(npc) (state)" + npc_collidable_set_true: "NPC named {warningColor}{npc} is now {successColor}collidable." + npc_collidable_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}collidable." + + npc_copy_success: "NPC named {warningColor}{npc} has been copied to {warningColor}{new_npc}." + From 66d7d913c5f638d8bac4454fb80ab1f27351500a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 00:24:20 +0200 Subject: [PATCH 16/94] /npc copy --- .../fancynpcs/commands/npc/CopyCMD.java | 24 +++++++++---------- src/main/resources/languages/en.yml | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java index 8a5acb8f..833c9927 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java @@ -1,7 +1,6 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.NpcData; @@ -9,15 +8,16 @@ import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.UUID; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class CopyCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -25,19 +25,19 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (!(receiver instanceof Player player)) { - MessageHelper.error(receiver, lang.get("npc-command.only-players")); + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { + if (!(sender instanceof Player player)) { + translator.translate("command_player_only").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_copy_syntax").send(sender); return false; } @@ -76,9 +76,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(copied); copied.spawnForAll(); - MessageHelper.success(receiver, lang.get("npc-command-copy-success", "npc", npc.getData().getName())); + translator.translate("npc_command_copy_success").replace("npc", npc.getData().getName()).replace("new_name", copied.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-copy-cancelled", "npc", npc.getData().getName())); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index f0914058..3a87ce6d 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -54,6 +54,7 @@ messages: npc_collidable_set_true: "NPC named {warningColor}{npc} is now {successColor}collidable." npc_collidable_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}collidable." + npc_copy_syntax: "Syntax: {primaryColor}/npc copy {secondaryColor}(npc) (new_name)" npc_copy_success: "NPC named {warningColor}{npc} has been copied to {warningColor}{new_npc}." From d265b2425e72a226103f76b245074027068ce3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 00:30:27 +0200 Subject: [PATCH 17/94] /npc create --- .../fancynpcs/commands/npc/CreateCMD.java | 17 +++++++++-------- src/main/resources/languages/en.yml | 5 +++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index a56dd813..d979b87c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -2,6 +2,7 @@ import de.oliver.fancylib.LanguageConfig; import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.NpcData; @@ -16,7 +17,7 @@ public class CreateCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -24,9 +25,9 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (!(receiver instanceof Player player)) { - MessageHelper.error(receiver, lang.get("npc-command.only-players")); + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { + if (!(sender instanceof Player player)) { + translator.translate("command_player_only").send(sender); return false; } @@ -34,12 +35,12 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled()) { if (FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name, player.getUniqueId()) != null) { - MessageHelper.error(receiver, lang.get("npc-command-create-name-already-exists", "npc", name)); + translator.translate("npc_create_failure_already_exists").replace("npc", name).send(sender); return false; } } else { if (FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name) != null) { - MessageHelper.error(receiver, lang.get("npc-command-create-name-already-exists", "npc", name)); + translator.translate("npc_create_failure_already_exists").replace("npc", name).send(sender); return false; } } @@ -59,9 +60,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(createdNpc); createdNpc.spawnForAll(); - MessageHelper.success(receiver, lang.get("npc-command-create-created", "npc", name)); + translator.translate("npc_create_success").replace("npc", name).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-create-cancelled", "npc", name)); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 3a87ce6d..c8136a94 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -57,4 +57,9 @@ messages: npc_copy_syntax: "Syntax: {primaryColor}/npc copy {secondaryColor}(npc) (new_name)" npc_copy_success: "NPC named {warningColor}{npc} has been copied to {warningColor}{new_npc}." + npc_create_syntax: "Syntax: {primaryColor}/npc create {secondaryColor}(npc)" + npc_create_success: "NPC named {warningColor}{npc} has been created." + npc_create_failure_already_exists: "› {errorColor}NPC named {warningColor}{npc}{errorColor} already exists." + + From 490aa79e6a062e3b03d5ffc48e0ae8a9da3426ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 08:19:45 +0200 Subject: [PATCH 18/94] fix /npc copy placeholders --- .../java/de/oliver/fancynpcs/commands/npc/CopyCMD.java | 2 +- .../java/de/oliver/fancynpcs/commands/npc/CreateCMD.java | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java index 833c9927..a2b116a9 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java @@ -76,7 +76,7 @@ public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull St FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(copied); copied.spawnForAll(); - translator.translate("npc_command_copy_success").replace("npc", npc.getData().getName()).replace("new_name", copied.getData().getName()).send(sender); + translator.translate("npc_command_copy_success").replace("npc", npc.getData().getName()).replace("new_npc", copied.getData().getName()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index d979b87c..343085f3 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -1,7 +1,5 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; @@ -10,11 +8,12 @@ import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class CreateCMD implements Subcommand { private final Translator translator = FancyNpcs.getInstance().getTranslator(); From e3ce097792c9fb44429df52299c193ff210868ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 08:38:06 +0200 Subject: [PATCH 19/94] command_incomplete_usage --- src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java | 3 ++- src/main/resources/languages/en.yml | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java index 5cedbab8..dcaffff0 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java @@ -128,8 +128,9 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No return new ListCMD().run(sender, null, args); } + // NOTE(command rework): This will be replaced to use command-specific syntax message instead. if (args.length < 2) { - translator.translate("command_wrong_usage").send(sender); + translator.translate("command_incomplete_usage").send(sender); return false; } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index c8136a94..916b0a2b 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -7,6 +7,7 @@ messages: # Commands (Common Replies) command_missing_permissions: "› {errorColor}Insufficient permissions. You cannot use this command." command_wrong_usage: "› {errorColor}This sub-command does not exist. Use {warningColor}/npc help{errorColor} to view available commands." + command_incomplete_usage: "› {errorColor}Incomplete command. Use {warningColor}/npc help{errorColor} to view correct syntax." command_player_only: "› {errorColor}This command can only be executed by in-game players." command_invalid_boolean: "› {errorColor}Argument {warningColor}{input}{errorColor} must be either {warningColor}true{errorColor} or {warningColor}false{errorColor}." command_invalid_world: "› {errorColor}World named {warningColor}{npc}{errorColor} does not exist." @@ -60,6 +61,3 @@ messages: npc_create_syntax: "Syntax: {primaryColor}/npc create {secondaryColor}(npc)" npc_create_success: "NPC named {warningColor}{npc} has been created." npc_create_failure_already_exists: "› {errorColor}NPC named {warningColor}{npc}{errorColor} already exists." - - - From e6f4d13018b37a875dbfb293780f6dfaf9778346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 08:53:55 +0200 Subject: [PATCH 20/94] /npc displayname --- .../commands/npc/DisplayNameCMD.java | 22 +++++++++---------- src/main/resources/languages/en.yml | 4 ++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java index 1d1df264..e2ed88c2 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java @@ -1,22 +1,22 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class DisplayNameCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -29,14 +29,14 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_displayname_syntax").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -46,15 +46,15 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull } displayName = displayName.substring(0, displayName.length() - 1); - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.DISPLAY_NAME, displayName, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.DISPLAY_NAME, displayName, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { npc.getData().setDisplayName(displayName.toString()); npc.updateForAll(); - MessageHelper.success(receiver, lang.get("npc-command-displayName-updated", "npc", npc.getData().getName())); + translator.translate("npc_displayname_success").replace("npc", args[1]).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 916b0a2b..4829eeff 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -61,3 +61,7 @@ messages: npc_create_syntax: "Syntax: {primaryColor}/npc create {secondaryColor}(npc)" npc_create_success: "NPC named {warningColor}{npc} has been created." npc_create_failure_already_exists: "› {errorColor}NPC named {warningColor}{npc}{errorColor} already exists." + + npc_displayname_syntax: "Syntax: {primaryColor}/npc displayname {secondaryColor}(npc) (name)" + npc_displayname_success: "NPC named {npc} has had their display-name updated." + From 4de865dc0b429fc140454cbf212209cc47b8bc76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 16:00:32 +0200 Subject: [PATCH 21/94] fix brackets --- src/main/resources/languages/en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 4829eeff..77354ee9 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -64,4 +64,5 @@ messages: npc_displayname_syntax: "Syntax: {primaryColor}/npc displayname {secondaryColor}(npc) (name)" npc_displayname_success: "NPC named {npc} has had their display-name updated." + npc_displayname_success: "NPC named {warningColor}{npc} has had their display-name updated." From a1cd286acdec249a12cedaa3ce3658a24df4b038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 16:07:02 +0200 Subject: [PATCH 22/94] /npc equipment --- .../fancynpcs/commands/npc/EquipmentCMD.java | 21 ++++++++++--------- src/main/resources/languages/en.yml | 5 ++++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java index 0013853b..402c1de2 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java @@ -2,6 +2,7 @@ import de.oliver.fancylib.LanguageConfig; import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; @@ -18,7 +19,7 @@ public class EquipmentCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -32,20 +33,20 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (!(receiver instanceof Player player)) { - MessageHelper.error(receiver, lang.get("npc-command.only-players")); + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { + if (!(sender instanceof Player player)) { + translator.translate("command_player_only").send(sender); return false; } if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_equipment_syntax").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -53,21 +54,21 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull NpcEquipmentSlot equipmentSlot = NpcEquipmentSlot.parse(slot); if (equipmentSlot == null) { - MessageHelper.error(receiver, lang.get("npc-command-equipment-invalid-slot", "input", slot)); + translator.translate("npc_equipment_failure_invalid_slot").replace("input", slot).send(sender); return false; } ItemStack item = player.getInventory().getItemInMainHand().clone(); - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.EQUIPMENT, new Object[]{equipmentSlot, item}, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.EQUIPMENT, new Object[]{equipmentSlot, item}, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { npc.getData().addEquipment(equipmentSlot, item); npc.updateForAll(); - MessageHelper.success(receiver, lang.get("npc-command-equipment-updated", "npc", npc.getData().getName())); + translator.translate("npc_equipment_success").replace("npc", npc.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 77354ee9..ebbf5f9b 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -63,6 +63,9 @@ messages: npc_create_failure_already_exists: "› {errorColor}NPC named {warningColor}{npc}{errorColor} already exists." npc_displayname_syntax: "Syntax: {primaryColor}/npc displayname {secondaryColor}(npc) (name)" - npc_displayname_success: "NPC named {npc} has had their display-name updated." npc_displayname_success: "NPC named {warningColor}{npc} has had their display-name updated." + npc_equipment_syntax: "Syntax: {primaryColor}/npc equipment {secondaryColor}(npc) (slot)" + npc_equipment_success: "NPC named {warningColor}{npc} has had their equipment updated." + npc_equipment_failure_invalid_slot: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid equipment slot." + From a34d2ac172e0a18728ea2ed7a2a03bc7a466ad96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 16:16:52 +0200 Subject: [PATCH 23/94] /npc fix --- .../java/de/oliver/fancynpcs/commands/npc/FixCMD.java | 9 +++++---- src/main/resources/languages/en.yml | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java index 016a0841..780eb712 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java @@ -2,6 +2,7 @@ import de.oliver.fancylib.LanguageConfig; import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.commands.Subcommand; @@ -15,7 +16,7 @@ public class FixCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -23,9 +24,9 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -33,7 +34,7 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.create(); Bukkit.getOnlinePlayers().forEach(npc::checkAndUpdateVisibility); - MessageHelper.success(receiver, lang.get("npc-command-fix-success")); + translator.translate("npc_fix_success").replace("npc", npc.getData().getName()).send(sender); return true; } } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index ebbf5f9b..fa48b3e3 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -69,3 +69,5 @@ messages: npc_equipment_success: "NPC named {warningColor}{npc} has had their equipment updated." npc_equipment_failure_invalid_slot: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid equipment slot." + npc_fix_success: "Attempted to fix NPC named {warningColor}{npc}... Still having issues? Please let us know." + From ffbc068f8ea63c7fcc9ab013ec763af45a6c2160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 19:35:32 +0200 Subject: [PATCH 24/94] /npc glowingColor --- .../commands/npc/GlowingColorCMD.java | 24 +++++++++---------- src/main/resources/languages/en.yml | 5 ++++ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java index 6010e3f3..6ed23c97 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java @@ -1,7 +1,6 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; @@ -9,14 +8,15 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class GlowingColorCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -30,33 +30,33 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_glowingColor_syntax").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").send(sender); return false; } NamedTextColor color = NamedTextColor.NAMES.value(args[2]); if (color == null) { - MessageHelper.error(receiver, lang.get("npc-command-glowingColor-invalid", "input", args[2])); + translator.translate("npc_glowingColor_failure_invalid_color").replace("input", args[2]).send(sender); return false; } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING_COLOR, color, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING_COLOR, color, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { npc.getData().setGlowingColor(color); npc.updateForAll(); - MessageHelper.success(receiver, lang.get("npc-command-glowingColor-updated", "npc", npc.getData().getName())); + translator.translate("npc_glowingColor_failure_invalid_color").replace("input", npc.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index fa48b3e3..7e41dd38 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -71,3 +71,8 @@ messages: npc_fix_success: "Attempted to fix NPC named {warningColor}{npc}... Still having issues? Please let us know." + npc_glowingColor_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (state)" + npc_glowingColor_success: "NPC named {warningColor}{npc} has had their glowing color updated." + npc_glowingColor_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." + + From c84171892a3d708fd831ef7acf7756374b4e539e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:18:06 +0200 Subject: [PATCH 25/94] tweak default colors --- src/main/java/de/oliver/fancynpcs/FancyNpcs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index 31dcd281..58cdfa48 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -151,7 +151,7 @@ public void onEnable() { } languageConfig.load(); - textConfig = new TextConfig("#E33239", "#AD1D23", "#55FF55", "#FFFF55", "#FF5555", ""); + textConfig = new TextConfig("#E33239", "#AD1D23", "#81E366", "#E3CA66", "#E36666", ""); translator = new Translator(textConfig); translator.loadLanguages(getDataFolder().getAbsolutePath()); translator.setSelectedLanguage(translator.getFallbackLanguage()); // WIP: Make it configurable. From 48380592de93a7ccc1116f13e41a317519715ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 23:03:06 +0200 Subject: [PATCH 26/94] /npc glowing --- .../fancynpcs/commands/npc/GlowingCMD.java | 29 ++++++++----------- src/main/resources/languages/en.yml | 4 +++ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java index 659dee12..d002035d 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java @@ -1,22 +1,22 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class GlowingCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -30,15 +30,15 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_glowing_syntax").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -46,24 +46,19 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull try { glowing = Boolean.parseBoolean(args[2]); } catch (Exception e) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("command_invalid_boolean").replace("input", args[2]).send(sender); return false; } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, glowing, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, glowing, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { npc.getData().setGlowing(glowing); npc.updateForAll(); - - if (glowing) { - MessageHelper.success(receiver, lang.get("npc-command-glowing-true", "npc", npc.getData().getName())); - } else { - MessageHelper.success(receiver, lang.get("npc-command-glowing-false", "npc", npc.getData().getName())); - } + translator.translate(glowing ? "npc_glowing_set_true" : "npc_glowing_set_false").replace("npc", npc.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 7e41dd38..edbf302a 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -71,6 +71,10 @@ messages: npc_fix_success: "Attempted to fix NPC named {warningColor}{npc}... Still having issues? Please let us know." + npc_glowing_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (state)" + npc_glowing_set_true: "NPC named {warningColor}{npc} is now {successColor}glowing." + npc_glowing_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}glowing." + npc_glowingColor_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (state)" npc_glowingColor_success: "NPC named {warningColor}{npc} has had their glowing color updated." npc_glowingColor_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." From 1d8f1fa1d447ffa049c7a311715cf3cee3db84bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 23:11:43 +0200 Subject: [PATCH 27/94] fix /npc glowingColor --- .../de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java index 6ed23c97..0399494f 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java @@ -38,7 +38,7 @@ public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull St if (npc == null) { - translator.translate("command_invalid_npc").send(sender); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -54,7 +54,7 @@ public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull St if (!npcModifyEvent.isCancelled()) { npc.getData().setGlowingColor(color); npc.updateForAll(); - translator.translate("npc_glowingColor_failure_invalid_color").replace("input", npc.getData().getName()).send(sender); + translator.translate("npc_glowingColor_success").replace("npc", npc.getData().getName()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } From 4f1fc810e91849ac8e9708da64078bd2fb9f3077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 23:16:50 +0200 Subject: [PATCH 28/94] /npc interactionCooldown --- .../commands/npc/InteractionCooldownCMD.java | 24 +++++++++---------- src/main/resources/languages/en.yml | 5 ++++ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java index d5c32ed3..33d292b2 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java @@ -1,21 +1,21 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class InteractionCooldownCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -23,14 +23,14 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_interactionCooldown_syntax").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -38,18 +38,18 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull try { cooldown = Float.parseFloat(args[2]); } catch (NumberFormatException e) { - MessageHelper.error(receiver, lang.get("could-not-parse-number")); + translator.translate("command_invalid_number").replace("input", args[2]).send(sender); return false; } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.INTERACTION_COOLDOWN, cooldown, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.INTERACTION_COOLDOWN, cooldown, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { npc.getData().setInteractionCooldown(cooldown); - MessageHelper.success(receiver, lang.get("npc-command-interactioncooldown-updated")); + translator.translate("npc_interactionCooldown_success").replace("npc", npc.getData().getName()); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index edbf302a..bd2de24e 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -10,6 +10,8 @@ messages: command_incomplete_usage: "› {errorColor}Incomplete command. Use {warningColor}/npc help{errorColor} to view correct syntax." command_player_only: "› {errorColor}This command can only be executed by in-game players." command_invalid_boolean: "› {errorColor}Argument {warningColor}{input}{errorColor} must be either {warningColor}true{errorColor} or {warningColor}false{errorColor}." + command_invalid_number: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid number." + command_invalid_integer: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid integer." command_invalid_world: "› {errorColor}World named {warningColor}{npc}{errorColor} does not exist." command_invalid_npc: "› {errorColor}NPC named {warningColor}{npc}{errorColor} does not exist." command_unsupported_npc_type: "This NPC type does not support this feature." @@ -79,4 +81,7 @@ messages: npc_glowingColor_success: "NPC named {warningColor}{npc} has had their glowing color updated." npc_glowingColor_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." + npc_interactionCooldown_syntax: "Syntax: {primaryColor}/npc interactionCooldown {secondaryColor}(npc) (seconds)" + npc_interactionCooldown_success: "NPC named {warningColor}{npc} has had their interaction cooldown updated." + From 9cd0290502deaec32cfbf898825b6faed985aa19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 23:22:11 +0200 Subject: [PATCH 29/94] /npc mirrorSkin --- .../fancynpcs/commands/npc/MirrorSkinCMD.java | 28 ++++++++----------- src/main/resources/languages/en.yml | 4 +++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java index d6918f65..0455bec3 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java @@ -1,22 +1,23 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class MirrorSkinCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -30,15 +31,15 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_mirrorSkin_syntax").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -46,11 +47,11 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull try { mirrorSkin = Boolean.parseBoolean(args[2]); } catch (Exception e) { - MessageHelper.error(receiver, lang.get("npc-command-wrong_usage")); + translator.translate("command_invalid_boolean").replace("input", args[2]).send(sender); return false; } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, mirrorSkin, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, mirrorSkin, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { @@ -58,14 +59,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.removeForAll(); npc.create(); npc.spawnForAll(); - - if (mirrorSkin) { - MessageHelper.success(receiver, lang.get("npc-command-mirrorSkin-true", "npc", npc.getData().getName())); - } else { - MessageHelper.success(receiver, lang.get("npc-command-mirrorSkin-false", "npc", npc.getData().getName())); - } + translator.translate(mirrorSkin ? "npc_mirrorSkin_set_true" : "npc_mirrorSkin_set_false").replace("npc", npc.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index bd2de24e..7623796f 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -84,4 +84,8 @@ messages: npc_interactionCooldown_syntax: "Syntax: {primaryColor}/npc interactionCooldown {secondaryColor}(npc) (seconds)" npc_interactionCooldown_success: "NPC named {warningColor}{npc} has had their interaction cooldown updated." + npc_mirrorSkin_syntax: "Syntax: {primaryColor}/npc mirrorSkin {secondaryColor}(npc) (state)" + npc_mirrorSkin_set_true: "NPC named {warningColor}{npc} is now {successColor}mirroring player skin." + npc_mirrorSkin_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}mirroring player skin." + From 2815d261e1d0da992461a7415bd6b93abd2464cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 23:25:52 +0200 Subject: [PATCH 30/94] /npc moveHere --- .../fancynpcs/commands/npc/MoveHereCMD.java | 25 +++++++++---------- src/main/resources/languages/en.yml | 4 +++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java index b0058fbb..f2be8abb 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java @@ -1,7 +1,6 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; @@ -9,14 +8,15 @@ import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class MoveHereCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -24,20 +24,20 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (!(receiver instanceof Player player)) { - MessageHelper.error(receiver, lang.get("npc-command.only-players")); + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { + if (!(sender instanceof Player player)) { + translator.translate("command_player_only").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } Location location = player.getLocation(); - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender); npcModifyEvent.callEvent(); String oldWorld = npc.getData().getLocation().getWorld().getName(); @@ -51,10 +51,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.removeForAll(); npc.spawnForAll(); } - - MessageHelper.success(receiver, lang.get("npc-command-moveHere-moved", "npc", npc.getData().getName())); + translator.translate("npc_moveHere_success").replace("npc", npc.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled", "npc", npc.getData().getName())); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 7623796f..8a8b369f 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -88,4 +88,8 @@ messages: npc_mirrorSkin_set_true: "NPC named {warningColor}{npc} is now {successColor}mirroring player skin." npc_mirrorSkin_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}mirroring player skin." + npc_moveHere_syntax: "Syntax: {primaryColor}/npc moveHere {secondaryColor}(npc)" + npc_moveHere_success: "NPC named {warningColor}{npc} has been moved to your location." + + From 93e0f830b41d5d8a5230c84dba6f9faa53d2f1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 7 Apr 2024 23:28:24 +0200 Subject: [PATCH 31/94] /npc remove --- .../fancynpcs/commands/npc/RemoveCMD.java | 20 +++++++++---------- src/main/resources/languages/en.yml | 3 +++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java index c098cfb6..ac5be5bf 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java @@ -1,7 +1,6 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcRemoveEvent; @@ -10,14 +9,15 @@ import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class RemoveCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -25,13 +25,13 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } - NpcRemoveEvent npcRemoveEvent = new NpcRemoveEvent(npc, receiver); + NpcRemoveEvent npcRemoveEvent = new NpcRemoveEvent(npc, sender); npcRemoveEvent.callEvent(); if (!npcRemoveEvent.isCancelled()) { npc.removeForAll(); @@ -45,9 +45,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull } } FancyNpcs.getInstance().getNpcManagerImpl().removeNpc(npc); - MessageHelper.success(receiver, lang.get("npc-command-remove-removed", "npc", npc.getData().getName())); + translator.translate("npc_remove_success").replace("npc", npc.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-remove-cancelled", "npc", npc.getData().getName())); + translator.translate("command_npc_modification_cancelled").send(sender); } return false; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 8a8b369f..1964f3a1 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -91,5 +91,8 @@ messages: npc_moveHere_syntax: "Syntax: {primaryColor}/npc moveHere {secondaryColor}(npc)" npc_moveHere_success: "NPC named {warningColor}{npc} has been moved to your location." + npc_remove_syntax: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" + npc_remove_success: "NPC named {warningColor}{npc} has been removed." + From 195fcda428e2378aaf2f2e6beea69418f987d1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Mon, 8 Apr 2024 11:11:06 +0200 Subject: [PATCH 32/94] /npc showInTab --- .../fancynpcs/commands/npc/ShowInTabCMD.java | 31 ++++++++----------- src/main/resources/languages/en.yml | 4 ++- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java index 80404478..d6e0d987 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java @@ -1,7 +1,6 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; @@ -9,15 +8,16 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class ShowInTabCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -31,20 +31,20 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_showInTab_syntax").send(sender); return false; } if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } if (npc.getData().getType() != EntityType.PLAYER) { - MessageHelper.error(receiver, lang.get("npc-must-be-player")); + translator.translate("command_unsupported_npc_type").send(sender); return false; } @@ -53,12 +53,12 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull case "true" -> showInTab = true; case "false" -> showInTab = false; default -> { - MessageHelper.error(receiver, lang.get("npc-command-showInTab-invalid-argument", "input", args[2].toLowerCase())); + translator.translate("command_invalid_boolean").replace("input", args[2].toLowerCase()); return false; } } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SHOW_IN_TAB, showInTab, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SHOW_IN_TAB, showInTab, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { @@ -70,14 +70,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.removeForAll(); npc.spawnForAll(); } - - if (showInTab) { - MessageHelper.success(receiver, lang.get("npc-command-showInTab-true", "npc", npc.getData().getName())); - } else { - MessageHelper.success(receiver, lang.get("npc-command-showInTab-false", "npc", npc.getData().getName())); - } + translator.translate(showInTab ? "npc_showInTab_set_true" : "npc_showInTab_set_false").replace("npc", npc.getData().getName()).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 1964f3a1..db5e814c 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -95,4 +95,6 @@ messages: npc_remove_success: "NPC named {warningColor}{npc} has been removed." - + npc_showInTab_syntax: "Syntax: {primaryColor}/npc showInTab {secondaryColor}(npc) (state)" + npc_showInTab_set_true: "NPC named {warningColor}{npc} is now {successColor}shown in player-list." + npc_showInTab_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}shown in player-list." From c491eff384acab517126684cc143c5db95ef21b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:12:29 +0200 Subject: [PATCH 33/94] FancyLib 1.0.19 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 861be4b8..4ebbb0af 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ minecraftVersion=1.20.4 -fancyLibVersion=1.0.18 +fancyLibVersion=1.0.19 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 \ No newline at end of file From 3c1d769a1c3f4a8818dcefc115fbdb651b54ee10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:14:40 +0200 Subject: [PATCH 34/94] FancyLib 1.0.20 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4ebbb0af..1d42536b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ minecraftVersion=1.20.4 -fancyLibVersion=1.0.19 +fancyLibVersion=1.0.20 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 \ No newline at end of file From 3da3495f394acf92a2671355514767a9ae852c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:15:10 +0200 Subject: [PATCH 35/94] /npc info --- .../fancynpcs/commands/npc/InfoCMD.java | 150 ++++++++++++++---- src/main/resources/languages/en.yml | 45 +++++- 2 files changed, 159 insertions(+), 36 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index e5399eb1..2e3265ca 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -1,21 +1,30 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; +import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; +import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; import de.oliver.fancynpcs.commands.Subcommand; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import java.text.DecimalFormat; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class InfoCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); + + private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); + private static final DecimalFormat SECONDS_FORMAT = new DecimalFormat("#,###.#"); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -23,51 +32,122 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } Location loc = npc.getData().getLocation(); - MessageHelper.info(receiver, "NPC: " + npc.getData().getName()); - MessageHelper.info(receiver, " - Id: " + npc.getData().getId()); - MessageHelper.info(receiver, " - Creator: " + npc.getData().getCreator()); - MessageHelper.info(receiver, " - Display name: " + npc.getData().getDisplayName()); - MessageHelper.info(receiver, " - Location: " + loc.getWorld().getName() + " " + loc.getBlockX() + "/" + loc.getBlockY() + "/" + loc.getBlockZ()); - MessageHelper.info(receiver, " - Type: " + npc.getData().getType().name()); - MessageHelper.info(receiver, " - Show in tab: " + npc.getData().isShowInTab()); - MessageHelper.info(receiver, " - Turn to player: " + npc.getData().isTurnToPlayer()); - MessageHelper.info(receiver, " - Is glowing: " + npc.getData().isGlowing()); - MessageHelper.info(receiver, " - Glowing color: " + npc.getData().getGlowingColor().toString()); - MessageHelper.info(receiver, " - Is collidable: " + npc.getData().isCollidable()); - MessageHelper.info(receiver, " - Interaction cooldown: " + npc.getData().getInteractionCooldown() + " seconds"); - MessageHelper.info(receiver, " - Server Command: " + npc.getData().getServerCommand()); + translator.translate("npc_info_general") + .replace("name", npc.getData().getName()) + .replace("id", npc.getData().getId()) + .replace("id_short", npc.getData().getId().substring(0, 13) + "...") + .replace("internal_id", "2") + .replace("creator", npc.getData().getCreator().toString()) + .replace("creator_short", npc.getData().getCreator().toString().substring(0, 13) + "...") + .replace("displayname", npc.getData().getDisplayName()) + .replace("type", "") // Not ideal solution but should work fine for now. + .replace("location_x", COORDS_FORMAT.format(loc.x())) + .replace("location_y", COORDS_FORMAT.format(loc.y())) + .replace("location_z", COORDS_FORMAT.format(loc.z())) + .replace("world", loc.getWorld().getName()) + .replace("is_glowing", getTranslatedBoolean(npc.getData().isGlowing())) + .replace("glowing_color", getFormattedColor(npc.getData().getGlowingColor())) + .replace("is_collidable", getTranslatedBoolean(npc.getData().isCollidable())) + .replace("is_turn_to_player", getTranslatedBoolean(npc.getData().isTurnToPlayer())) + .replace("is_show_in_tab", getTranslatedBoolean(npc.getData().isShowInTab())) + .replace("is_skin_mirror", getTranslatedBoolean(npc.getData().isMirrorSkin())) + .replace("interaction_cooldown", SECONDS_FORMAT.format(npc.getData().getInteractionCooldown()) + "s") + .send(sender); + + if (npc.getData().getServerCommand() != null) { + translator.translate("npc_info_serverCommands_header").send(sender); + translator.translate("npc_info_serverCommands_entry").replace("command", npc.getData().getServerCommand()).send(sender); + translator.translate("npc_info_serverCommands_footer").send(sender); + } if (!npc.getData().getPlayerCommands().isEmpty()) { - MessageHelper.info(receiver, " - Player commands:"); - for (int i = 0; i < npc.getData().getMessages().size(); i++) { - MessageHelper.info(receiver, " " + (i + 1) + ": " + npc.getData().getPlayerCommands().get(i)); - } + translator.translate("npc_info_playerCommands_header").send(sender); + npc.getData().getPlayerCommands().forEach(command -> { + translator.translate("npc_info_playerCommands_entry").replace("command", command).send(sender); + }); + translator.translate("npc_info_playerCommands_footer").send(sender); } if (!npc.getData().getMessages().isEmpty()) { - MessageHelper.info(receiver, " - Messages:"); - for (int i = 0; i < npc.getData().getMessages().size(); i++) { - MessageHelper.info(receiver, " " + (i + 1) + ": " + npc.getData().getMessages().get(i)); - } + translator.translate("npc_info_messages_header").send(sender); + npc.getData().getMessages().forEach(message -> + translator.translate("npc_info_messages_entry").replace("message", message).send(sender) + ); + translator.translate("npc_info_messages_footer").send(sender); } + if (!npc.getData().getEquipment().isEmpty()) { + translator.translate("npc_info_equipment_header").send(sender); + npc.getData().getEquipment().forEach((slot, item) -> { + if (item.getType() == Material.AIR) + return; + translator.translate("npc_info_equipment_entry") + .replace("slot", getTranslatedSlot(slot)) + .addTagResolver(Placeholder.component("item", item.displayName().hoverEvent(item.asHoverEvent()))) + .send(sender); + }); + translator.translate("npc_info_equipment_footer").send(sender); + } - npc.getData().getEquipment().forEach((slot, item) -> - MessageHelper.info(receiver, " - Equipment: " + slot.name() + " -> " + item.getType().name()) - ); + if (!npc.getData().getAttributes().isEmpty()) { + translator.translate("npc_info_attributes_header").send(sender); + npc.getData().getAttributes().forEach((attribute, value) -> + translator.translate("npc_info_attributes_entry").replace("attribute", attribute.getName()).replace("value", value).send(sender) + ); + translator.translate("npc_info_attributes_footer").send(sender); + } + return false; + } + + // NOTE: Might need to be improved later down the line, should get work done for now. + private @NotNull String getTranslatedBoolean(final boolean bool) { + return (bool) ? ((SimpleMessage) translator.translate("true")).getMessage() : ((SimpleMessage) translator.translate("false")).getMessage(); + } - npc.getData().getAttributes().forEach((attribute, value) -> - MessageHelper.info(receiver, " - Attribute: " + attribute.getName() + " -> " + value) - ); + // NOTE: Might need to be improved later down the line, should get work done for now. + private @NotNull String getTranslatedSlot(final @NotNull NpcEquipmentSlot slot) { + return ((SimpleMessage) translator.translate( + switch (slot) { + case MAINHAND -> "main_hand"; + case OFFHAND -> "off_hand"; + case HEAD -> "head"; + case CHEST -> "chest"; + case LEGS -> "legs"; + case FEET -> "feet"; + } + )).getMessage(); + } - return false; + // NOTE: Might need to be improved later down the line, should get work done for now. + private static @NotNull String getFormattedColor(final @NotNull NamedTextColor color) { + final int colorCode = color.value(); + return switch (colorCode) { + case 0 -> "Black"; + case 170 -> "Dark Blue"; + case 43520 -> "Dark Green"; + case 43690 -> "Dark Aqua"; + case 11141120 -> "Dark Red"; + case 11141290 -> "Dark Purple"; + case 16755200 -> "Gold"; + case 11184810 -> "Gray"; + case 5592405 -> "Dark Gray"; + case 5592575 -> "Blue"; + case 5635925 -> "Green"; + case 5636095 -> "Aqua"; + case 16733525 -> "Red"; + case 16733695 -> "Light Purple"; + case 16777045 -> "Yellow"; + case 16777215 -> "White"; + default -> "Unknown"; + }; } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index db5e814c..de0fee14 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -2,7 +2,17 @@ language_name: english # Messages support MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html messages: - # Common + # Common (States) + true: "{successColor}True" + false: "{errorColor}False" + # Common (Equipment Slots) + main_hand: "Main Hand" + off_hand: "Off Hand" + head: "Head" + chest: "Chest" + legs: "Legs" + feet: "Feet" + # Common (Other) interaction_on_cooldown: "" # Commands (Common Replies) command_missing_permissions: "› {errorColor}Insufficient permissions. You cannot use this command." @@ -81,6 +91,39 @@ messages: npc_glowingColor_success: "NPC named {warningColor}{npc} has had their glowing color updated." npc_glowingColor_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." + npc_info_syntax: "Syntax: {primaryColor}/npc info {secondaryColor}(npc)" + npc_info_general: + - "Information about NPC named {primaryColor}{name}:" + - " " + - "Unique, permanent identifier of the NPC.'>Identifier: Click to copy identifier to clipboard.'>{warningColor}{id}" + - "Identifier of player who created this NPC.'>Creator: Click to copy creator to clipboard.'>{warningColor}{creator}" + - "Current location of the NPC.'>Location: Click to copy location to clipboard.'>{warningColor}{location_x}, {warningColor}{location_y}, {warningColor}{location_z} in {warningColor}{world}" + - "Display name of the NPC, displayed above their head.'>Display Name: {displayname}" + - "Entity type of the NPC.'>Type: {warningColor}{type} Glowing state of the NPC. Can be {successColor}true or {errorColor}false.'>Glowing: {is_glowing} Glowing color of the NPC.'>Glowing Color: {warningColor}{glowing_color}" + - "Whether the NPC should be shown in player-list. Can be {successColor}true or {errorColor}false.'>Shown in TAB: {is_show_in_tab} Collidable state of the NPC. Can be {successColor}true or {errorColor}false.'>Collidable: {is_collidable} Whether the NPC should turn to player. Can be {successColor}true or {errorColor}false.'>Turns to Player: {is_turn_to_player}" + - "Skin mirroring state of the NPC.. Can be {successColor}true or {errorColor}false.'>Skin Mirroring: {warningColor}{is_skin_mirror} Interaction cooldown between interactions. In seconds.'>Interaction Cooldown: {warningColor}{interaction_cooldown}" + - " " + + npc_info_messages_header: "Messages:" + npc_info_messages_entry: "{message}" + npc_info_messages_footer: " " + + npc_info_playerCommands_header: "Player Commands:" + npc_info_playerCommands_entry: "{command}" + npc_info_playerCommands_footer: " " + + npc_info_serverCommands_header: "Server Commands:" + npc_info_serverCommands_entry: "{command}" + npc_info_serverCommands_footer: " " + + npc_info_equipment_header: "Equipment:" + npc_info_equipment_entry: "› <#848484>{slot}: {warningColor}" # DEV NOTE: This uses <> brackets because this must be a MiniMessage placeholder (TagResolver). + npc_info_equipment_footer: " " + + npc_info_attributes_header: "Attributes:" + npc_info_attributes_entry: "› <#848484>{attribute}: {warningColor}{value}" + npc_info_attributes_footer: " " + npc_interactionCooldown_syntax: "Syntax: {primaryColor}/npc interactionCooldown {secondaryColor}(npc) (seconds)" npc_interactionCooldown_success: "NPC named {warningColor}{npc} has had their interaction cooldown updated." From 3f591cc4dfb5da023157d47640250526c849a8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:16:43 +0200 Subject: [PATCH 36/94] remove unused placeholders --- src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index 2e3265ca..b33eaa8b 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -43,10 +43,7 @@ public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull St translator.translate("npc_info_general") .replace("name", npc.getData().getName()) .replace("id", npc.getData().getId()) - .replace("id_short", npc.getData().getId().substring(0, 13) + "...") - .replace("internal_id", "2") .replace("creator", npc.getData().getCreator().toString()) - .replace("creator_short", npc.getData().getCreator().toString().substring(0, 13) + "...") .replace("displayname", npc.getData().getDisplayName()) .replace("type", "") // Not ideal solution but should work fine for now. .replace("location_x", COORDS_FORMAT.format(loc.x())) From 9d639340851090d7193089a77d533c3cad9cc359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 9 Apr 2024 20:25:34 +0200 Subject: [PATCH 37/94] /npc turnToPlayer --- .../commands/npc/TurnToPlayerCMD.java | 27 +++++++++---------- src/main/resources/languages/en.yml | 3 +++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java index d5531be9..7ce5264c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java @@ -1,22 +1,22 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class TurnToPlayerCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -30,15 +30,14 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_turnToPlayer_syntax").send(sender); return false; } - if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } @@ -46,24 +45,24 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull try { turnToPlayer = Boolean.parseBoolean(args[2]); } catch (Exception e) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("command_invalid_boolean").replace("input", args[2]).send(sender); return false; } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.TURN_TO_PLAYER, turnToPlayer, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.TURN_TO_PLAYER, turnToPlayer, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { npc.getData().setTurnToPlayer(turnToPlayer); if (turnToPlayer) { - MessageHelper.success(receiver, lang.get("npc-command-turnToPlayer-true", "npc", npc.getData().getName())); + translator.translate("npc_turnToPlayer_set_true").replace("npc", npc.getData().getName()).send(sender); } else { - MessageHelper.success(receiver, lang.get("npc-command-turnToPlayer-false", "npc", npc.getData().getName())); + translator.translate("npc_turnToPlayer_set_false").replace("npc", npc.getData().getName()).send(sender); npc.updateForAll(); // move to default pos } } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index de0fee14..1cabe5cd 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -137,6 +137,9 @@ messages: npc_remove_syntax: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" npc_remove_success: "NPC named {warningColor}{npc} has been removed." + npc_turnToPlayer_syntax: "Syntax: {primaryColor}/npc turnToPlayer {secondaryColor}(npc) (state)" + npc_turnToPlayer_set_true: "NPC named {warningColor}{npc} is now {successColor}turning to player." + npc_turnToPlayer_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}turning to player." npc_showInTab_syntax: "Syntax: {primaryColor}/npc showInTab {secondaryColor}(npc) (state)" npc_showInTab_set_true: "NPC named {warningColor}{npc} is now {successColor}shown in player-list." From 0d20b8fda811b01f4d80009178ab5691091e9254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 9 Apr 2024 20:42:17 +0200 Subject: [PATCH 38/94] /npc teleport --- .../fancynpcs/commands/npc/TeleportCMD.java | 63 ++++++++++++------- src/main/resources/languages/en.yml | 5 +- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java index 79ac9f70..e290c181 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java @@ -1,7 +1,6 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; @@ -12,16 +11,17 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.util.RayTraceResult; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.text.DecimalFormat; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class TeleportCMD implements Subcommand { - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); - private final DecimalFormat DF = new DecimalFormat(".###"); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); + private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); @Override public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { @@ -29,18 +29,18 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No if (args.length == 3) { return List.of(String.valueOf(rayTraceResult != null ? - DF.format(rayTraceResult.getHitPosition().getX()) : - DF.format(player.getLocation().getX())).replace(',', '.') + COORDS_FORMAT.format(rayTraceResult.getHitPosition().getX()) : + COORDS_FORMAT.format(player.getLocation().getX())).replace(',', '.') ); } else if (args.length == 4) { return List.of(String.valueOf(rayTraceResult != null ? - DF.format(rayTraceResult.getHitPosition().getY()) : - DF.format(player.getLocation().getY())).replace(',', '.') + COORDS_FORMAT.format(rayTraceResult.getHitPosition().getY()) : + COORDS_FORMAT.format(player.getLocation().getY())).replace(',', '.') ); } else if (args.length == 5) { return List.of(String.valueOf(rayTraceResult != null ? - DF.format(rayTraceResult.getHitPosition().getZ()) : - DF.format(player.getLocation().getZ())).replace(',', '.') + COORDS_FORMAT.format(rayTraceResult.getHitPosition().getZ()) : + COORDS_FORMAT.format(player.getLocation().getZ())).replace(',', '.') ); } else if (args.length == 6) { return List.of(player.getLocation().getWorld().getName()); @@ -50,26 +50,37 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No } @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { + public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); + translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); return false; } if (args.length < 5) { - MessageHelper.error(receiver, lang.get("wrong-usage")); + translator.translate("npc_teleport_syntax").send(sender); return false; } double x, y, z; - try { + try { // NOTE: Additional try-catch blocks has been added to improve error message, will be improved during commands rework. x = Double.parseDouble(args[2]); + } catch (NumberFormatException e) { + translator.translate("command_invalid_number").replace("input", args[2]).send(sender); + return false; + } + + try { // NOTE: Additional try-catch blocks has been added to improve error message, will be improved during commands rework. y = Double.parseDouble(args[3]); + } catch (NumberFormatException e) { + translator.translate("command_invalid_number").replace("input", args[3]).send(sender); + return false; + } + + try { // NOTE: Additional try-catch blocks has been added to improve error message, will be improved during commands rework. z = Double.parseDouble(args[4]); } catch (NumberFormatException e) { - MessageHelper.error(receiver, "wrong-usage"); - MessageHelper.error(receiver, "could-not-parse-number"); + translator.translate("command_invalid_number").replace("input", args[4]).send(sender); return false; } @@ -77,26 +88,32 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull if (args.length == 6) { world = Bukkit.getWorld(args[5]); - } else if (receiver instanceof Player p) { + } else if (sender instanceof Player p) { world = p.getWorld(); } if (world == null) { - MessageHelper.error(receiver, "world-not-found"); + translator.translate("command_invalid_world").replace("input", args[5]).send(sender); return false; } Location location = new Location(world, x, y, z); - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, receiver); + NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender); npcModifyEvent.callEvent(); if (!npcModifyEvent.isCancelled()) { npc.getData().setLocation(location); npc.updateForAll(); - MessageHelper.success(receiver, lang.get("npc-command-teleport-success")); + translator.translate("command_invalid_world") + .replace("npc", npc.getData().getName()) + .replace("x", COORDS_FORMAT.format(x)) + .replace("y", COORDS_FORMAT.format(x)) + .replace("z", COORDS_FORMAT.format(x)) + .replace("world", world.getName()) + .send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 1cabe5cd..f9f333e2 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -22,7 +22,7 @@ messages: command_invalid_boolean: "› {errorColor}Argument {warningColor}{input}{errorColor} must be either {warningColor}true{errorColor} or {warningColor}false{errorColor}." command_invalid_number: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid number." command_invalid_integer: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid integer." - command_invalid_world: "› {errorColor}World named {warningColor}{npc}{errorColor} does not exist." + command_invalid_world: "› {errorColor}World named {warningColor}{input}{errorColor} does not exist." command_invalid_npc: "› {errorColor}NPC named {warningColor}{npc}{errorColor} does not exist." command_unsupported_npc_type: "This NPC type does not support this feature." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." @@ -137,6 +137,9 @@ messages: npc_remove_syntax: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" npc_remove_success: "NPC named {warningColor}{npc} has been removed." + npc_teleport_syntax: "Syntax: {primaryColor}/npc teleport {secondaryColor}(npc) (x) (y) (z) [world]" + npc_teleport_success: "NPC named {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." + npc_turnToPlayer_syntax: "Syntax: {primaryColor}/npc turnToPlayer {secondaryColor}(npc) (state)" npc_turnToPlayer_set_true: "NPC named {warningColor}{npc} is now {successColor}turning to player." npc_turnToPlayer_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}turning to player." From 3925df79c931e3c247aa2d63901df6148e24ea9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:04:16 +0200 Subject: [PATCH 39/94] cloud commands base --- build.gradle.kts | 6 ++ gradle.properties | 3 +- .../java/de/oliver/fancynpcs/FancyNpcs.java | 4 + .../commands/CloudCommandManager.java | 82 +++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java diff --git a/build.gradle.kts b/build.gradle.kts index bcd73083..a812bf94 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -38,6 +38,9 @@ dependencies { implementation("de.oliver:FancyLib:${findProperty("fancyLibVersion")}") implementation("me.dave:ChatColorHandler:${findProperty("chatcolorhandlerVersion")}") + implementation("org.incendo:cloud-core:${findProperty("cloudVersion")}") + implementation("org.incendo:cloud-paper:${findProperty("cloudVersion")}") + implementation("org.incendo:cloud-annotations:${findProperty("cloudVersion")}") compileOnly("com.intellectualsites.plotsquared:plotsquared-core:${findProperty("plotsquaredVersion")}") } @@ -100,6 +103,9 @@ tasks { // Set the release flag. This configures what version bytecode the compiler will emit, as well as what JDK APIs are usable. // See https://openjdk.java.net/jeps/247 for more information. options.release.set(17) + + // For cloud-annotations, see https://cloud.incendo.org/annotations/#command-components + options.compilerArgs.add("-parameters") } javadoc { diff --git a/gradle.properties b/gradle.properties index 1d42536b..f68b5079 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,5 @@ minecraftVersion=1.20.4 fancyLibVersion=1.0.20 plotsquaredVersion=7.2.0 -chatcolorhandlerVersion=v2.5.3 \ No newline at end of file +chatcolorhandlerVersion=v2.5.3 +cloudVersion=2.0.0-beta.4 \ No newline at end of file diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index 58cdfa48..434429d6 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -20,6 +20,7 @@ import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.NpcData; import de.oliver.fancynpcs.api.NpcManager; +import de.oliver.fancynpcs.commands.CloudCommandManager; import de.oliver.fancynpcs.commands.FancyNpcsCMD; import de.oliver.fancynpcs.commands.npc.NpcCMD; import de.oliver.fancynpcs.listeners.PlayerChangedWorldListener; @@ -232,6 +233,9 @@ public void onEnable() { if (config.isEnableAutoSave() && config.getAutoSaveInterval() > 0) { scheduler.runTaskTimerAsynchronously(60L * 20L, autosaveInterval * 60L * 20L, () -> npcManager.saveNpcs(false)); } + // Creating new instance of CloudCommandManager and registering commands. + final CloudCommandManager cloud = new CloudCommandManager(this, true).registerCommands(); + } @Override diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java new file mode 100644 index 00000000..a4053e36 --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -0,0 +1,82 @@ +package de.oliver.fancynpcs.commands; + +import de.oliver.fancynpcs.FancyNpcs; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.AnnotationParser; +import org.incendo.cloud.bukkit.CloudBukkitCapabilities; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.paper.PaperCommandManager; +import org.incendo.cloud.paper.parser.KeyedWorldParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.jetbrains.annotations.NotNull; + +public final class CloudCommandManager { + + private final @NotNull FancyNpcs plugin; + + private final @NotNull PaperCommandManager commandManager; + private final @NotNull AnnotationParser annotationParser; + + private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); + + // NOTE: We may provide configuration option for brigadier, hence why it's parameter here. Subject to change. + public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrigadier) { + this.plugin = plugin; + // Creating instance of Cloud's PaperCommandManager, which is used for anything command-related. + this.commandManager = PaperCommandManager.createNative(plugin, ExecutionCoordinator.simpleCoordinator()); + // Registering Brigadier, if available: + if (isBrigadier && commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { + commandManager.registerBrigadier(); + } + // Creating instance of AnnotationParser, which is used for parsing and registering commands. + this.annotationParser = new AnnotationParser<>(commandManager, CommandSender.class); + // Registering parsers and suggestion providers. + commandManager.parserRegistry().registerNamedParser("keyedWorld", KeyedWorldParser.keyedWorldParser()); + commandManager.parserRegistry().registerSuggestionProvider("keyedWorld", KEYED_WORLD_SUGGESTIONS); + commandManager.parserRegistry().registerSuggestionProvider("contextAwareLocation", RELATIVE_COORDS_SUGGESTION); + } + + /** + * Registers plugin commands to the {@link PaperCommandManager}. + */ + public @NotNull CloudCommandManager registerCommands() { + // TO-DO + + return this; + } + + // Copied from KeyedWorldParser because otherwise suggestions wouldn't work. (bug?) + private static final SuggestionProvider KEYED_WORLD_SUGGESTIONS = (context, input) -> { + final List worlds = Bukkit.getWorlds(); + final List completions = new ArrayList<>(worlds.size() * 2); + for (final World world : worlds) { + final NamespacedKey key = world.getKey(); + if (input.hasRemainingInput() && key.getNamespace().equals(NamespacedKey.MINECRAFT_NAMESPACE)) { + completions.add(Suggestion.suggestion(key.getKey())); + } + completions.add(Suggestion.suggestion(key.getNamespace() + ':' + key.getKey())); + } + return CompletableFuture.completedFuture(completions); + }; + + private static final SuggestionProvider RELATIVE_COORDS_SUGGESTION = (context, input) -> { + if (context.sender() instanceof Player sender) { + // TO-DO + } + // Console should not get any completions. + return CompletableFuture.completedFuture(Collections.emptyList()); + }; + +} From 6c449c01334aef1ae0d5e0e5a9988ade08bfce26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 28 Apr 2024 21:54:20 +0200 Subject: [PATCH 40/94] port majority of commands --- gradle.properties | 4 +- .../java/de/oliver/fancynpcs/FancyNpcs.java | 18 +- .../commands/CloudCommandManager.java | 113 ++++--- .../commands/arguments/NpcArgument.java | 53 ++++ .../arguments/NpcAttributeArgument.java | 46 +++ .../exceptions/ReplyingParseException.java | 21 ++ .../fancynpcs/commands/npc/AttributeCMD.java | 121 +++----- .../fancynpcs/commands/npc/CollidableCMD.java | 70 ++--- .../fancynpcs/commands/npc/CopyCMD.java | 60 ++-- .../fancynpcs/commands/npc/CreateCMD.java | 82 +++--- .../commands/npc/DisplayNameCMD.java | 67 ++--- .../fancynpcs/commands/npc/EquipmentCMD.java | 72 ++--- .../oliver/fancynpcs/commands/npc/FixCMD.java | 33 +-- .../fancynpcs/commands/npc/GlowingCMD.java | 126 +++++--- .../commands/npc/GlowingColorCMD.java | 64 ---- .../fancynpcs/commands/npc/InfoCMD.java | 29 +- .../commands/npc/InteractionCooldownCMD.java | 53 +--- .../fancynpcs/commands/npc/ListCMD.java | 102 +++++-- .../fancynpcs/commands/npc/MirrorSkinCMD.java | 69 ----- .../fancynpcs/commands/npc/MoveHereCMD.java | 52 ++-- .../oliver/fancynpcs/commands/npc/NpcCMD.java | 276 +++--------------- .../fancynpcs/commands/npc/RemoveCMD.java | 36 +-- .../fancynpcs/commands/npc/ShowInTabCMD.java | 85 ++---- .../fancynpcs/commands/npc/SkinCMD.java | 170 +++++++---- .../fancynpcs/commands/npc/TeleportCMD.java | 105 +------ .../commands/npc/TurnToPlayerCMD.java | 75 ++--- .../fancynpcs/commands/npc/TypeCMD.java | 64 ++-- src/main/resources/languages/en.yml | 68 +++-- 28 files changed, 874 insertions(+), 1260 deletions(-) create mode 100644 src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java create mode 100644 src/main/java/de/oliver/fancynpcs/commands/arguments/NpcAttributeArgument.java create mode 100644 src/main/java/de/oliver/fancynpcs/commands/exceptions/ReplyingParseException.java delete mode 100644 src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java delete mode 100644 src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java diff --git a/gradle.properties b/gradle.properties index f68b5079..84e4bb4e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ minecraftVersion=1.20.4 -fancyLibVersion=1.0.20 +fancyLibVersion=1.0.21 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 -cloudVersion=2.0.0-beta.4 \ No newline at end of file +cloudVersion=2.0.0-beta.5 \ No newline at end of file diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index 434429d6..d63cd8dd 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -22,7 +22,6 @@ import de.oliver.fancynpcs.api.NpcManager; import de.oliver.fancynpcs.commands.CloudCommandManager; import de.oliver.fancynpcs.commands.FancyNpcsCMD; -import de.oliver.fancynpcs.commands.npc.NpcCMD; import de.oliver.fancynpcs.listeners.PlayerChangedWorldListener; import de.oliver.fancynpcs.listeners.PlayerJoinListener; import de.oliver.fancynpcs.listeners.PlayerNpcsListener; @@ -39,15 +38,12 @@ import de.oliver.fancynpcs.v1_20_4.Npc_1_20_4; import org.apache.maven.artifact.versioning.ComparableVersion; import org.bukkit.Bukkit; -import org.bukkit.command.Command; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; -import java.util.Arrays; -import java.util.Collection; import java.util.function.Function; public class FancyNpcs extends JavaPlugin implements FancyNpcsPlugin { @@ -192,14 +188,7 @@ public void onEnable() { PluginManager pluginManager = Bukkit.getPluginManager(); usingPlotSquared = pluginManager.isPluginEnabled("PlotSquared"); - // register commands - final Collection commands = Arrays.asList(new FancyNpcsCMD(), new NpcCMD()); - if (config.isRegisterCommands()) { - commands.forEach(command -> getServer().getCommandMap().register("fancynpcs", command)); - } else { - commands.stream().filter(Command::isRegistered).forEach(command -> - command.unregister(getServer().getCommandMap())); - } + this.getServer().getCommandMap().register("fancynpcs", new FancyNpcsCMD()); // register listeners pluginManager.registerEvents(new PlayerJoinListener(), instance); @@ -234,8 +223,9 @@ public void onEnable() { scheduler.runTaskTimerAsynchronously(60L * 20L, autosaveInterval * 60L * 20L, () -> npcManager.saveNpcs(false)); } // Creating new instance of CloudCommandManager and registering commands. - final CloudCommandManager cloud = new CloudCommandManager(this, true).registerCommands(); - + // NOTE: Brigadier is a bit bugged currently, should be disabled by default for the time being. + // + final CloudCommandManager cloud = new CloudCommandManager(this, false).registerCommands(); } @Override diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index a4053e36..9d952896 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -1,27 +1,45 @@ package de.oliver.fancynpcs.commands; import de.oliver.fancynpcs.FancyNpcs; -import org.bukkit.Bukkit; -import org.bukkit.NamespacedKey; -import org.bukkit.World; +import de.oliver.fancynpcs.commands.arguments.NpcArgument; +import de.oliver.fancynpcs.commands.arguments.NpcAttributeArgument; +import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; +import de.oliver.fancynpcs.commands.npc.AttributeCMD; +import de.oliver.fancynpcs.commands.npc.CollidableCMD; +import de.oliver.fancynpcs.commands.npc.CreateCMD; +import de.oliver.fancynpcs.commands.npc.DisplayNameCMD; +import de.oliver.fancynpcs.commands.npc.EquipmentCMD; +import de.oliver.fancynpcs.commands.npc.FixCMD; +import de.oliver.fancynpcs.commands.npc.GlowingCMD; +import de.oliver.fancynpcs.commands.npc.InfoCMD; +import de.oliver.fancynpcs.commands.npc.InteractionCooldownCMD; +import de.oliver.fancynpcs.commands.npc.ListCMD; +import de.oliver.fancynpcs.commands.npc.MoveHereCMD; +import de.oliver.fancynpcs.commands.npc.NpcCMD; +import de.oliver.fancynpcs.commands.npc.RemoveCMD; +import de.oliver.fancynpcs.commands.npc.ShowInTabCMD; +import de.oliver.fancynpcs.commands.npc.SkinCMD; +import de.oliver.fancynpcs.commands.npc.TeleportCMD; +import de.oliver.fancynpcs.commands.npc.TurnToPlayerCMD; +import de.oliver.fancynpcs.commands.npc.TypeCMD; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import org.incendo.cloud.annotations.AnnotationParser; import org.incendo.cloud.bukkit.CloudBukkitCapabilities; +import org.incendo.cloud.exception.ArgumentParseException; import org.incendo.cloud.execution.ExecutionCoordinator; import org.incendo.cloud.paper.PaperCommandManager; -import org.incendo.cloud.paper.parser.KeyedWorldParser; -import org.incendo.cloud.suggestion.Suggestion; -import org.incendo.cloud.suggestion.SuggestionProvider; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; import org.jetbrains.annotations.NotNull; +import static org.incendo.cloud.exception.handling.ExceptionHandler.unwrappingHandler; + +// DEV NOTES: +// - Location suggestions might behave a bit weird, writing custom provider doesn't work either. +// I'm fairly sure Cloud developers are aware of that issue and they'll fix it soon. +// - For the time being, due to the reasons below, Brigadier integration should be OFF by default: +// a) Argument pop-ups don't work properly, they don't appear most of the time. +// b) Suggestions are supplied per-whitespace, and not per-argument. +// c) Location suggestions might also behave a bit weird, similarly as with Brigadier disabled. public final class CloudCommandManager { private final @NotNull FancyNpcs plugin; @@ -29,54 +47,65 @@ public final class CloudCommandManager { private final @NotNull PaperCommandManager commandManager; private final @NotNull AnnotationParser annotationParser; - private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); - - // NOTE: We may provide configuration option for brigadier, hence why it's parameter here. Subject to change. public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrigadier) { this.plugin = plugin; // Creating instance of Cloud's PaperCommandManager, which is used for anything command-related. this.commandManager = PaperCommandManager.createNative(plugin, ExecutionCoordinator.simpleCoordinator()); - // Registering Brigadier, if available: + // Registering Brigadier, if available. if (isBrigadier && commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { commandManager.registerBrigadier(); } // Creating instance of AnnotationParser, which is used for parsing and registering commands. this.annotationParser = new AnnotationParser<>(commandManager, CommandSender.class); // Registering parsers and suggestion providers. - commandManager.parserRegistry().registerNamedParser("keyedWorld", KeyedWorldParser.keyedWorldParser()); - commandManager.parserRegistry().registerSuggestionProvider("keyedWorld", KEYED_WORLD_SUGGESTIONS); - commandManager.parserRegistry().registerSuggestionProvider("contextAwareLocation", RELATIVE_COORDS_SUGGESTION); + annotationParser.parse(NpcArgument.INSTANCE); + annotationParser.parse(NpcAttributeArgument.INSTANCE); + // Registering exception handlers. + commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(ReplyingParseException.class)); + commandManager.exceptionController().registerHandler(ReplyingParseException.class, context -> context.exception().runnable().run()); } /** * Registers plugin commands to the {@link PaperCommandManager}. */ public @NotNull CloudCommandManager registerCommands() { - // TO-DO - + annotationParser.parse(AttributeCMD.INSTANCE); + annotationParser.parse(CollidableCMD.INSTANCE); + annotationParser.parse(CreateCMD.INSTANCE); + annotationParser.parse(DisplayNameCMD.INSTANCE); + annotationParser.parse(EquipmentCMD.INSTANCE); + annotationParser.parse(FixCMD.INSTANCE); + annotationParser.parse(GlowingCMD.INSTANCE); + annotationParser.parse(InfoCMD.INSTANCE); + annotationParser.parse(InteractionCooldownCMD.INSTANCE); + annotationParser.parse(ListCMD.INSTANCE); + // annotationParser.parse(MessageCMD.INSTANCE); + // annotationParser.parse(ServerCommandCMD.INSTANCE); + // annotationParser.parse(PlayerCommandCMD.INSTANCE); + annotationParser.parse(MoveHereCMD.INSTANCE); + annotationParser.parse(NpcCMD.INSTANCE); + annotationParser.parse(TurnToPlayerCMD.INSTANCE); + annotationParser.parse(ShowInTabCMD.INSTANCE); + annotationParser.parse(TypeCMD.INSTANCE); + annotationParser.parse(RemoveCMD.INSTANCE); + annotationParser.parse(SkinCMD.INSTANCE); + annotationParser.parse(TeleportCMD.INSTANCE); + // Returning this instance of CloudCommandManager to keep "builder-like" flow. return this; } - // Copied from KeyedWorldParser because otherwise suggestions wouldn't work. (bug?) - private static final SuggestionProvider KEYED_WORLD_SUGGESTIONS = (context, input) -> { - final List worlds = Bukkit.getWorlds(); - final List completions = new ArrayList<>(worlds.size() * 2); - for (final World world : worlds) { - final NamespacedKey key = world.getKey(); - if (input.hasRemainingInput() && key.getNamespace().equals(NamespacedKey.MINECRAFT_NAMESPACE)) { - completions.add(Suggestion.suggestion(key.getKey())); - } - completions.add(Suggestion.suggestion(key.getNamespace() + ':' + key.getKey())); - } - return CompletableFuture.completedFuture(completions); - }; + /** + * Returns the internal {@link PaperCommandManager} associated with this instance of {@link CloudCommandManager}. + */ + public @NotNull PaperCommandManager getCommandManager() { + return commandManager; + } - private static final SuggestionProvider RELATIVE_COORDS_SUGGESTION = (context, input) -> { - if (context.sender() instanceof Player sender) { - // TO-DO - } - // Console should not get any completions. - return CompletableFuture.completedFuture(Collections.emptyList()); - }; + /** + * Returns the internal {@link AnnotationParser} associated with this instance of {@link CloudCommandManager}. + */ + public @NotNull AnnotationParser getAnnotationParser() { + return annotationParser; + } } diff --git a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java new file mode 100644 index 00000000..4b4046ab --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java @@ -0,0 +1,53 @@ +package de.oliver.fancynpcs.commands.arguments; + +import de.oliver.fancylib.translations.Translator; +import de.oliver.fancynpcs.FancyNpcs; +import de.oliver.fancynpcs.api.Npc; +import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.checkerframework.checker.units.qual.C; +import org.incendo.cloud.annotations.parser.Parser; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; + +import java.util.List; + +import org.jetbrains.annotations.NotNull; + +public enum NpcArgument { + INSTANCE; // SINGLETON + + private final Translator translator = FancyNpcs.getInstance().getTranslator(); + + @Parser(suggestions = "npc") + public @NotNull Npc parse(final CommandContext context, final CommandInput input) { + // Reading next argument as single/literal String. + final String value = input.readString(); + // Getting the NPC from the manager. + final Npc npc = FancyNpcs.getInstance().getNpcManager().getNpc(value); + // Throwing exception if NPC does not exist. + if (npc == null) + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replace("input", value).send(context.sender())); + // Throwing exception if PLAYER NPCS FLAG is enabled and sender (player) is not creator of the specified NPC. + if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && context.sender() instanceof Player sender && !npc.getData().getCreator().equals(sender.getUniqueId())) + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replace("input", value).send(context.sender())); + // Returning... + return npc; + } + + @Suggestions("npc") // NOTE: Consider caching, might not be necessary but should be kept in mind. + public List suggestions(final CommandContext context, final CommandInput input) { + return (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && context.sender() instanceof Player sender) + // PLAYER NPCS FLAG is enabled and sender is player; Filtering NPCs and showing only those that are created by the sender. + ? FancyNpcs.getInstance().getNpcManager().getAllNpcs().stream() + .filter(npc -> npc.getData().getCreator().equals(sender.getUniqueId())) + .map(npc -> npc.getData().getName()) + .sorted() + .toList() + // PLAYER NPCS FLAG is disabled or sender is console; Showing all NPCs. + : FancyNpcs.getInstance().getNpcManager().getAllNpcs().stream().map(npc -> npc.getData().getName()).sorted().toList(); + } + +} diff --git a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcAttributeArgument.java b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcAttributeArgument.java new file mode 100644 index 00000000..2527b4f5 --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcAttributeArgument.java @@ -0,0 +1,46 @@ +package de.oliver.fancynpcs.commands.arguments; + +import de.oliver.fancylib.translations.Translator; +import de.oliver.fancynpcs.FancyNpcs; +import de.oliver.fancynpcs.api.AttributeManager; +import de.oliver.fancynpcs.api.Npc; +import de.oliver.fancynpcs.api.NpcAttribute; +import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; +import org.bukkit.command.CommandSender; +import org.incendo.cloud.annotations.parser.Parser; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; + +import java.util.List; + +public enum NpcAttributeArgument { + INSTANCE; // SINGLETON + + private final Translator translator = FancyNpcs.getInstance().getTranslator(); + private final AttributeManager attributeManager = FancyNpcs.getInstance().getAttributeManager(); + + @Parser(suggestions = "attribute") + public NpcAttribute parser(final CommandContext context, final CommandInput input) { + // Getting npc argument that already should exist within the command context. + final Npc npc = context.get("npc"); + // Reading the string, which is supposed to be an attribute name. + final String value = input.readString(); + // Getting the NpcAttribute from the name and npc type. + final NpcAttribute attribute = attributeManager.getAttributeByName(npc.getData().getType(), value); + // Throwing exception when non-existent attribute has been provided. + if (attribute == null) + throw ReplyingParseException.replying(() -> translator.translate("npc_attribute_invalid_for_this_entity_type").send(context.sender())); + // Otherwise, returning the attribute from the parser. + return attribute; + } + + @Suggestions("attribute") + public List suggestions(final CommandContext context, final CommandInput input) { + // Getting npc argument that already should exist within the command context. + final Npc npc = context.getOrDefault("npc", null); + // Mapping and returning list of suggestions. + return attributeManager.getAllAttributesForEntityType(npc.getData().getType()).stream().map(NpcAttribute::getName).toList(); + } + +} diff --git a/src/main/java/de/oliver/fancynpcs/commands/exceptions/ReplyingParseException.java b/src/main/java/de/oliver/fancynpcs/commands/exceptions/ReplyingParseException.java new file mode 100644 index 00000000..79452da0 --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/commands/exceptions/ReplyingParseException.java @@ -0,0 +1,21 @@ +package de.oliver.fancynpcs.commands.exceptions; + +import org.jetbrains.annotations.NotNull; + +public final class ReplyingParseException extends RuntimeException { + + private final @NotNull Runnable runnable; + + private ReplyingParseException(final @NotNull Runnable runnable) { + this.runnable = runnable; + } + + public static ReplyingParseException replying(final Runnable runnable) { + return new ReplyingParseException(runnable); + } + + public @NotNull Runnable runnable() { + return runnable; + } + +} diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java index f4d433a0..0a1491bc 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java @@ -6,99 +6,54 @@ import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.NpcAttribute; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - +import org.incendo.cloud.annotations.Argument; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; + +import java.util.Collections; import java.util.List; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class AttributeCMD implements Subcommand { +public enum AttributeCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); private final AttributeManagerImpl attributeManager = FancyNpcs.getInstance().getAttributeManager(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (npc == null) { - return null; - } - - if (args.length == 3) { - List attributes = attributeManager.getAllAttributesForEntityType(npc.getData().getType()); - - return attributes.stream() - .map(NpcAttribute::getName) - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - if (args.length == 4) { - String attributeName = args[2]; - NpcAttribute attribute = attributeManager.getAttributeByName(npc.getData().getType(), attributeName); - if (attribute == null) { - return null; - } - - return attribute.getPossibleValues().stream() - .filter(input -> input.toLowerCase().startsWith(args[3].toLowerCase())) - .toList(); - } - - return null; + @Suggestions("attribute_value") + public List attributeValueSuggestions(final CommandContext context, final CommandInput input) { + final Npc npc = context.getOrDefault("npc", null); + final NpcAttribute attribute = context.getOrDefault("attribute", null); + // ... + if (attribute != null && npc != null) + return attributeManager.getAttributeByName(npc.getData().getType(), attribute.getName()).getPossibleValues(); + // ... + return Collections.emptyList(); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - if (args.length < 4) { - translator.translate("npc_attribute_syntax").send(sender); - return false; - } - - String attributeName = args[2].toLowerCase(); // note: forced lower-case for better command output - String value = ""; - - for (int i = 3; i < args.length; i++) { - value += args[i] + " "; - } - value = value.substring(0, value.length() - 1); - - NpcAttribute attribute = attributeManager.getAttributeByName(npc.getData().getType(), attributeName); - if (attribute == null) { - translator.translate("npc_attribute_invalid_attribute").replace("input", attributeName).send(sender); - return false; - } - - if (!attribute.getTypes().contains(npc.getData().getType())) { - translator.translate("npc_attribute_invalid_entity_type").replace("input", attributeName).send(sender); - return false; - } - - if (!attribute.isValidValue(value)) { - translator.translate("npc_attribute_invalid_attribute_value").replace("input", value).send(sender); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.ATTRIBUTE, new Object[]{attribute, value}, sender); - npcModifyEvent.callEvent(); - - if (npcModifyEvent.isCancelled()) { + @Command("npc attribute ") + @Permission("fancynpcs.command.npc.attribute") + public void onCommand( + final CommandSender sender, + final Npc npc, + final NpcAttribute attribute, + final @Argument(suggestions = "attribute_value") String attributeValue + ) { + if (!attribute.isValidValue(attributeValue)) { + translator.translate("npc_attribute_invalid_attribute_value").replace("input", attributeValue).send(sender); + return; + } + // ... + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.ATTRIBUTE, new Object[]{attribute, attributeValue}, sender).callEvent()) { + npc.getData().addAttribute(attribute, attributeValue); + npc.updateForAll(); + translator.translate("npc_attribute_set").replace("attribute", attribute.getName()).replace("value", attributeValue.toLowerCase()).send(sender); + } else { translator.translate("command_npc_modification_cancelled").send(sender); - return false; } - - npc.getData().addAttribute(attribute, value); - npc.updateForAll(); - - translator.translate("npc_attribute_set").replace("attribute", attributeName).replace("value", value).send(sender); - - return false; } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java index 4e93c7e1..817bcf74 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java @@ -4,62 +4,38 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.List; -import java.util.stream.Stream; - -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class CollidableCMD implements Subcommand { +public enum CollidableCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Stream.of("true", "false") - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - return null; + @Command("npc collidable") + @Permission("fancynpcs.command.npc.collidable") + public void onDefault(final CommandSender sender) { + translator.translate("npc_collidable_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - translator.translate("npc_collidable_syntax").send(sender); - return false; - } - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - boolean collidable; - try { - collidable = Boolean.parseBoolean(args[2]); - } catch (Exception e) { - translator.translate("command_invalid_boolean").replace("input", args[2]).send(sender); - return false; + @Command("npc collidable [state]") + @Permission("fancynpcs.command.npc.collidable") + public void onCommand(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + final boolean finalState = (state == null) ? !npc.getData().isCollidable() : state; + // Calling the event and updating the state if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.COLLIDABLE, finalState, sender).callEvent()) { + // Updating the state. + npc.getData().setCollidable(finalState); + // Sending message to the sender. + translator.translate(finalState ? "npc_collidable_set_true" : "npc_collidable_set_false").replace("npc", npc.getData().getName()).send(sender); + // Returning from the command block. + return; } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.COLLIDABLE, collidable, sender); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().setCollidable(collidable); - npc.updateForAll(); - translator.translate(collidable ? "npc_collidable_set_true" : "npc_collidable_set_false").replace("npc", npc.getData().getName()).send(sender); - } else { - translator.translate("command_npc_modification_cancelled").send(sender); - } - - return true; + // Otherwise, sending error message to the sender. + translator.translate("command_npc_modification_cancelled").send(sender); } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java index a2b116a9..41fb8d91 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java @@ -5,52 +5,37 @@ import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.NpcData; import de.oliver.fancynpcs.api.events.NpcCreateEvent; -import de.oliver.fancynpcs.commands.Subcommand; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.Regex; -import java.util.List; import java.util.UUID; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class CopyCMD implements Subcommand { +// TO-DO: Console support with --position and --world parameter flags. +public enum CopyCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; + @Command(value = "npc copy", requiredSender = Player.class) + @Permission("fancynpcs.command.npc.copy") + public void onDefault(final Player sender) { + translator.translate("npc_copy_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - translator.translate("command_player_only").send(sender); - return false; - } - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - if (args.length < 3) { - translator.translate("npc_copy_syntax").send(sender); - return false; - } - - String newName = args[2]; - - Npc copied = FancyNpcs.getInstance().getNpcAdapter().apply( + @Command(value = "npc copy ", requiredSender = Player.class) + @Permission("fancynpcs.command.npc.copy") + public void onCommand(final Player sender, final Npc npc, final @Regex("^[^.]*$") String name) { + // Copying the NPC. + final Npc copied = FancyNpcs.getInstance().getNpcAdapter().apply( new NpcData( UUID.randomUUID().toString(), - newName, - player.getUniqueId(), + name, + sender.getUniqueId(), npc.getData().getDisplayName(), npc.getData().getSkin(), - player.getLocation(), + sender.getLocation(), npc.getData().isShowInTab(), npc.getData().isSpawnEntity(), npc.getData().isCollidable(), @@ -68,19 +53,14 @@ public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull St npc.getData().getAttributes(), npc.getData().isMirrorSkin() )); - - NpcCreateEvent npcCreateEvent = new NpcCreateEvent(copied, player); - npcCreateEvent.callEvent(); - if (!npcCreateEvent.isCancelled()) { + // Calling the event and creating + registering copied NPC if not cancelled. + if (new NpcCreateEvent(copied, sender).callEvent()) { copied.create(); FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(copied); copied.spawnForAll(); - translator.translate("npc_command_copy_success").replace("npc", npc.getData().getName()).replace("new_npc", copied.getData().getName()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index 343085f3..edc646f1 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -5,65 +5,61 @@ import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.NpcData; import de.oliver.fancynpcs.api.events.NpcCreateEvent; -import de.oliver.fancynpcs.commands.Subcommand; +import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.command.CommandSender; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Default; +import org.incendo.cloud.annotations.Flag; +import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.Regex; -import java.util.List; +import java.util.UUID; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class CreateCMD implements Subcommand { +public enum CreateCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; - } - - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - translator.translate("command_player_only").send(sender); - return false; + @Command("npc create ") + @Permission("fancynpcs.command.npc.create") + public void onCreateCommand(final @NotNull CommandSender sender, + final @NotNull @Regex("^[^.]*$") String name, + final @Nullable @Flag("type") @Default("player") EntityType type, + final @Nullable @Flag(value = "position") Location position, + final @Nullable @Flag(value = "world") World world + ) { + if (FancyNpcs.getInstance().getNpcManager().getNpc(name) != null) { + translator.translate("npc_create_failure_already_exists").replace("npc", FancyNpcs.getInstance().getNpcManager().getNpc(name).getData().getName()).send(sender); + return; } - - String name = args[1]; - - if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled()) { - if (FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name, player.getUniqueId()) != null) { - translator.translate("npc_create_failure_already_exists").replace("npc", name).send(sender); - return false; + // Getting the Location where NPC will be created at. + final Location location = (position == null && sender instanceof Player player) ? player.getLocation() : position; + // Setting the world of specified location. + if (location.getWorld() == null) { + if (world == null) { + sender.sendMessage("must specify world"); + return; } - } else { - if (FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name) != null) { - translator.translate("npc_create_failure_already_exists").replace("npc", name).send(sender); - return false; - } - } - - - if (name.contains(".")) { - name = name.replace('.', '_'); + location.setWorld(world); } - - Npc createdNpc = FancyNpcs.getInstance().getNpcAdapter().apply(new NpcData(name, player.getUniqueId(), player.getLocation())); - createdNpc.getData().setLocation(player.getLocation()); - - NpcCreateEvent npcCreateEvent = new NpcCreateEvent(createdNpc, player); - npcCreateEvent.callEvent(); - if (!npcCreateEvent.isCancelled()) { - createdNpc.create(); - FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(createdNpc); - createdNpc.spawnForAll(); - + final Npc npc = FancyNpcs.getInstance().getNpcAdapter().apply(new NpcData(name, (sender instanceof Player player) ? player.getUniqueId() : UUID.nameUUIDFromBytes(new byte[0]), location)); + // Setting the type of NPC. Default type is EntityType.PLAYER. + npc.getData().setType(type); // TO-DO: FIX IT + // Calling event and creating NPC if not cancelled, sending error message otherwise. + if (new NpcCreateEvent(npc, sender).callEvent()) { + npc.create(); + FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(npc); + npc.spawnForAll(); translator.translate("npc_create_success").replace("npc", name).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java index e2ed88c2..fb812ae8 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java @@ -4,59 +4,46 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.incendo.cloud.annotation.specifier.Greedy; +import org.incendo.cloud.annotations.Argument; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; import java.util.List; -import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class DisplayNameCMD implements Subcommand { +public enum DisplayNameCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Stream.of("") - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - return null; - } - - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - translator.translate("npc_displayname_syntax").send(sender); - return false; - } - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } + private static final List SUGGESTIONS = List.of(""); - String displayName = ""; - for (int i = 2; i < args.length; i++) { - displayName += args[i] + " "; - } - displayName = displayName.substring(0, displayName.length() - 1); + @Suggestions("empty") + public List suggestions(final CommandContext sender, CommandInput input) { + return SUGGESTIONS; + } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.DISPLAY_NAME, displayName, sender); - npcModifyEvent.callEvent(); + @Command("npc displayname") + @Permission("fancynpcs.command.npc.displayname") + public void onDefault(final CommandSender sender) { + translator.translate("npc_displayname_syntax").send(sender); + } - if (!npcModifyEvent.isCancelled()) { - npc.getData().setDisplayName(displayName.toString()); + @Command("npc displayname ") + @Permission("fancynpcs.command.npc.displayname") + public void onCommand(final CommandSender sender, final Npc npc, final @Argument(suggestions = "empty") @Greedy String name) { + // Calling the event and updating the state if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.DISPLAY_NAME, name, sender).callEvent()) { + npc.getData().setDisplayName(name); npc.updateForAll(); - translator.translate("npc_displayname_success").replace("npc", args[1]).send(sender); + translator.translate("npc_displayname_success").replace("npc", npc.getData().getName()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java index 402c1de2..fdf82bd0 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java @@ -1,76 +1,40 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; -import de.oliver.fancynpcs.commands.Subcommand; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.Arrays; -import java.util.List; - -public class EquipmentCMD implements Subcommand { +public enum EquipmentCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Arrays.stream(NpcEquipmentSlot.values()) - .map(Enum::name) - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - return null; + @Command(value = "npc equipment", requiredSender = Player.class) + @Permission("fancynpcs.command.npc.equipment") + public void onDefault(final Player sender) { + translator.translate("npc_equipment_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - translator.translate("command_player_only").send(sender); - return false; - } - - if (args.length < 3) { - translator.translate("npc_equipment_syntax").send(sender); - return false; - } - - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - String slot = args[2]; - - NpcEquipmentSlot equipmentSlot = NpcEquipmentSlot.parse(slot); - if (equipmentSlot == null) { - translator.translate("npc_equipment_failure_invalid_slot").replace("input", slot).send(sender); - return false; - } - - ItemStack item = player.getInventory().getItemInMainHand().clone(); - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.EQUIPMENT, new Object[]{equipmentSlot, item}, sender); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().addEquipment(equipmentSlot, item); + @Command(value = "npc equipment ", requiredSender = Player.class) + @Permission("fancynpcs.command.npc.equipment") + // NOTE: NpcEquipmentSlot and potentially other enums could use their own parser to keep the error message (somewhat) accurate. + public void onCommand(final Player sender, final Npc npc, final NpcEquipmentSlot slot) { + // Getting item player has currently in hand. + final ItemStack item = sender.getInventory().getItemInMainHand().clone(); + // Calling the event and updating equipment if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.EQUIPMENT, new Object[]{slot, item}, sender).callEvent()) { + npc.getData().addEquipment(slot, item); npc.updateForAll(); translator.translate("npc_equipment_success").replace("npc", npc.getData().getName()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java index 780eb712..42387a7a 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java @@ -1,40 +1,31 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.List; - -public class FixCMD implements Subcommand { +public enum FixCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; + @Command("npc fix") + @Permission("fancynpcs.command.npc.fix") + public void onDefault(final CommandSender sender) { + translator.translate("npc_fix_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - + @Command("npc fix ") + @Permission("fancynpcs.command.npc.fix") + public void onCommand(final CommandSender sender, final Npc npc) { npc.removeForAll(); npc.create(); Bukkit.getOnlinePlayers().forEach(npc::checkAndUpdateVisibility); - translator.translate("npc_fix_success").replace("npc", npc.getData().getName()).send(sender); - return true; } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java index d002035d..b1d77eb8 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java @@ -1,66 +1,112 @@ package de.oliver.fancynpcs.commands.npc; import de.oliver.fancylib.translations.Translator; +import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.List; -import java.util.stream.Stream; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class GlowingCMD implements Subcommand { +public enum GlowingCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Stream.of("true", "false") - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - return null; + @Command("npc glowing") + @Permission("fancynpcs.command.npc.glowing") + public void onDefault(final CommandSender sender) { + translator.translate("npc_glowing_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - translator.translate("npc_glowing_syntax").send(sender); - return false; + @Command("npc glowing [color]") + @Permission("fancynpcs.command.npc.glowing") + public void onCommand(final CommandSender sender, final Npc npc, final @Nullable GlowingColor color) { + // Handling 'toggle' state. + if (color == null) { + // Inverting the current glowing state, so it works like a toggle. + final boolean isGlowingToggled = !npc.getData().isGlowing(); + // Calling the event and updating the state if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, isGlowingToggled, sender).callEvent()) { + npc.getData().setGlowing(isGlowingToggled); + npc.updateForAll(); + translator.translate(isGlowingToggled ? "npc_glowing_set_true" : "npc_glowing_set_false").replace("npc", npc.getData().getName()).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + } + // Handling 'disabled' state. + else if (color == GlowingColor.DISABLED) { + // Calling the event and updating the state if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, false, sender).callEvent()) { + npc.getData().setGlowing(false); + npc.updateForAll(); + translator.translate("npc_glowing_set_false").replace("npc", npc.getData().getName()).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + // Handling 'color' state, which means enabling glowing and changing the color to desired one. + } else if (npc.getData().isGlowing() || new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, true, sender).callEvent()) { + // Updating the glowing state, if previously disabled. + if (!npc.getData().isGlowing()) { + npc.getData().setGlowing(true); + npc.updateForAll(); + } + // Calling the event and updating the glowing color if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING_COLOR, color.getColor(), sender).callEvent()) { + npc.getData().setGlowingColor(color.getColor()); + npc.updateForAll(); + translator.translate("npc_glowing_set_color_success") + .replace("npc", npc.getData().getName()) + .replace("color", ((SimpleMessage) translator.translate(color.translationKey)).getMessage()) + .send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + } else { + translator.translate("command_npc_modification_cancelled").send(sender); } + } + // NOTE: Perhaps this could be moved somewhere or be a standalone class. + public enum GlowingColor { + DISABLED(null, ""), + BLACK(NamedTextColor.BLACK, "color_black"), + DARK_BLUE(NamedTextColor.DARK_BLUE, "color_dark_blue"), + DARK_GREEN(NamedTextColor.DARK_GREEN, "color_dark_green"), + DARK_AQUA(NamedTextColor.DARK_AQUA, "color_dark_aqua"), + DARK_RED(NamedTextColor.DARK_RED, "color_dark_red"), + DARK_PURPLE(NamedTextColor.DARK_PURPLE, "color_dark_purple"), + GOLD(NamedTextColor.GOLD, "color_gold"), + GRAY(NamedTextColor.GRAY, "color_gray"), + DARK_GRAY(NamedTextColor.DARK_GRAY, "color_dark_gray"), + BLUE(NamedTextColor.BLUE, "color_blue"), + GREEN(NamedTextColor.GREEN, "color_green"), + AQUA(NamedTextColor.AQUA, "color_aqua"), + RED(NamedTextColor.RED, "color_red"), + LIGHT_PURPLE(NamedTextColor.LIGHT_PURPLE, "color_light_purple"), + YELLOW(NamedTextColor.YELLOW, "color_yellow"), + WHITE(NamedTextColor.WHITE, "color_white"); - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } + // Handled as 'disabled' if set to null. + private final @Nullable NamedTextColor color; - boolean glowing; - try { - glowing = Boolean.parseBoolean(args[2]); - } catch (Exception e) { - translator.translate("command_invalid_boolean").replace("input", args[2]).send(sender); - return false; - } + private final @NotNull String translationKey; - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, glowing, sender); - npcModifyEvent.callEvent(); + private GlowingColor(final @Nullable NamedTextColor color, final @NotNull String translationKey) { + this.color = color; + this.translationKey = translationKey; + } - if (!npcModifyEvent.isCancelled()) { - npc.getData().setGlowing(glowing); - npc.updateForAll(); - translator.translate(glowing ? "npc_glowing_set_true" : "npc_glowing_set_false").replace("npc", npc.getData().getName()).send(sender); - } else { - translator.translate("command_npc_modification_cancelled").send(sender); + public @Nullable NamedTextColor getColor() { + return color; } - return true; } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java deleted file mode 100644 index 0399494f..00000000 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingColorCMD.java +++ /dev/null @@ -1,64 +0,0 @@ -package de.oliver.fancynpcs.commands.npc; - -import de.oliver.fancylib.translations.Translator; -import de.oliver.fancynpcs.FancyNpcs; -import de.oliver.fancynpcs.api.Npc; -import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.List; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class GlowingColorCMD implements Subcommand { - - private final Translator translator = FancyNpcs.getInstance().getTranslator(); - - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return NamedTextColor.NAMES.keys().stream() - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - return null; - } - - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - translator.translate("npc_glowingColor_syntax").send(sender); - return false; - } - - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - NamedTextColor color = NamedTextColor.NAMES.value(args[2]); - if (color == null) { - translator.translate("npc_glowingColor_failure_invalid_color").replace("input", args[2]).send(sender); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING_COLOR, color, sender); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().setGlowingColor(color); - npc.updateForAll(); - translator.translate("npc_glowingColor_success").replace("npc", npc.getData().getName()).send(sender); - } else { - translator.translate("command_npc_modification_cancelled").send(sender); - } - - return true; - } -} diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index b33eaa8b..f9e091e7 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -5,40 +5,36 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; -import de.oliver.fancynpcs.commands.Subcommand; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; import java.text.DecimalFormat; -import java.util.List; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -public class InfoCMD implements Subcommand { +public enum InfoCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); private static final DecimalFormat SECONDS_FORMAT = new DecimalFormat("#,###.#"); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; + @Command("npc info") + @Permission("fancynpcs.command.npc.info") + public void onDefault(final CommandSender sender) { + translator.translate("npc_info_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - Location loc = npc.getData().getLocation(); + @Command("npc info ") + @Permission("fancynpcs.command.npc.info") + public void onCommand(final CommandSender sender, final Npc npc) { + final Location loc = npc.getData().getLocation(); translator.translate("npc_info_general") .replace("name", npc.getData().getName()) @@ -101,7 +97,6 @@ public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull St ); translator.translate("npc_info_attributes_footer").send(sender); } - return false; } // NOTE: Might need to be improved later down the line, should get work done for now. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java index 33d292b2..b0a8cf82 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java @@ -4,54 +4,31 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.List; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class InteractionCooldownCMD implements Subcommand { +public enum InteractionCooldownCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; + @Command("npc interaction_cooldown") + @Permission("fancynpcs.command.npc.interaction_cooldown") + public void onDefault(final CommandSender sender) { + translator.translate("npc_interaction_cooldown_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - translator.translate("npc_interactionCooldown_syntax").send(sender); - return false; - } - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - float cooldown; - try { - cooldown = Float.parseFloat(args[2]); - } catch (NumberFormatException e) { - translator.translate("command_invalid_number").replace("input", args[2]).send(sender); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.INTERACTION_COOLDOWN, cooldown, sender); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { + @Command("npc interaction_cooldown ") + @Permission("fancynpcs.command.npc.interaction_cooldown") + public void onCommand(final CommandSender sender, final Npc npc, final float cooldown) { + // Calling the event and updating the cooldown if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.INTERACTION_COOLDOWN, cooldown, sender).callEvent()) { npc.getData().setInteractionCooldown(cooldown); - translator.translate("npc_interactionCooldown_success").replace("npc", npc.getData().getName()); + translator.translate("npc_interaction_cooldown_success").replace("npc", npc.getData().getName()); } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java index 48d84344..18919c5a 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java @@ -23,39 +23,79 @@ public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @No return null; } - @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (!receiver.hasPermission("fancynpcs.npc.list") && !receiver.hasPermission("fancynpcs.npc.*")) { - MessageHelper.error(receiver, lang.get("no-permission-subcommand")); - return false; - } - - MessageHelper.info(receiver, lang.get("npc-command-list-header")); - - Collection allNpcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs(); - if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && receiver instanceof Player player) { - allNpcs = allNpcs.stream() - .filter(n -> n.getData().getCreator().equals(player.getUniqueId())) - .toList(); - } - - if (allNpcs.isEmpty()) { - MessageHelper.warning(receiver, lang.get("npc-command-list-no-npcs")); - } else { - final DecimalFormat df = new DecimalFormat("#########.##"); - for (Npc n : allNpcs) { - MessageHelper.info(receiver, lang.get( - "npc-command-list-tp-hover", - "name", n.getData().getName(), - "x", df.format(n.getData().getLocation().x()), - "y", df.format(n.getData().getLocation().y()), - "z", df.format(n.getData().getLocation().z()), - "tp_cmd", "/tp " + n.getData().getLocation().x() + " " + n.getData().getLocation().y() + " " + n.getData().getLocation().z() - ) - ); + @Command("npc list") + @Permission("fancynpcs.command.npc.list") + public void onCommand( + final CommandSender sender, + final @Nullable @Flag("radius") Long radius, + final @Nullable @Flag("type") EntityType type, + final @Nullable @Flag("sort") SortType sort + ) { + Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); + // Excluding NPCs not created by the sender, if PLAYER_NPCS_FEATURE_FLAG is enabled and sender is a player. + if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && sender instanceof Player player) + npcs = npcs.filter(npc -> npc.getData().getCreator().equals(player.getUniqueId())); + // Excluding NPCs that are not in radius, if specified and sender is a player. (radius is calculated from the location of player) + if (radius != null && sender instanceof Player player) + npcs = npcs.filter(npc -> npc.getData().getLocation().distance(player.getLocation()) <= radius); + // Excluding NPCs that are not of a specified type, if desired. + if (type != null) + npcs = npcs.filter(npc -> npc.getData().getType() == type); + // Sorting... + switch (sort != null ? sort : (sender instanceof Player player) ? SortType.NEAREST : SortType.NAME) { + case NEAREST -> { + if (sender instanceof Player player) + npcs = npcs.sorted(Comparator.comparingDouble(npc -> npc.getData().getLocation().distance(player.getLocation()))); + // ... + else sender.sendMessage("Cannot use SortType.NEAREST from console."); // TODO + } + case FARTHEST -> { + if (sender instanceof Player player) + // This needs a cast for some reason. + npcs = npcs.sorted(Comparator.comparingDouble(npc -> ((Npc) npc).getData().getLocation().distance(player.getLocation())).reversed()); + // ... + else sender.sendMessage("Cannot use SortType.FARTHEST from console."); // TODO + } + case NAME -> { + npcs = npcs.sorted(Comparator.comparing(npc -> npc.getData().getName())); + } + case NAME_REVERSED -> { + // This needs a cast for some reason. + npcs = npcs.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); } } + translator.translate("npc_list_header").send(sender); + final AtomicInteger count = new AtomicInteger(1); + // ... + npcs.toList().forEach(npc -> { + final Location loc = npc.getData().getLocation(); + // ... + translator.translate(sender instanceof Player player ? "npc_list_entry_player" : "npc_list_entry") + .replace("num", String.valueOf(count.getAndIncrement())) + .replace("npc", npc.getData().getName()) + .replace("name", npc.getData().getName()) + .replace("id", npc.getData().getId()) + .replace("id_short", npc.getData().getId().substring(0, 13) + "...") + .replace("internal_id", "2") + .replace("creator", npc.getData().getCreator().toString()) + .replace("creator_short", npc.getData().getCreator().toString().substring(0, 13) + "...") + .replace("displayname", npc.getData().getDisplayName()) + .replace("type", npc.getData().getType().toString()) + .replace("location_x", COORDS_FORMAT.format(loc.x())) + .replace("location_y", COORDS_FORMAT.format(loc.y())) + .replace("location_z", COORDS_FORMAT.format(loc.z())) + .replace("distance", (sender instanceof Player player) ? new DecimalFormat("#.#").format(player.getLocation().distance(npc.getData().getLocation())) : "N/A") + .replace("world", loc.getWorld().getName()) + .send(sender); + }); + translator.translate("npc_list_footer") + .replace("count", String.valueOf(count)) + .replace("total", String.valueOf(FancyNpcs.getInstance().getNpcManager().getAllNpcs().size())) + .send(sender); + } - return true; + public enum SortType { + NEAREST, FARTHEST, NAME, NAME_REVERSED } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java deleted file mode 100644 index 0455bec3..00000000 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MirrorSkinCMD.java +++ /dev/null @@ -1,69 +0,0 @@ -package de.oliver.fancynpcs.commands.npc; - -import de.oliver.fancylib.MessageHelper; -import de.oliver.fancylib.translations.Translator; -import de.oliver.fancynpcs.FancyNpcs; -import de.oliver.fancynpcs.api.Npc; -import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.List; -import java.util.stream.Stream; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class MirrorSkinCMD implements Subcommand { - - private final Translator translator = FancyNpcs.getInstance().getTranslator(); - - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Stream.of("true", "false") - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - return null; - } - - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - translator.translate("npc_mirrorSkin_syntax").send(sender); - return false; - } - - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - boolean mirrorSkin; - try { - mirrorSkin = Boolean.parseBoolean(args[2]); - } catch (Exception e) { - translator.translate("command_invalid_boolean").replace("input", args[2]).send(sender); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, mirrorSkin, sender); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().setMirrorSkin(mirrorSkin); - npc.removeForAll(); - npc.create(); - npc.spawnForAll(); - translator.translate(mirrorSkin ? "npc_mirrorSkin_set_true" : "npc_mirrorSkin_set_false").replace("npc", npc.getData().getName()).send(sender); - } else { - translator.translate("command_npc_modification_cancelled").send(sender); - } - - return true; - } -} diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java index f2be8abb..8633de90 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java @@ -4,58 +4,40 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.Location; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.List; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class MoveHereCMD implements Subcommand { +// NOTE: Perhaps a better command could be added instead, which supports both - teleporting to the sender and setting coordinates. +public enum MoveHereCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; + @Command(value = "npc move_here", requiredSender = Player.class) + @Permission("fancynpcs.command.npc.move_here") + public void onDefault(final Player sender) { + translator.translate("npc_move_here_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (!(sender instanceof Player player)) { - translator.translate("command_player_only").send(sender); - return false; - } - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - Location location = player.getLocation(); - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender); - npcModifyEvent.callEvent(); - - String oldWorld = npc.getData().getLocation().getWorld().getName(); - - if (!npcModifyEvent.isCancelled()) { + @Command(value = "npc move_here ", requiredSender = Player.class) + @Permission("fancynpcs.command.npc.move_here") + public void onCommand(final Player sender, final Npc npc) { + final Location location = sender.getLocation(); + final String oldWorld = npc.getData().getLocation().getWorld().getName(); + // Calling the event and moving the NPc to location of the sender, if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender).callEvent()) { npc.getData().setLocation(location); - if (oldWorld.equals(location.getWorld().getName())) { npc.updateForAll(); } else { npc.removeForAll(); npc.spawnForAll(); } - translator.translate("npc_moveHere_success").replace("npc", npc.getData().getName()).send(sender); + translator.translate("npc_move_here_success").replace("npc", npc.getData().getName()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java index dcaffff0..3f673b85 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java @@ -3,255 +3,61 @@ import de.oliver.fancylib.translations.Translator; import de.oliver.fancylib.translations.message.MultiMessage; import de.oliver.fancynpcs.FancyNpcs; -import de.oliver.fancynpcs.api.Npc; -import de.oliver.fancynpcs.commands.Subcommand; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Argument; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class NpcCMD extends Command { +public enum NpcCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private final Subcommand attributeCMD = new AttributeCMD(); - private final Subcommand collidableCMD = new CollidableCMD(); - private final Subcommand displayNameCMD = new DisplayNameCMD(); - private final Subcommand equipmentCMD = new EquipmentCMD(); - private final Subcommand glowingCMD = new GlowingCMD(); - private final Subcommand glowingColorCMD = new GlowingColorCMD(); - private final Subcommand messageCMD = new MessageCMD(); - private final Subcommand playerCommandCMD = new PlayerCommandCMD(); - private final Subcommand serverCommandCMD = new ServerCommandCMD(); - private final Subcommand showInTabCMD = new ShowInTabCMD(); - private final Subcommand teleportCMD = new TeleportCMD(); - private final Subcommand turnToPlayerCMD = new TurnToPlayerCMD(); - private final Subcommand typeCMD = new TypeCMD(); - private final Subcommand mirrorSkinCMD = new MirrorSkinCMD(); - private final Subcommand fixCMD = new FixCMD(); - public NpcCMD() { - super("npc"); - setPermission("fancynpcs.npc"); - } - - @Override - public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { - if (!(sender instanceof Player p)) { - translator.translate("command_player_only").send(sender); - return null; - } - - List suggestions = new ArrayList<>(); - - if (args.length == 1) { - suggestions.addAll(Stream.of("help", "info", "message", "create", "remove", "copy", "fix", "skin", "movehere", "teleport", "displayName", "equipment", "playerCommand", "serverCommand", "showInTab", "glowing", "glowingColor", "collidable", "list", "turnToPlayer", "type", "attribute", "interactionCooldown", "mirrorSkin") - .filter(input -> input.toLowerCase().startsWith(args[0].toLowerCase())) - .toList()); - - } else if (args.length == 2 && !args[0].equalsIgnoreCase("create")) { - suggestions.addAll(FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs() - .stream() - .filter(npc -> !FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() || npc.getData().getCreator().equals(p.getUniqueId())) - .map(npc -> npc.getData().getName()) - .filter(input -> input.toLowerCase().startsWith(args[1].toLowerCase())) - .toList()); - } - - if (!suggestions.isEmpty()) return suggestions; - - if (args.length < 3) { - return Collections.emptyList(); - } - - String subcommand = args[0]; - String name = args[1]; - Npc npc = FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() ? - FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name, p.getUniqueId()) : - FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name); - - return switch (subcommand.toLowerCase()) { - case "attribute" -> attributeCMD.tabcompletion(p, npc, args); - case "collidable" -> collidableCMD.tabcompletion(p, npc, args); - case "displayname" -> displayNameCMD.tabcompletion(p, npc, args); - case "equipment" -> equipmentCMD.tabcompletion(p, npc, args); - case "glowing" -> glowingCMD.tabcompletion(p, npc, args); - case "glowingcolor" -> glowingColorCMD.tabcompletion(p, npc, args); - case "message" -> messageCMD.tabcompletion(p, npc, args); - case "playercommand" -> playerCommandCMD.tabcompletion(p, npc, args); - case "servercommand" -> serverCommandCMD.tabcompletion(p, npc, args); - case "showintab" -> showInTabCMD.tabcompletion(p, npc, args); - case "teleport" -> teleportCMD.tabcompletion(p, npc, args); - case "turntoplayer" -> turnToPlayerCMD.tabcompletion(p, npc, args); - case "type" -> typeCMD.tabcompletion(p, npc, args); - case "mirrorskin" -> mirrorSkinCMD.tabcompletion(p, npc, args); - case "fix" -> fixCMD.tabcompletion(p, npc, args); - - default -> Collections.emptyList(); + @Suggestions("page") + public List suggestions(final CommandContext context, final CommandInput input) { + // Getting the (full) help contents. + final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); + // Calculating max page number. + final int maxPage = contents.getRawMessages().size() / 6 + 1; + // Returning suggestions... + return new ArrayList<>() {{ + for (int i = 1; i <= maxPage; i++) { + add(String.valueOf(i)); + }} }; } - @Override - public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { - if (!testPermission(sender)) { - return false; - } - - if (args.length >= 1 && args[0].equalsIgnoreCase("help")) { - if (!sender.hasPermission("fancynpcs.npc.help") && !sender.hasPermission("fancynpcs.npc.*")) { - translator.translate("command_missing_permissions").send(sender); - return false; - } - // Getting the (full) help contents. - final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); - // Calculating max page number. - final int maxPage = contents.getRawMessages().size() / 6 + 1; - // Getting the requested page. Defaults to 1 for invalid input and is capped by number of the last page. - final int page = Math.min(args.length == 2 ? parseIntOrDefault(args[1], 1) : 1, maxPage); - // Getting help contents for requested page, or defaulting to 1. - final MultiMessage requestedContents = contents.page(page, 6); - // Sending help header to the sender. - translator.translate("npc_help_page_header").replace("page", String.valueOf(page)).replace("max_page", String.valueOf(maxPage)).send(sender); - // Sending (requested) help contents to the sender. - requestedContents.send(sender); - // Sending help footer to the sender. - translator.translate("npc_help_page_footer").replace("page", String.valueOf(page)).replace("max_page", String.valueOf(maxPage)).send(sender); - return true; - } - - if (args.length >= 1 && args[0].equalsIgnoreCase("list")) { - return new ListCMD().run(sender, null, args); - } - - // NOTE(command rework): This will be replaced to use command-specific syntax message instead. - if (args.length < 2) { - translator.translate("command_incomplete_usage").send(sender); - return false; - } - - String subcommand = args[0]; - String name = args[1]; - Npc npc; - if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && sender instanceof Player player) { - npc = FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name, player.getUniqueId()); - } else { - npc = FancyNpcs.getInstance().getNpcManagerImpl().getNpc(name); - } - - - if (!sender.hasPermission("fancynpcs.npc." + subcommand) && !sender.hasPermission("fancynpcs.npc.*")) { - translator.translate("command_missing_permissions").send(sender); - return false; - } - - switch (subcommand.toLowerCase()) { - case "create" -> { - return new CreateCMD().run(sender, null, args); - } - - case "remove" -> { - return new RemoveCMD().run(sender, npc, args); - } - - case "copy" -> { - return new CopyCMD().run(sender, npc, args); - } - - case "info" -> { - return new InfoCMD().run(sender, npc, args); - } - - case "movehere" -> { - return new MoveHereCMD().run(sender, npc, args); - } - - case "teleport" -> { - return teleportCMD.run(sender, npc, args); - } - - case "message" -> { - return messageCMD.run(sender, npc, args); - } - - case "skin" -> { - return new SkinCMD().run(sender, npc, args); - } - - case "displayname" -> { - return displayNameCMD.run(sender, npc, args); - } - - case "equipment" -> { - return equipmentCMD.run(sender, npc, args); - } - - case "servercommand" -> { - return serverCommandCMD.run(sender, npc, args); - } - - case "playercommand" -> { - return playerCommandCMD.run(sender, npc, args); - } - - case "interactioncooldown" -> { - return new InteractionCooldownCMD().run(sender, npc, args); - } - - case "showintab" -> { - return showInTabCMD.run(sender, npc, args); - } - - case "glowing" -> { - return glowingCMD.run(sender, npc, args); - } - - case "glowingcolor" -> { - return glowingColorCMD.run(sender, npc, args); - } - - case "collidable" -> { - return collidableCMD.run(sender, npc, args); - } - - case "turntoplayer" -> { - return turnToPlayerCMD.run(sender, npc, args); - } - - case "type" -> { - return typeCMD.run(sender, npc, args); - } - - case "attribute" -> { - return attributeCMD.run(sender, npc, args); - } - - case "mirrorskin" -> { - return mirrorSkinCMD.run(sender, npc, args); - } - - case "fix" -> { - return fixCMD.run(sender, npc, args); - } - - default -> { - translator.translate("command_wrong_usage").send(sender); - return false; - } - } + @Command("npc") + @Permission("fancynpcs.command.npc") + public void onDefault(final CommandSender sender) { + translator.translate("command_incomplete_usage").send(sender); } - // Parses String to Integer and returns it, or default value if exception was caught. - private static int parseIntOrDefault(final String str, final int def) { - try { - return Integer.parseInt(str); - } catch (final NumberFormatException e) { - return def; - } + @Command("npc help [page]") + @Permission("fancynpcs.command.npc") + public void onHelp(final CommandSender sender, final @Argument(suggestions = "page") @Nullable Integer page) { + // Getting the (full) help contents. + final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); + // Calculating max page number. + final int maxPage = contents.getRawMessages().size() / 6 + 1; + // Getting the requested page. Defaults to 1 for invalid input and is capped by number of the last page. + final int finalPage = Math.min(page != null ? page : 1, maxPage); + // Getting help contents for requested page, or defaulting to 1. + final MultiMessage requestedContents = contents.page(finalPage, 6); + // Sending help header to the sender. + translator.translate("npc_help_page_header").replace("page", String.valueOf(finalPage)).replace("max_page", String.valueOf(maxPage)).send(sender); + // Sending (requested) help contents to the sender. + requestedContents.send(sender); + // Sending help footer to the sender. + translator.translate("npc_help_page_footer").replace("page", String.valueOf(finalPage)).replace("max_page", String.valueOf(maxPage)).send(sender); } } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java index ac5be5bf..7ad08f78 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java @@ -5,35 +5,32 @@ import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcRemoveEvent; import de.oliver.fancynpcs.api.events.NpcStopLookingEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Flag; +import org.incendo.cloud.annotations.Permission; -import java.util.List; - -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class RemoveCMD implements Subcommand { +public enum RemoveCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; + @Command("npc remove") + @Permission("fancynpcs.command.npc.remove") + public void onDefault(final CommandSender sender) { + translator.translate("npc_remove_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - NpcRemoveEvent npcRemoveEvent = new NpcRemoveEvent(npc, sender); - npcRemoveEvent.callEvent(); - if (!npcRemoveEvent.isCancelled()) { + @Command("npc remove ") + @Permission("fancynpcs.command.npc.remove") + public void onCommand(final CommandSender sender, final Npc npc, final @Nullable @Flag("creator") OfflinePlayer creator) { + // Calling the event and removing the NPC if not cancelled. + if (new NpcRemoveEvent(npc, sender).callEvent()) { npc.removeForAll(); // Iterating over all online players that the NPC is currently looking at. for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { @@ -49,7 +46,6 @@ public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull St } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - return false; } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java index d6e0d987..288df162 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java @@ -4,77 +4,38 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.List; -import java.util.stream.Stream; - -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class ShowInTabCMD implements Subcommand { +public enum ShowInTabCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Stream.of("true", "false") - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - return null; + @Command("npc show_in_tab") + @Permission("fancynpcs.command.npc.show_in_tab") + public void onDefault(final CommandSender sender) { + translator.translate("npc_show_in_tab_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - translator.translate("npc_showInTab_syntax").send(sender); - return false; - } - - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - if (npc.getData().getType() != EntityType.PLAYER) { - translator.translate("command_unsupported_npc_type").send(sender); - return false; + @Command("npc show_in_tab [state]") + @Permission("fancynpcs.command.npc.show_in_tab") + public void onCommand(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + final boolean finalState = (state == null) ? !npc.getData().isShowInTab() : state; + // Calling the event and updating the state if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SHOW_IN_TAB, finalState, sender).callEvent()) { + // Updating the state. + npc.getData().setShowInTab(finalState); + // Sending message to the sender. + translator.translate(finalState ? "npc_show_in_tab_set_true" : "npc_show_in_tab_set_false").replace("npc", npc.getData().getName()).send(sender); + // Returning from the command block. + return; } - - boolean showInTab; - switch (args[2].toLowerCase()) { - case "true" -> showInTab = true; - case "false" -> showInTab = false; - default -> { - translator.translate("command_invalid_boolean").replace("input", args[2].toLowerCase()); - return false; - } - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SHOW_IN_TAB, showInTab, sender); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().setShowInTab(showInTab); - - if (showInTab) { - npc.updateForAll(); - } else { - npc.removeForAll(); - npc.spawnForAll(); - } - translator.translate(showInTab ? "npc_showInTab_set_true" : "npc_showInTab_set_false").replace("npc", npc.getData().getName()).send(sender); - } else { - translator.translate("command_npc_modification_cancelled").send(sender); - } - - return true; + // Otherwise, sending error message to the sender. + translator.translate("command_npc_modification_cancelled").send(sender); } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java index 206338a7..5df90dda 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java @@ -1,82 +1,152 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; import de.oliver.fancylib.UUIDFetcher; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.api.utils.SkinFetcher; -import de.oliver.fancynpcs.commands.Subcommand; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.incendo.cloud.annotations.Argument; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; import java.util.List; import java.util.UUID; +import java.util.regex.Pattern; -public class SkinCMD implements Subcommand { +import org.jetbrains.annotations.NotNull; - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); +public enum SkinCMD { + INSTANCE; // SINGLETON - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; - } + private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (args.length != 3 && args.length != 2) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - String skinName = args.length == 3 ? args[2] : receiver instanceof Player player ? player.getName() : "Steve"; + private static final Pattern USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{3,16}$"); + @Suggestions("skin") + public List suggestions(final CommandContext context, final CommandInput input) { + return new ArrayList<>() {{ + add("@none"); + add("@mirror"); + Bukkit.getOnlinePlayers().stream().map(Player::getName).forEach(this::add); + }}; + } - if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); - return false; - } + @Command("npc skin") + @Permission("fancynpcs.command.npc.skin") + public void onDefault(final CommandSender sender) { + translator.translate("npc_skin_syntax").send(sender); + } + @Command("npc skin ") + @Permission("fancynpcs.command.npc.skin") + public void onCommand(final CommandSender sender, final Npc npc, final @Argument(suggestions = "skin") String skin) { + // Exiting command block if specified NPC is not of a PLAYER type. if (npc.getData().getType() != EntityType.PLAYER) { - MessageHelper.error(receiver, lang.get("npc-must-be-player")); - return false; + translator.translate("command_unsupported_npc_type").send(sender); + return; } + // Getting some information about input to handle command accordingly and improve message accuracy. + final boolean isMirror = skin.equalsIgnoreCase("@mirror"); + final boolean isNone = skin.equalsIgnoreCase("@none"); + final boolean isURL = isURL(skin); - if (SkinFetcher.SkinType.getType(skinName) == SkinFetcher.SkinType.UUID) { - UUID uuid = UUIDFetcher.getUUID(skinName); - if (uuid == null) { - MessageHelper.error(receiver, lang.get("npc-command-skin-invalid", "input", args[2])); - return false; + if (isMirror) { + // Calling event and updating the skin if not cancelled, sending error message otherwise. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, true, sender).callEvent()) { + npc.getData().setMirrorSkin(true); + npc.removeForAll(); + npc.create(); + npc.spawnForAll(); + translator.translate("npc_skin_set_mirror").replace("npc", npc.getData().getName()).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); } - skinName = uuid.toString(); - } - SkinFetcher skinFetcher = new SkinFetcher(skinName); - if (!skinFetcher.isLoaded()) { - MessageHelper.error(receiver, lang.get("npc-command-message-failed_header")); - MessageHelper.error(receiver, lang.get("npc-command-skin-failed_url")); - MessageHelper.error(receiver, lang.get("npc-command-skin-failed_limited")); - return false; - } + } else if (isNone) { + // Calling events and updating the skin if not cancelled, sending error message otherwise. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, false, sender).callEvent() && new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SKIN, null, sender).callEvent()) { + npc.getData().setMirrorSkin(false); + npc.getData().setSkin(null); + npc.removeForAll(); + npc.create(); + npc.spawnForAll(); + translator.translate("npc_skin_set_none").replace("npc", npc.getData().getName()).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SKIN, skinFetcher, receiver); - npcModifyEvent.callEvent(); + } else if (isURL) { + // Creating SkinFetcher from the specified texture URL. + final SkinFetcher skinFetcher = new SkinFetcher(skin); + // Sending error message if SkinFetcher has failed to load the skin. + if (!skinFetcher.isLoaded()) { + translator.translate("npc_skin_failure_invalid_url").replace("input", skin).send(sender); + return; + } + // Calling events and updating the skin if not cancelled, sending error message otherwise. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, false, sender).callEvent() && new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SKIN, skinFetcher, sender).callEvent()) { + npc.getData().setMirrorSkin(false); + npc.getData().setSkin(skinFetcher); + npc.removeForAll(); + npc.create(); + npc.spawnForAll(); + translator.translate("npc_skin_set_url").replace("npc", npc.getData().getName()).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } - if (!npcModifyEvent.isCancelled()) { - npc.getData().setSkin(skinFetcher); - npc.getData().setMirrorSkin(false); - npc.removeForAll(); - npc.create(); - npc.spawnForAll(); - MessageHelper.success(receiver, lang.get("npc-command-skin-updated", "npc", npc.getData().getName())); + // NOTE: Matching against valid username pattern to make it somewhat injection-proof. + } else if (USERNAME_PATTERN.matcher(skin).find()) { + // Fetching UUID from the specified player name. + // NOTE: This can occasionally print stacktrace to the console and right now there is nothing that could be done to prevent that. + final UUID uuid = UUIDFetcher.getUUID(skin); + // Exiting the command block and sending error message if invalid/unsupported URL has been provided. + if (uuid == null) { + translator.translate("npc_skin_failure_invalid_name_or_rate_limit").send(sender); + return; + } + // Creating SkinFetcher from the fetched UUID. + final SkinFetcher skinFetcher = new SkinFetcher(uuid.toString()); + // Sending error message if SkinFetcher has failed to load the skin. + if (!skinFetcher.isLoaded()) { + translator.translate("npc_skin_failure_invalid_name_or_rate_limit").send(sender); + return; + } + // Calling events and updating the skin if not cancelled, sending error message otherwise. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, false, sender).callEvent() && new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SKIN, skinFetcher, sender).callEvent()) { + npc.getData().setMirrorSkin(false); + npc.getData().setSkin(skinFetcher); + npc.removeForAll(); + npc.create(); + npc.spawnForAll(); + translator.translate("npc_skin_set_name").replace("npc", npc.getData().getName()).replace("name", skin).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("npc_skin_failure_invalid_name_or_url").replace("input", skin).send(sender); } + } - return true; + // Returns 'true' if String can be parsed to an URL or 'false' otherwise. + private static boolean isURL(final @NotNull String url) { + try { + new URL(url); + return true; + } catch (final MalformedURLException e) { + return false; + } } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java index e290c181..1e396285 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java @@ -4,118 +4,45 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.util.RayTraceResult; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; import java.text.DecimalFormat; -import java.util.List; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class TeleportCMD implements Subcommand { +public enum TeleportCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); - - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - RayTraceResult rayTraceResult = player.rayTraceBlocks(50); - if (args.length == 3) { - return List.of(String.valueOf(rayTraceResult != null ? - COORDS_FORMAT.format(rayTraceResult.getHitPosition().getX()) : - COORDS_FORMAT.format(player.getLocation().getX())).replace(',', '.') - ); - } else if (args.length == 4) { - return List.of(String.valueOf(rayTraceResult != null ? - COORDS_FORMAT.format(rayTraceResult.getHitPosition().getY()) : - COORDS_FORMAT.format(player.getLocation().getY())).replace(',', '.') - ); - } else if (args.length == 5) { - return List.of(String.valueOf(rayTraceResult != null ? - COORDS_FORMAT.format(rayTraceResult.getHitPosition().getZ()) : - COORDS_FORMAT.format(player.getLocation().getZ())).replace(',', '.') - ); - } else if (args.length == 6) { - return List.of(player.getLocation().getWorld().getName()); - } + private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); - return null; + @Command("npc teleport") + @Permission("fancynpcs.command.npc.teleport") + public void onDefault(final CommandSender sender) { + translator.translate("npc_teleport_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - if (args.length < 5) { - translator.translate("npc_teleport_syntax").send(sender); - return false; - } - - double x, y, z; - - try { // NOTE: Additional try-catch blocks has been added to improve error message, will be improved during commands rework. - x = Double.parseDouble(args[2]); - } catch (NumberFormatException e) { - translator.translate("command_invalid_number").replace("input", args[2]).send(sender); - return false; - } - - try { // NOTE: Additional try-catch blocks has been added to improve error message, will be improved during commands rework. - y = Double.parseDouble(args[3]); - } catch (NumberFormatException e) { - translator.translate("command_invalid_number").replace("input", args[3]).send(sender); - return false; - } - - try { // NOTE: Additional try-catch blocks has been added to improve error message, will be improved during commands rework. - z = Double.parseDouble(args[4]); - } catch (NumberFormatException e) { - translator.translate("command_invalid_number").replace("input", args[4]).send(sender); - return false; - } - - World world = null; - - if (args.length == 6) { - world = Bukkit.getWorld(args[5]); - } else if (sender instanceof Player p) { - world = p.getWorld(); - } + @Command("npc teleport [world]") + @Permission("fancynpcs.command.npc.teleport") + public void onCommand(final CommandSender sender, final Npc npc, final Location location, final @Nullable World world) { - if (world == null) { - translator.translate("command_invalid_world").replace("input", args[5]).send(sender); - return false; - } - - Location location = new Location(world, x, y, z); - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender).callEvent()) { npc.getData().setLocation(location); npc.updateForAll(); translator.translate("command_invalid_world") .replace("npc", npc.getData().getName()) - .replace("x", COORDS_FORMAT.format(x)) - .replace("y", COORDS_FORMAT.format(x)) - .replace("z", COORDS_FORMAT.format(x)) + .replace("x", COORDS_FORMAT.format(location.x())) + .replace("y", COORDS_FORMAT.format(location.y())) + .replace("z", COORDS_FORMAT.format(location.z())) .replace("world", world.getName()) .send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java index 7ce5264c..4dbdcd49 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java @@ -4,67 +4,38 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.List; -import java.util.stream.Stream; - -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class TurnToPlayerCMD implements Subcommand { +public enum TurnToPlayerCMD { + INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Stream.of("true", "false") - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - return null; + @Command("npc turn_to_player") + @Permission("fancynpcs.command.npc.turn_to_player") + public void onDefault(final CommandSender sender) { + translator.translate("npc_turn_to_player_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender sender, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - translator.translate("npc_turnToPlayer_syntax").send(sender); - return false; - } - - if (npc == null) { - translator.translate("command_invalid_npc").replace("npc", args[1]).send(sender); - return false; - } - - boolean turnToPlayer; - try { - turnToPlayer = Boolean.parseBoolean(args[2]); - } catch (Exception e) { - translator.translate("command_invalid_boolean").replace("input", args[2]).send(sender); - return false; + @Command("npc turn_to_player [state]") + @Permission("fancynpcs.command.npc.turn_to_player") + public void onCommand(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + final boolean finalState = (state == null) ? !npc.getData().isTurnToPlayer() : state; + // Calling the event and updating the state if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.TURN_TO_PLAYER, finalState, sender).callEvent()) { + // Updating the state. + npc.getData().setTurnToPlayer(finalState); + // Sending message to the sender. + translator.translate(finalState ? "npc_turn_to_player_set_true" : "npc_turn_to_player_set_false").replace("npc", npc.getData().getName()).send(sender); + // Returning from the command block. + return; } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.TURN_TO_PLAYER, turnToPlayer, sender); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().setTurnToPlayer(turnToPlayer); - - if (turnToPlayer) { - translator.translate("npc_turnToPlayer_set_true").replace("npc", npc.getData().getName()).send(sender); - } else { - translator.translate("npc_turnToPlayer_set_false").replace("npc", npc.getData().getName()).send(sender); - npc.updateForAll(); // move to default pos - } - } else { - translator.translate("command_npc_modification_cancelled").send(sender); - } - - return true; + // Otherwise, sending error message to the sender. + translator.translate("command_npc_modification_cancelled").send(sender); } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java index 2dca3a4f..5adf3551 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java @@ -1,61 +1,31 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.Arrays; -import java.util.List; +public enum TypeCMD { + INSTANCE; // SINGLETON -public class TypeCMD implements Subcommand { + private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); - - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Arrays.stream(EntityType.values()) - .map(Enum::name) - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - return null; + @Command("npc type") + @Permission("fancynpcs.command.npc.type") + public void onDefault(final CommandSender sender) { + translator.translate("npc_type_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); - return false; - } - - EntityType type = EntityType.fromName(args[2].toLowerCase()); - - if (type == null) { - MessageHelper.error(receiver, lang.get("npc-command-type-invalid", "input", args[2].toLowerCase())); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.TYPE, type, receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { + @Command("npc type ") + @Permission("fancynpcs.command.npc.type") + public boolean onCommand(final CommandSender sender, final Npc npc, final EntityType type) { + // Calling the event and updating the type if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.TYPE, type, sender).callEvent()) { npc.getData().setType(type); - if (type != EntityType.PLAYER) { npc.getData().setGlowing(false); npc.getData().setShowInTab(false); @@ -67,9 +37,9 @@ public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull npc.removeForAll(); npc.create(); npc.spawnForAll(); - MessageHelper.success(receiver, lang.get("npc-command-type-updated", "npc", npc.getData().getName(), "type", type.name().toLowerCase())); + //MessageHelper.success(receiver, lang.get("npc-command-type-updated", "npc", npc.getData().getName(), "type", type.name().toLowerCase())); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + //MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); } return true; diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index f9f333e2..c042e0f3 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -12,6 +12,23 @@ messages: chest: "Chest" legs: "Legs" feet: "Feet" + # Common (Colors) + color_black: "Black" + color_dark_blue: "Dark Blue" + color_dark_green: "Dark Green" + color_dark_aqua: "Dark Aqua" + color_dark_red: "Dark Red" + color_dark_purple: "Dark Purple" + color_gold: "Gold" + color_gray: "Gray" + color_dark_gray: "Dark Gray" + color_blue: "Blue" + color_green: "Green" + color_aqua: "Aqua" + color_red: "Red" + color_light_purple: "Light Purple" + color_yellow: "Yellow" + color_white: "White" # Common (Other) interaction_on_cooldown: "" # Commands (Common Replies) @@ -23,8 +40,8 @@ messages: command_invalid_number: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid number." command_invalid_integer: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid integer." command_invalid_world: "› {errorColor}World named {warningColor}{input}{errorColor} does not exist." - command_invalid_npc: "› {errorColor}NPC named {warningColor}{npc}{errorColor} does not exist." - command_unsupported_npc_type: "This NPC type does not support this feature." + command_invalid_npc: "› {errorColor}NPC named {warningColor}{input}{errorColor} does not exist." + command_unsupported_npc_type: "› This NPC type does not support this feature." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." # Commands fancynpcs_syntax: "{primaryColor}/fancynpcs {secondaryColor}(version|reload|save)" @@ -40,28 +57,26 @@ messages: - "› {primaryColor}/npc remove {secondaryColor}(npc) - Removes specified NPC." - "› {primaryColor}/npc copy {secondaryColor}(npc) (new_name) - Copies/clones specified NPC." - "› {primaryColor}/npc list - Lists all loaded NPCs." - - "› {primaryColor}/npc skin {secondaryColor}(skin) - Changes skin of an NPC." + - "› {primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url) - Changes NPC's skin." - "› {primaryColor}/npc type {secondaryColor}(npc) (type) - Changes entity type of an NPC." - - "› {primaryColor}/npc movehere {secondaryColor}(npc) - Teleports NPC to your location." + - "› {primaryColor}/npc move_here {secondaryColor}(npc) - Teleports NPC to your location." - "› {primaryColor}/npc teleport {secondaryColor}(npc) (x) (y) (z) [world] - Teleports NPC." - "› {primaryColor}/npc displayname {secondaryColor}(npc) (name) - Changes NPC's displayname." - "› {primaryColor}/npc equipment {secondaryColor}(npc) (slot) - Changes equipment of an NPC." - "› {primaryColor}/npc message {secondaryColor}(npc) (...) - Changes click message(s)." - "› {primaryColor}/npc playerCommand {secondaryColor}(npc) (...) - Changes click command(s)." - "› {primaryColor}/npc serverCommand {secondaryColor}(npc) (...) - Changes click command(s)." - - "› {primaryColor}/npc showInTab {secondaryColor}(npc) (state) - Changes tab-list visibility." - - "› {primaryColor}/npc glowing {secondaryColor}(npc) (state) - Changes glowing effect state." - - "› {primaryColor}/npc glowingColor {secondaryColor}(npc) (color) - Changes glowing color." + - "› {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state) - Changes tab-list visibility." + - "› {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color) - Changes glowing state." - "› {primaryColor}/npc collidable {secondaryColor}(npc) (state) - Changes collidable state." - "› {primaryColor}/npc turnToPlayer {secondaryColor}(npc) (state) - Changes turning state." - "› {primaryColor}/npc attribute {secondaryColor}(npc) (attr) (value) - Sets entity attribute." - - "› {primaryColor}/npc interactionCooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." - - "› {primaryColor}/npc mirrorSkin {secondaryColor}(npc) (state) - Changes skin mirroring state." + - "› {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." npc_attribute_syntax: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) (attribute) (value)" npc_attribute_set: "Attribute {primaryColor}{attribute} has been set to {primaryColor}{value}." npc_attribute_invalid_attribute: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid attribute." npc_attribute_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." - npc_attribute_invalid_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not a valid for this entity type." + npc_attribute_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." npc_collidable_syntax: "Syntax: {primaryColor}/npc collidable {secondaryColor}(npc) (state)" npc_collidable_set_true: "NPC named {warningColor}{npc} is now {successColor}collidable." @@ -83,13 +98,11 @@ messages: npc_fix_success: "Attempted to fix NPC named {warningColor}{npc}... Still having issues? Please let us know." - npc_glowing_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (state)" + npc_glowing_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color)" npc_glowing_set_true: "NPC named {warningColor}{npc} is now {successColor}glowing." npc_glowing_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}glowing." - - npc_glowingColor_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (state)" - npc_glowingColor_success: "NPC named {warningColor}{npc} has had their glowing color updated." - npc_glowingColor_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." + npc_glowing_set_color_success: "NPC named {warningColor}{npc} is now glowing in {color}." + npc_glowing_set_color_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." npc_info_syntax: "Syntax: {primaryColor}/npc info {secondaryColor}(npc)" npc_info_general: @@ -124,15 +137,20 @@ messages: npc_info_attributes_entry: "› <#848484>{attribute}: {warningColor}{value}" npc_info_attributes_footer: " " - npc_interactionCooldown_syntax: "Syntax: {primaryColor}/npc interactionCooldown {secondaryColor}(npc) (seconds)" - npc_interactionCooldown_success: "NPC named {warningColor}{npc} has had their interaction cooldown updated." + npc_interaction_cooldown_syntax: "Syntax: {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (seconds)" + npc_interaction_cooldown_success: "NPC named {warningColor}{npc} has had their interaction cooldown updated." - npc_mirrorSkin_syntax: "Syntax: {primaryColor}/npc mirrorSkin {secondaryColor}(npc) (state)" - npc_mirrorSkin_set_true: "NPC named {warningColor}{npc} is now {successColor}mirroring player skin." - npc_mirrorSkin_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}mirroring player skin." + npc_skin_syntax: "Syntax: {primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" + npc_skin_set_name: "NPC named {warningColor}{npc} is now using {warningColor}{name}'s skin." + npc_skin_set_url: "NPC named {warningColor}{npc} is now using skin from specified URL." + npc_skin_set_mirror: "NPC named {warningColor}{npc} is now mirroring player skin." + npc_skin_set_none: "NPC named {warningColor}{npc} is no longer using any skin." + npc_skin_failure_invalid_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is invalid or unsupported URL." + npc_skin_failure_invalid_name_or_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid player name or URL." + npc_skin_failure_invalid_name_or_rate_limit: "› {errorColor}Could not find {warningColor}{input}'s{errorColor} skin. Either the account does not exist or you're being rate limited." - npc_moveHere_syntax: "Syntax: {primaryColor}/npc moveHere {secondaryColor}(npc)" - npc_moveHere_success: "NPC named {warningColor}{npc} has been moved to your location." + npc_move_here_syntax: "Syntax: {primaryColor}/npc move_here {secondaryColor}(npc)" + npc_move_here_success: "NPC named {warningColor}{npc} has been moved to your location." npc_remove_syntax: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" npc_remove_success: "NPC named {warningColor}{npc} has been removed." @@ -144,6 +162,6 @@ messages: npc_turnToPlayer_set_true: "NPC named {warningColor}{npc} is now {successColor}turning to player." npc_turnToPlayer_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}turning to player." - npc_showInTab_syntax: "Syntax: {primaryColor}/npc showInTab {secondaryColor}(npc) (state)" - npc_showInTab_set_true: "NPC named {warningColor}{npc} is now {successColor}shown in player-list." - npc_showInTab_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}shown in player-list." + npc_show_in_tab_syntax: "Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" + npc_show_in_tab_set_true: "NPC named {warningColor}{npc} is now {successColor}shown in player-list." + npc_show_in_tab_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}shown in player-list." From f97e065f5328594594a3e3b87bb3d3ba4e2ec0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 30 Apr 2024 21:59:29 +0200 Subject: [PATCH 41/94] more --- .../commands/CloudCommandManager.java | 6 +- .../fancynpcs/commands/npc/CreateCMD.java | 2 +- .../fancynpcs/commands/npc/ListCMD.java | 89 +++++++---------- .../fancynpcs/commands/npc/MoveToCMD.java | 52 ++++++++++ .../fancynpcs/commands/npc/NearbyCMD.java | 97 +++++++++++++++++++ .../fancynpcs/commands/npc/TeleportCMD.java | 45 ++++----- src/main/resources/languages/en.yml | 38 ++++++-- 7 files changed, 236 insertions(+), 93 deletions(-) create mode 100644 src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java create mode 100644 src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 9d952896..1eeb7f91 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -15,6 +15,8 @@ import de.oliver.fancynpcs.commands.npc.InteractionCooldownCMD; import de.oliver.fancynpcs.commands.npc.ListCMD; import de.oliver.fancynpcs.commands.npc.MoveHereCMD; +import de.oliver.fancynpcs.commands.npc.MoveToCMD; +import de.oliver.fancynpcs.commands.npc.NearbyCMD; import de.oliver.fancynpcs.commands.npc.NpcCMD; import de.oliver.fancynpcs.commands.npc.RemoveCMD; import de.oliver.fancynpcs.commands.npc.ShowInTabCMD; @@ -83,13 +85,15 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig // annotationParser.parse(ServerCommandCMD.INSTANCE); // annotationParser.parse(PlayerCommandCMD.INSTANCE); annotationParser.parse(MoveHereCMD.INSTANCE); + annotationParser.parse(NearbyCMD.INSTANCE); annotationParser.parse(NpcCMD.INSTANCE); annotationParser.parse(TurnToPlayerCMD.INSTANCE); annotationParser.parse(ShowInTabCMD.INSTANCE); + annotationParser.parse(TeleportCMD.INSTANCE); annotationParser.parse(TypeCMD.INSTANCE); annotationParser.parse(RemoveCMD.INSTANCE); annotationParser.parse(SkinCMD.INSTANCE); - annotationParser.parse(TeleportCMD.INSTANCE); + annotationParser.parse(MoveToCMD.INSTANCE); // Returning this instance of CloudCommandManager to keep "builder-like" flow. return this; } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index edc646f1..5bd04043 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -30,7 +30,7 @@ public enum CreateCMD { @Permission("fancynpcs.command.npc.create") public void onCreateCommand(final @NotNull CommandSender sender, final @NotNull @Regex("^[^.]*$") String name, - final @Nullable @Flag("type") @Default("player") EntityType type, + final @Nullable @Flag("type") @Default("player") EntityType type, // NOTE: @Default annotation doesn't work, waiting for a fix. final @Nullable @Flag(value = "position") Location position, final @Nullable @Flag(value = "world") World world ) { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java index 18919c5a..996d125d 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java @@ -1,91 +1,67 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; -import de.oliver.fancynpcs.commands.Subcommand; +import org.bukkit.Location; import org.bukkit.command.CommandSender; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Default; +import org.incendo.cloud.annotations.Flag; +import org.incendo.cloud.annotations.Permission; import java.text.DecimalFormat; -import java.util.Collection; -import java.util.List; +import java.util.Comparator; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; + +public enum ListCMD { + INSTANCE; // SINGLETON -public class ListCMD implements Subcommand { + private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); + private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - return null; + static { + COORDS_FORMAT.setMinimumFractionDigits(2); } @Command("npc list") @Permission("fancynpcs.command.npc.list") public void onCommand( final CommandSender sender, - final @Nullable @Flag("radius") Long radius, final @Nullable @Flag("type") EntityType type, - final @Nullable @Flag("sort") SortType sort + final @Flag("sort") @Default("name") SortType sort // NOTE: @Default annotation doesn't work, waiting for a fix. ) { Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); // Excluding NPCs not created by the sender, if PLAYER_NPCS_FEATURE_FLAG is enabled and sender is a player. if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && sender instanceof Player player) npcs = npcs.filter(npc -> npc.getData().getCreator().equals(player.getUniqueId())); - // Excluding NPCs that are not in radius, if specified and sender is a player. (radius is calculated from the location of player) - if (radius != null && sender instanceof Player player) - npcs = npcs.filter(npc -> npc.getData().getLocation().distance(player.getLocation()) <= radius); // Excluding NPCs that are not of a specified type, if desired. if (type != null) npcs = npcs.filter(npc -> npc.getData().getType() == type); // Sorting... - switch (sort != null ? sort : (sender instanceof Player player) ? SortType.NEAREST : SortType.NAME) { - case NEAREST -> { - if (sender instanceof Player player) - npcs = npcs.sorted(Comparator.comparingDouble(npc -> npc.getData().getLocation().distance(player.getLocation()))); - // ... - else sender.sendMessage("Cannot use SortType.NEAREST from console."); // TODO - } - case FARTHEST -> { - if (sender instanceof Player player) - // This needs a cast for some reason. - npcs = npcs.sorted(Comparator.comparingDouble(npc -> ((Npc) npc).getData().getLocation().distance(player.getLocation())).reversed()); - // ... - else sender.sendMessage("Cannot use SortType.FARTHEST from console."); // TODO - } - case NAME -> { - npcs = npcs.sorted(Comparator.comparing(npc -> npc.getData().getName())); - } - case NAME_REVERSED -> { - // This needs a cast for some reason. - npcs = npcs.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); - } + switch (sort) { + case NAME -> npcs = npcs.sorted(Comparator.comparing(npc -> npc.getData().getName())); + case NAME_REVERSED -> npcs = npcs.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); // This needs a cast for some reason. } translator.translate("npc_list_header").send(sender); - final AtomicInteger count = new AtomicInteger(1); + final AtomicInteger count = new AtomicInteger(0); // ... npcs.toList().forEach(npc -> { - final Location loc = npc.getData().getLocation(); + final Location location = npc.getData().getLocation(); // ... - translator.translate(sender instanceof Player player ? "npc_list_entry_player" : "npc_list_entry") - .replace("num", String.valueOf(count.getAndIncrement())) + translator.translate("npc_list_entry") + .replace("number", String.valueOf(count.incrementAndGet())) .replace("npc", npc.getData().getName()) - .replace("name", npc.getData().getName()) - .replace("id", npc.getData().getId()) - .replace("id_short", npc.getData().getId().substring(0, 13) + "...") - .replace("internal_id", "2") - .replace("creator", npc.getData().getCreator().toString()) - .replace("creator_short", npc.getData().getCreator().toString().substring(0, 13) + "...") - .replace("displayname", npc.getData().getDisplayName()) - .replace("type", npc.getData().getType().toString()) - .replace("location_x", COORDS_FORMAT.format(loc.x())) - .replace("location_y", COORDS_FORMAT.format(loc.y())) - .replace("location_z", COORDS_FORMAT.format(loc.z())) - .replace("distance", (sender instanceof Player player) ? new DecimalFormat("#.#").format(player.getLocation().distance(npc.getData().getLocation())) : "N/A") - .replace("world", loc.getWorld().getName()) + .replace("location_x", COORDS_FORMAT.format(location.x())) + .replace("location_y", COORDS_FORMAT.format(location.y())) + .replace("location_z", COORDS_FORMAT.format(location.z())) + .replace("world", location.getWorld().getName()) .send(sender); }); translator.translate("npc_list_footer") @@ -94,8 +70,9 @@ public void onCommand( .send(sender); } + // SortType enum contains all possible sort types for the '/npc list' command. public enum SortType { - NEAREST, FARTHEST, NAME, NAME_REVERSED + NAME, NAME_REVERSED } } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java new file mode 100644 index 00000000..cc1b9212 --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java @@ -0,0 +1,52 @@ +package de.oliver.fancynpcs.commands.npc; + +import de.oliver.fancylib.translations.Translator; +import de.oliver.fancynpcs.FancyNpcs; +import de.oliver.fancynpcs.api.Npc; +import de.oliver.fancynpcs.api.events.NpcModifyEvent; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; + +import java.text.DecimalFormat; + +import org.jetbrains.annotations.Nullable; + +public enum MoveToCMD { + INSTANCE; // SINGLETON + + private final Translator translator = FancyNpcs.getInstance().getTranslator(); + + private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); + + @Command("npc move_to") + @Permission("fancynpcs.command.npc.move_to") + public void onDefault(final CommandSender sender) { + translator.translate("npc_move_to_syntax").send(sender); + } + + @Command("npc move_to [world]") + @Permission("fancynpcs.command.npc.move_to") + public void onCommand( + final CommandSender sender, + final Npc npc, + final Location location, + final @Nullable World world + ) { + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender).callEvent()) { + npc.getData().setLocation(location); + npc.updateForAll(); + translator.translate("npc_move_to_success") + .replace("npc", npc.getData().getName()) + .replace("x", COORDS_FORMAT.format(location.x())) + .replace("y", COORDS_FORMAT.format(location.y())) + .replace("z", COORDS_FORMAT.format(location.z())) + .replace("world", world.getName()) + .send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + } +} diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java new file mode 100644 index 00000000..df549d29 --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java @@ -0,0 +1,97 @@ +package de.oliver.fancynpcs.commands.npc; + +import de.oliver.fancylib.translations.Translator; +import de.oliver.fancynpcs.FancyNpcs; +import de.oliver.fancynpcs.api.Npc; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Default; +import org.incendo.cloud.annotations.Flag; +import org.incendo.cloud.annotations.Permission; + +import java.text.DecimalFormat; +import java.util.Comparator; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; + +public enum NearbyCMD { + INSTANCE; // SINGLETON + + private final Translator translator = FancyNpcs.getInstance().getTranslator(); + + private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); + private static final DecimalFormat DISTANCE_FORMAT = new DecimalFormat("#.#"); + + static { + COORDS_FORMAT.setMinimumFractionDigits(2); + } + + @Command("npc nearby") + @Permission("fancynpcs.command.npc.nearby") + public void onCommand( + final Player sender, + final @Nullable @Flag("radius") Long radius, + final @Nullable @Flag("type") EntityType type, + final @Nullable @Flag("sort") @Default("nearest") SortType sort // NOTE: @Default annotation doesn't work, waiting for a fix. + ) { + Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); + // Getting location of the sender. + final Location location = sender.getLocation(); + // Creating a counter which is increased by 1 for every NPC present in player's world. + final AtomicInteger totalCount = new AtomicInteger(0); + // Excluding NPCs from different worlds. This also increments the counter defined above. + npcs = npcs.filter(npc -> { + if (npc.getData().getLocation().getWorld().equals(location.getWorld())) { + totalCount.incrementAndGet(); + return true; + } + return false; + }); + // Excluding NPCs not created by the sender, if PLAYER_NPCS_FEATURE_FLAG is enabled and sender is a player. + if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled()) + npcs = npcs.filter(npc -> npc.getData().getCreator().equals(sender.getUniqueId())); + // Excluding NPCs that are not in radius, if specified and sender is a player. (radius is calculated from the location of player) + if (radius != null) + npcs = npcs.filter(npc -> npc.getData().getLocation().distance(location) <= radius); + // Excluding NPCs that are not of a specified type, if desired. + if (type != null) + npcs = npcs.filter(npc -> npc.getData().getType() == type); + // Sorting... + switch (sort) { // This should never produce NPE. + case NAME -> npcs = npcs.sorted(Comparator.comparing(npc -> npc.getData().getName())); + case NAME_REVERSED -> npcs = npcs.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); + case NEAREST -> npcs = npcs.sorted(Comparator.comparingDouble(npc -> npc.getData().getLocation().distance(location))); + case FARTHEST -> npcs = npcs.sorted(Comparator.comparingDouble(npc -> ((Npc) npc).getData().getLocation().distance(location)).reversed()); + } + // Printing the header. + translator.translate("npc_nearby_header").send(sender); + // Creating a counter which is increased by 1 for every NPC that is "selected" in this query. + final AtomicInteger count = new AtomicInteger(0); + // Printing each entry. + npcs.toList().forEach(npc -> { + translator.translate("npc_nearby_entry") + .replace("number", String.valueOf(count.incrementAndGet())) + .replace("npc", npc.getData().getName()) + .replace("distance", DISTANCE_FORMAT.format(npc.getData().getLocation().distance(location))) + .replace("location_x", COORDS_FORMAT.format(npc.getData().getLocation().x())) + .replace("location_y", COORDS_FORMAT.format(npc.getData().getLocation().y())) + .replace("location_z", COORDS_FORMAT.format(npc.getData().getLocation().z())) + .send(sender); + }); + // Printing the footer. + translator.translate("npc_nearby_footer") + .replace("count", String.valueOf(count)) + .replace("total", String.valueOf(totalCount)) + .send(sender); + } + + // SortType enum contains all possible sort types for the '/npc nearby' command. + public enum SortType { + NAME, NAME_REVERSED, NEAREST, FARTHEST + } + +} diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java index 1e396285..8c821007 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java @@ -3,46 +3,39 @@ import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; -import de.oliver.fancynpcs.api.events.NpcModifyEvent; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; -import java.text.DecimalFormat; - -import org.jetbrains.annotations.Nullable; - public enum TeleportCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); - - @Command("npc teleport") + @Command(value = "npc teleport", requiredSender = Player.class) @Permission("fancynpcs.command.npc.teleport") - public void onDefault(final CommandSender sender) { + public void onDefault(final Player sender) { translator.translate("npc_teleport_syntax").send(sender); } - @Command("npc teleport [world]") + @Command(value = "npc teleport ", requiredSender = Player.class) @Permission("fancynpcs.command.npc.teleport") - public void onCommand(final CommandSender sender, final Npc npc, final Location location, final @Nullable World world) { - - if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender).callEvent()) { - npc.getData().setLocation(location); - npc.updateForAll(); - translator.translate("command_invalid_world") - .replace("npc", npc.getData().getName()) - .replace("x", COORDS_FORMAT.format(location.x())) - .replace("y", COORDS_FORMAT.format(location.y())) - .replace("z", COORDS_FORMAT.format(location.z())) - .replace("world", world.getName()) - .send(sender); - } else { - translator.translate("command_npc_modification_cancelled").send(sender); + public void onCommand(final Player sender, final Npc npc) { + final Location location = npc.getData().getLocation(); + // Checking if the world is still loaded. + if (location.getWorld() == null) { + translator.translate("npc_teleport_failure_world_not_loaded").send(sender); + return; } + // Teleporting... + sender.teleportAsync(location).whenComplete((isSuccess, thr) -> { + // Sending message to the sender. + translator.translate(isSuccess ? "npc_teleport_success" : "npc_teleport_failure_exception").replace("npc", npc.getData().getName()).send(sender); + // Printing stacktrace to the console in case an exception occurred. + if (thr != null) + thr.printStackTrace(); + }); } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index c042e0f3..86e14008 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -56,11 +56,13 @@ messages: - "› {primaryColor}/npc create {secondaryColor}(npc) - Creates a new NPC at your location." - "› {primaryColor}/npc remove {secondaryColor}(npc) - Removes specified NPC." - "› {primaryColor}/npc copy {secondaryColor}(npc) (new_name) - Copies/clones specified NPC." - - "› {primaryColor}/npc list - Lists all loaded NPCs." + - "› {primaryColor}/npc list {secondaryColor}[flags...] - Lists all NPCs." + - "› {primaryColor}/npc nearby {secondaryColor}[flags...] - Lists nearby NPCs." - "› {primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url) - Changes NPC's skin." - "› {primaryColor}/npc type {secondaryColor}(npc) (type) - Changes entity type of an NPC." - - "› {primaryColor}/npc move_here {secondaryColor}(npc) - Teleports NPC to your location." - - "› {primaryColor}/npc teleport {secondaryColor}(npc) (x) (y) (z) [world] - Teleports NPC." + - "› {primaryColor}/npc teleport {secondaryColor}(npc) - Teleports you to the NPC." + - "› {primaryColor}/npc move_here {secondaryColor}(npc) - Moves NPC to your location." + - "› {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world] - Moves NPC." - "› {primaryColor}/npc displayname {secondaryColor}(npc) (name) - Changes NPC's displayname." - "› {primaryColor}/npc equipment {secondaryColor}(npc) (slot) - Changes equipment of an NPC." - "› {primaryColor}/npc message {secondaryColor}(npc) (...) - Changes click message(s)." @@ -69,7 +71,7 @@ messages: - "› {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state) - Changes tab-list visibility." - "› {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color) - Changes glowing state." - "› {primaryColor}/npc collidable {secondaryColor}(npc) (state) - Changes collidable state." - - "› {primaryColor}/npc turnToPlayer {secondaryColor}(npc) (state) - Changes turning state." + - "› {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state) - Changes turning state." - "› {primaryColor}/npc attribute {secondaryColor}(npc) (attr) (value) - Sets entity attribute." - "› {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." npc_attribute_syntax: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) (attribute) (value)" @@ -155,12 +157,30 @@ messages: npc_remove_syntax: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" npc_remove_success: "NPC named {warningColor}{npc} has been removed." - npc_teleport_syntax: "Syntax: {primaryColor}/npc teleport {secondaryColor}(npc) (x) (y) (z) [world]" - npc_teleport_success: "NPC named {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." + npc_list_syntax: "Syntax: {primaryColor}/npc list {secondaryColor}[filters...]" + npc_list_header: "Listing results for requested query:" + npc_list_entry: "› <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({location_x}, {location_y}, {location_z} in {world})" + npc_list_footer: "Showing {warningColor}{count} out of total {warningColor}{total} entries in all worlds." - npc_turnToPlayer_syntax: "Syntax: {primaryColor}/npc turnToPlayer {secondaryColor}(npc) (state)" - npc_turnToPlayer_set_true: "NPC named {warningColor}{npc} is now {successColor}turning to player." - npc_turnToPlayer_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}turning to player." + npc_nearby_syntax: "Syntax: {primaryColor}/npc nearby {secondaryColor}[filters...]" + npc_nearby_header: "Listing results for requested query:" + npc_nearby_entry: "› <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({distance} blocks away)" + npc_nearby_footer: "Showing {warningColor}{count} out of total {warningColor}{total} entries in your world." + + npc_list_failure_sort_requires_player: "› {errorColor}This sort type cannot be used from the console." + npc_list_failure_requires_world_flag: "› {errorColor}You must specify a {warningColor}--world{errorColor} flag when running this command from the console." + + npc_move_to_syntax: "Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" + npc_move_to_success: "NPC named {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." + + npc_teleport_syntax: "Syntax: {primaryColor}/npc teleport {secondaryColor}(npc)" + npc_teleport_success: "You have been teleported to NPC named {warningColor}{npc}." + npc_teleport_failure_exception: "› {errorColor}An error occurred while trying to teleport to NPC. Check console for errors." + npc_teleport_failure_world_not_loaded: "› {errorColor}An error occurred while trying to teleport to NPC. Destination world is not loaded." + + npc_turn_to_player_syntax: "Syntax: {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" + npc_turn_to_player_set_true: "NPC named {warningColor}{npc} is now {successColor}turning to player." + npc_turn_to_player_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}turning to player." npc_show_in_tab_syntax: "Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" npc_show_in_tab_set_true: "NPC named {warningColor}{npc} is now {successColor}shown in player-list." From 0bed9a34619eb30790ac1c51d4c97cd35e7fdd38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 1 May 2024 01:32:56 +0200 Subject: [PATCH 42/94] port /fancynpcs --- .../java/de/oliver/fancynpcs/FancyNpcs.java | 12 +-- .../commands/CloudCommandManager.java | 9 ++ .../fancynpcs/commands/FancyNpcsCMD.java | 101 +++++++++--------- src/main/resources/languages/en.yml | 11 +- 4 files changed, 75 insertions(+), 58 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index d63cd8dd..7f922a03 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -21,7 +21,6 @@ import de.oliver.fancynpcs.api.NpcData; import de.oliver.fancynpcs.api.NpcManager; import de.oliver.fancynpcs.commands.CloudCommandManager; -import de.oliver.fancynpcs.commands.FancyNpcsCMD; import de.oliver.fancynpcs.listeners.PlayerChangedWorldListener; import de.oliver.fancynpcs.listeners.PlayerJoinListener; import de.oliver.fancynpcs.listeners.PlayerNpcsListener; @@ -58,6 +57,7 @@ public class FancyNpcs extends JavaPlugin implements FancyNpcsPlugin { private final VersionConfig versionConfig; private final FeatureFlagConfig featureFlagConfig; private final VersionFetcher versionFetcher; + private CloudCommandManager commandManager; private TextConfig textConfig; private Translator translator; private Function npcAdapter; @@ -188,8 +188,6 @@ public void onEnable() { PluginManager pluginManager = Bukkit.getPluginManager(); usingPlotSquared = pluginManager.isPluginEnabled("PlotSquared"); - this.getServer().getCommandMap().register("fancynpcs", new FancyNpcsCMD()); - // register listeners pluginManager.registerEvents(new PlayerJoinListener(), instance); pluginManager.registerEvents(new PlayerQuitListener(), instance); @@ -223,9 +221,7 @@ public void onEnable() { scheduler.runTaskTimerAsynchronously(60L * 20L, autosaveInterval * 60L * 20L, () -> npcManager.saveNpcs(false)); } // Creating new instance of CloudCommandManager and registering commands. - // NOTE: Brigadier is a bit bugged currently, should be disabled by default for the time being. - // - final CloudCommandManager cloud = new CloudCommandManager(this, false).registerCommands(); + commandManager = new CloudCommandManager(this, false).registerCommands(); } @Override @@ -273,6 +269,10 @@ public VersionConfig getVersionConfig() { return versionConfig; } + public CloudCommandManager getCommandManager() { + return commandManager; + } + public Translator getTranslator() { return translator; } diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 1eeb7f91..d63f9769 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -71,6 +71,7 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig * Registers plugin commands to the {@link PaperCommandManager}. */ public @NotNull CloudCommandManager registerCommands() { + annotationParser.parse(FancyNpcsCMD.INSTANCE); annotationParser.parse(AttributeCMD.INSTANCE); annotationParser.parse(CollidableCMD.INSTANCE); annotationParser.parse(CreateCMD.INSTANCE); @@ -98,6 +99,14 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig return this; } + /** + * Unregisters plugin commands from the {@link PaperCommandManager}. + */ + public void unregisterCommands() { + commandManager.deleteRootCommand("fancynpcs"); + commandManager.deleteRootCommand("npc"); + } + /** * Returns the internal {@link PaperCommandManager} associated with this instance of {@link CloudCommandManager}. */ diff --git a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java index e23bcb90..8ced1247 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java @@ -1,70 +1,75 @@ package de.oliver.fancynpcs.commands; import de.oliver.fancylib.translations.Translator; +import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; - -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; import org.jetbrains.annotations.NotNull; -public class FancyNpcsCMD extends Command { +public enum FancyNpcsCMD { + INSTANCE; // SINGLETON + private final FancyNpcs plugin = FancyNpcs.getInstance(); private final Translator translator = FancyNpcs.getInstance().getTranslator(); - public FancyNpcsCMD() { - super("fancynpcs"); - setPermission("fancynpcs.admin"); + @Command("fancynpcs") + @Permission("fancynpcs.command.fancynpcs") + public void onDefault(final CommandSender sender) { + translator.translate("fancynpcs_syntax").send(sender); } - @Override - public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { - - if (args.length == 1) { - return Stream.of("version", "reload", "save", "featureFlags") - .filter(input -> input.toLowerCase().startsWith(args[0].toLowerCase())) - .toList(); - } - - return Collections.emptyList(); + @Command("fancynpcs version") + @Permission("fancynpcs.command.fancynpcs.version") + public void onVersion(final CommandSender sender) { + plugin.getVersionConfig().checkVersionAndDisplay(sender, false); } - @Override - public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { - if (!testPermission(sender)) - return false; + @Command("fancynpcs reload") + @Permission("fancynpcs.command.fancynpcs.reload") + public void onReload(final CommandSender sender) { + // Reloading all defined languages. + translator.loadLanguages(plugin.getDataFolder().getAbsolutePath()); + // Reloading configuration + plugin.getFancyNpcConfig().reload(); + // Updating the selected language obtained from configuration. + translator.setSelectedLanguage(translator.getFallbackLanguage()); // WIP: Make it configurable. + // Reloading all NPCs. + plugin.getNpcManagerImpl().reloadNpcs(); + // Sending success message to the sender. + translator.translate("fancynpcs_reload_success").send(sender); + } - final FancyNpcs plugin = FancyNpcs.getInstance(); + @Command("fancynpcs save") + @Permission("fancynpcs.command.fancynpcs.save") + public void onSave(final CommandSender sender) { + // Saving all NPCs. + plugin.getNpcManagerImpl().saveNpcs(true); + // Sending success message to the sender. + translator.translate("fancynpcs_save_success").send(sender); + } - if (args.length >= 1) { - switch (args[0].toLowerCase()) { - case "version" -> FancyNpcs.getInstance().getVersionConfig().checkVersionAndDisplay(sender, false); - case "reload" -> { - translator.loadLanguages(plugin.getDataFolder().getAbsolutePath()); - plugin.getFancyNpcConfig().reload(); - plugin.getNpcManagerImpl().reloadNpcs(); - translator.translate("fancynpcs_reload_success").send(sender); - } - case "save" -> { - plugin.getNpcManagerImpl().saveNpcs(true); - translator.translate("fancynpcs_save_success").send(sender); - } - case "featureflags" -> { - translator.translate("Feature Flags:").send(sender); - translator.translate("› Player NPCs: " + getFormattedBoolean(FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled())).send(sender); - } - } - return true; - } - translator.translate("fancynpcs_syntax").send(sender); - return false; + @Command("fancynpcs feature_flags") + @Permission("fancynpcs.command.fancynpcs.feature_flags") + public void onFeatureFlags(final CommandSender sender) { + // Printing the header of the list. + translator.translate("fancynpcs_feature_flags_header").send(sender); + // Printing status of all existing feature flags. + translator.translate("fancynpcs_feature_flags_entry") + .replace("number", "1") + .replace("name", "Player NPCs") + .replace("id", FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.getName()) + .replace("state", getTranslatedState(FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled())) + .send(sender); + // Printing the footer of the list. + translator.translate("fancynpcs_feature_flags_footer").send(sender); } - private static @NotNull String getFormattedBoolean(final boolean bool) { - return (bool) ? "ON" : "OFF"; + // NOTE: Might need to be improved later down the line, should get work done for now. + private @NotNull String getTranslatedState(final boolean bool) { + return (bool) ? ((SimpleMessage) translator.translate("enabled")).getMessage() : ((SimpleMessage) translator.translate("disabled")).getMessage(); } } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 86e14008..c5a23e14 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -4,7 +4,9 @@ language_name: english messages: # Common (States) true: "{successColor}True" + enabled: "{successColor}Enabled" false: "{errorColor}False" + disabled: "{errorColor}Disabled" # Common (Equipment Slots) main_hand: "Main Hand" off_hand: "Off Hand" @@ -44,12 +46,13 @@ messages: command_unsupported_npc_type: "› This NPC type does not support this feature." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." # Commands - fancynpcs_syntax: "{primaryColor}/fancynpcs {secondaryColor}(version|reload|save)" + fancynpcs_syntax: "Syntax: {primaryColor}/fancynpcs {secondaryColor}(version | reload | save | feature_flags)" fancynpcs_reload_success: "› {successColor}Plugin has been reloaded." - fancynpcs_save_success: "› {successColor}NPCs has been saved." + fancynpcs_save_success: "› {successColor}NPCs have been saved." fancynpcs_version: "" # NOT CONFIGURABLE - fancynpcs_feature_flags_header: "" # NOT CONFIGURABLE - fancynpcs_feature_flags_entry: "" # NOT CONFIGURABLE + fancynpcs_feature_flags_header: "Feature Flags:" + fancynpcs_feature_flags_entry: "› <#848484>{number}. {warningColor}{name} <#848484>({id}): {state}" + fancynpcs_feature_flags_footer: "" npc_help_page_header: "Commands for {primaryColor}FancyNpcs plugin: ({primaryColor}{page}/{primaryColor}{max_page})" npc_help_page_footer: "Full command reference available {primaryColor}here." npc_help_contents: From d29880ad13f60d028f4e51f418855495506b3cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 4 May 2024 14:35:30 +0200 Subject: [PATCH 43/94] half-baked `/npc message` command --- api/build.gradle.kts | 14 +- .../fancynpcs/api/events/NpcModifyEvent.java | 37 +- build.gradle.kts | 8 +- .../commands/CloudCommandManager.java | 3 +- .../fancynpcs/commands/npc/MessageCMD.java | 412 ++++++------------ src/main/resources/languages/en.yml | 35 +- 6 files changed, 208 insertions(+), 301 deletions(-) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index a6dc3a68..92de412c 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -4,21 +4,17 @@ plugins { id("com.github.johnrengelman.shadow") version "8.1.1" } +repositories { + maven(url = "https://repo.smrt-1.com/releases") +} + dependencies { compileOnly("io.papermc.paper:paper-api:${findProperty("minecraftVersion")}-R0.1-SNAPSHOT") - compileOnly("de.oliver:FancyLib:${findProperty("fancyLibVersion")}") - - implementation("me.dave:ChatColorHandler:${findProperty("chatcolorhandlerVersion")}") + compileOnly("me.dave:ChatColorHandler:${findProperty("chatcolorhandlerVersion")}") } tasks { - shadowJar { - archiveClassifier.set("") - - relocate("me.dave.chatcolorhandler", "de.oliver.fancynpcs.libs.chatcolorhandler") - } - publishing { repositories { maven { diff --git a/api/src/main/java/de/oliver/fancynpcs/api/events/NpcModifyEvent.java b/api/src/main/java/de/oliver/fancynpcs/api/events/NpcModifyEvent.java index 552a0594..fc8f3670 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/events/NpcModifyEvent.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/events/NpcModifyEvent.java @@ -78,21 +78,38 @@ public void setCancelled(boolean cancel) { } public enum NpcModification { - LOCATION, - SKIN, + ATTRIBUTE, + COLLIDABLE, DISPLAY_NAME, EQUIPMENT, - SERVER_COMMAND, - PLAYER_COMMAND, - SHOW_IN_TAB, GLOWING, GLOWING_COLOR, - TURN_TO_PLAYER, - CUSTOM_MESSAGE, - TYPE, - ATTRIBUTE, - COLLIDABLE, INTERACTION_COOLDOWN, + LOCATION, MIRROR_SKIN, + PLAYER_COMMAND, + SERVER_COMMAND, + SHOW_IN_TAB, + SKIN, + TURN_TO_PLAYER, + TYPE, + // Messages. + MESSAGE_ADD, + MESSAGE_SET, + MESSAGE_REMOVE, + MESSAGE_CLEAR, + MESSAGE_SEND_RANDOMLY, + // Player commands. + PLAYER_COMMAND_ADD, + PLAYER_COMMAND_SET, + PLAYER_COMMAND_REMOVE, + PLAYER_COMMAND_CLEAR, + PLAYER_COMMAND_SEND_RANDOMLY, + // Server commands. + SERVER_COMMAND_ADD, + SERVER_COMMAND_SET, + SERVER_COMMAND_REMOVE, + SERVER_COMMAND_CLEAR, + SERVER_COMMAND_SEND_RANDOMLY } } diff --git a/build.gradle.kts b/build.gradle.kts index a3ec9a46..353aa578 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,17 +27,18 @@ allprojects { } dependencies { + api(project(":api")) + compileOnly("io.papermc.paper:paper-api:${findProperty("minecraftVersion")}-R0.1-SNAPSHOT") - implementation(project(":api")) implementation(project(":implementation_1_20_4", configuration = "reobf")) implementation(project(":implementation_1_20_2", configuration = "reobf")) implementation(project(":implementation_1_20_1", configuration = "reobf")) implementation(project(":implementation_1_20", configuration = "reobf")) implementation(project(":implementation_1_19_4", configuration = "reobf")) - implementation("de.oliver:FancyLib:${findProperty("fancyLibVersion")}") implementation("me.dave:ChatColorHandler:${findProperty("chatcolorhandlerVersion")}") + implementation("de.oliver:FancyLib:${findProperty("fancyLibVersion")}") implementation("org.incendo:cloud-core:${findProperty("cloudVersion")}") implementation("org.incendo:cloud-paper:${findProperty("cloudVersion")}") implementation("org.incendo:cloud-annotations:${findProperty("cloudVersion")}") @@ -59,10 +60,7 @@ tasks { shadowJar { archiveClassifier.set("") - dependsOn(":api:shadowJar") - - relocate("me.dave.chatcolorhandler", "de.oliver.fancynpcs.libs.chatcolorhandler") relocate("io.sentry", "de.oliver.fancynpcs.libs.sentry") } diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index d63f9769..48ba0f2c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -14,6 +14,7 @@ import de.oliver.fancynpcs.commands.npc.InfoCMD; import de.oliver.fancynpcs.commands.npc.InteractionCooldownCMD; import de.oliver.fancynpcs.commands.npc.ListCMD; +import de.oliver.fancynpcs.commands.npc.MessageCMD; import de.oliver.fancynpcs.commands.npc.MoveHereCMD; import de.oliver.fancynpcs.commands.npc.MoveToCMD; import de.oliver.fancynpcs.commands.npc.NearbyCMD; @@ -82,7 +83,7 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig annotationParser.parse(InfoCMD.INSTANCE); annotationParser.parse(InteractionCooldownCMD.INSTANCE); annotationParser.parse(ListCMD.INSTANCE); - // annotationParser.parse(MessageCMD.INSTANCE); + annotationParser.parse(MessageCMD.INSTANCE); // annotationParser.parse(ServerCommandCMD.INSTANCE); // annotationParser.parse(PlayerCommandCMD.INSTANCE); annotationParser.parse(MoveHereCMD.INSTANCE); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index fbd2cee1..23e449ea 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -1,307 +1,183 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; +import me.dave.chatcolorhandler.ModernChatColorHandler; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentIteratorType; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.ClickEvent.Action; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.incendo.cloud.annotation.specifier.Greedy; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; -import java.util.LinkedList; import java.util.List; -import java.util.Queue; +import java.util.stream.StreamSupport; -public class MessageCMD implements Subcommand { - - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return List.of("add", "set", "remove", "clear", "sendRandomly"); - } else if (args.length == 4) { - if (args[2].equalsIgnoreCase("set") || args[2].equalsIgnoreCase("remove")) { - List messages = new LinkedList<>(); - for (int i = 0; i < npc.getData().getMessages().size(); i++) { - messages.add(String.valueOf(i + 1)); - } - return messages; - } else if (args[2].equalsIgnoreCase("sendRandomly")) { - return List.of("true", "false"); - } - } else if (args.length == 5) { - if (args[2].equalsIgnoreCase("set")) { - int index; - try { - index = Integer.parseInt(args[3]); - } catch (NumberFormatException e) { - return null; - } +public enum MessageCMD { + INSTANCE; // SINGLETON - if (index < 1 || index > npc.getData().getMessages().size()) { - return null; - } + private final Translator translator = FancyNpcs.getInstance().getTranslator(); - return List.of(npc.getData().getMessages().get(index - 1)); - } - } - - return null; + @Command("npc message add") + @Permission("fancynpcs.command.npc.message.add") + public void onMessageAdd(final CommandSender sender, final Npc npc) { + translator.translate("npc_message_add_syntax").send(sender); } - @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); - return false; - } - - if (args.length == 3 && args[2].equalsIgnoreCase("clear")) { - return clearMessages(receiver, npc, args); - } - - if (args.length == 4 && args[2].equalsIgnoreCase("sendRandomly")) { - return sendMessagesRandomly(receiver, npc, args); - } - - if (args.length == 4 && args[2].equalsIgnoreCase("remove")) { - return removeMessage(receiver, npc, args); - } - - if (args.length >= 4 && args[2].equalsIgnoreCase("add")) { - return addMessage(receiver, npc, args); - } - - if (args.length >= 5 && args[2].equalsIgnoreCase("set")) { - return setMessage(receiver, npc, args); - } - - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - private boolean sendMessagesRandomly(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 4) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); - return false; - } - - boolean sendMessagesRandomly; - try { - sendMessagesRandomly = Boolean.parseBoolean(args[3]); - } catch (Exception e) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.CUSTOM_MESSAGE, sendMessagesRandomly, receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().setSendMessagesRandomly(sendMessagesRandomly); - - if (sendMessagesRandomly) { - MessageHelper.success(receiver, lang.get("npc-command-message-sendMessagesRandomly-true", "npc", npc.getData().getName())); - } else { - MessageHelper.success(receiver, lang.get("npc-command-message-sendMessagesRandomly-false", "npc", npc.getData().getName())); - npc.updateForAll(); // move to default pos - } + @Command("npc message add ") + @Permission("fancynpcs.command.npc.message.add") + public void onMessageAdd(final CommandSender sender, final Npc npc, final @Greedy String message) { + // Exiting the command block in case banned command has been found in the message. + if (hasBlockedCommands(message)) { + translator.translate("command_input_contains_blocked_command").send(sender); + return; + } + // ... + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SET, message, sender).callEvent()) { + npc.getData().getMessages().add(message); + // ... + translator.translate("npc_message_add_success").replace("total", String.valueOf(npc.getData().getMessages().size())).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } - private boolean addMessage(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - String message = ""; - for (int i = 3; i < args.length; i++) { - message += args[i] + " "; - } - - message = message.substring(0, message.length() - 1); - - if (message.equalsIgnoreCase("none")) { - message = ""; - } - - if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && hasIllegalCommand(message.toLowerCase())) { - MessageHelper.error(receiver, lang.get("illegal-command")); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.CUSTOM_MESSAGE, message, receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().addMessage(message); - MessageHelper.success(receiver, lang.get("npc-command-message-updated", "npc", npc.getData().getName())); + @Command("npc message set ") + @Permission("fancynpcs.command.npc.message.set") + public void onMessageSet(final CommandSender sender, final Npc npc, final int number, final @Greedy String message) { + // Sending error message in case banned command has been found in the message. + if (hasBlockedCommands(message)) { + translator.translate("command_input_contains_blocked_command").send(sender); + return; + } + // Getting the total count of messages that are currently in the list. + final int totalCount = npc.getData().getMessages().size(); + // Sending error message if the list is empty. + if (totalCount == 0) { + translator.translate("npc_message_set_failure_list_is_empty").send(sender); + return; + } + // Sending error message Exiting command block if provided number is lower than 0 or higher than the list size. + if (number < 1 || number > totalCount) { + translator.translate("npc_message_set_failure_not_in_range").replace("input", String.valueOf(number)).replace("max", String.valueOf(totalCount)).send(sender); + return; + } + // User-specified number starts from 1, while index starts from 0. Subtracting 1 from the provided number to get the list index. + final int index = number - 1; + // ... + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SET, new Object[]{index, message}, sender).callEvent()) { + npc.getData().getMessages().set(index, message); + // ... + translator.translate("npc_message_set_success") + .replace("number", String.valueOf(number)) + .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. + .send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } - private boolean setMessage(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 4) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - int index; - try { - index = Integer.parseInt(args[3]); - } catch (NumberFormatException e) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - if (index < 1 || index > npc.getData().getMessages().size()) { - MessageHelper.error(receiver, lang.get("npc-command-message-invalid-index", "input", String.valueOf(index))); - return false; - } - - String message = ""; - for (int i = 4; i < args.length; i++) { - message += args[i] + " "; - } - - message = message.substring(0, message.length() - 1); - - if (message.equalsIgnoreCase("none")) { - message = ""; - } - - if (hasIllegalCommand(message.toLowerCase())) { - MessageHelper.error(receiver, lang.get("illegal-command")); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.CUSTOM_MESSAGE, message, receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().getMessages().set(index - 1, message); - MessageHelper.success(receiver, lang.get("npc-command-message-updated", "npc", npc.getData().getName())); - } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); - } - - return true; + @Command("npc message remove") + @Permission("fancynpcs.command.npc.message.remove") + public void onMessageRemoveSyntax(final CommandSender sender, final Npc npc) { + translator.translate("npc_message_remove_syntax").send(sender); } - private boolean removeMessage(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - int index; - try { - index = Integer.parseInt(args[3]); - } catch (NumberFormatException e) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - if (index < 1 || index > npc.getData().getMessages().size()) { - MessageHelper.error(receiver, lang.get("npc-command-message-invalid-index", "input", String.valueOf(index))); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.CUSTOM_MESSAGE, "", receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().removeMessage(index - 1); - MessageHelper.success(receiver, lang.get("npc-command-message-updated", "npc", npc.getData().getName())); + @Command("npc message remove ") + @Permission("fancynpcs.command.npc.message.remove") + public void onMessageRemove(final CommandSender sender, final Npc npc, final int number) { + // Getting the total count of messages that are currently in the list. + final int totalCount = npc.getData().getMessages().size(); + // Sending error message if the list is empty. + if (totalCount == 0) { + translator.translate("npc_message_remove_failure_list_is_empty").send(sender); + return; + } + // Sending error message Exiting command block if provided number is lower than 0 or higher than the list size. + if (number < 1 || number > totalCount) { + translator.translate("npc_message_remove_failure_not_in_range").replace("input", String.valueOf(number)).replace("max", String.valueOf(totalCount)).send(sender); + return; + } + // User-specified number starts from 1, while index starts from 0. Subtracting 1 from the provided number to get the list index. + final int index = number - 1; + // Getting the message to pass to the NpcModifyEvent. + final String message = npc.getData().getMessages().get(index); + // ... + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_REMOVE, new Object[]{index, message}, sender).callEvent()) { + npc.getData().getMessages().remove(index); + // ... + translator.translate("npc_message_remove_success") + .replace("number", String.valueOf(number)) + .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. + .send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } - private boolean clearMessages(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 2) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.CUSTOM_MESSAGE, "", receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { + @Command("npc message clear") + @Permission("fancynpcs.command.npc.message.clear") + public void onMessageClear(final CommandSender sender, final Npc npc) { + final int total = npc.getData().getMessages().size(); + // ... + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_CLEAR, null, sender).callEvent()) { npc.getData().getMessages().clear(); - MessageHelper.success(receiver, lang.get("npc-command-message-updated", "npc", npc.getData().getName())); + translator.translate("npc_message_clear_success").replace("total", String.valueOf(total)).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } - // TEST - private boolean hasIllegalCommand(String message) { - message = message.replace("/", ""); + @Command("npc message list") + @Permission("fancynpcs.command.npc.message.list") + public void onMessageList(final CommandSender sender, final Npc npc) { + throw new UnsupportedOperationException("NOT IMPLEMENTED"); + } - char[] chars = message.toCharArray(); - Queue tokens = new LinkedList<>(); - List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); - String currentWord = ""; - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - if (c == ' ') { - if (!currentWord.equals(" ") && !currentWord.equals("")) - tokens.add(currentWord); - currentWord = ""; - } else if (c == '<' || c == '>' || c == ':') { - if (!currentWord.equals(" ") && !currentWord.equals("")) - tokens.add(currentWord); - tokens.add(String.valueOf(c)); - currentWord = ""; - } else { - currentWord = currentWord + c; - } + @Command("npc message send_randomly [state]") + @Permission("fancynpcs.command.npc.message.send_randomly") + public void onMessageSendRandomly(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + final boolean finalState = state != null ? state : !npc.getData().isSendMessagesRandomly(); + // ... + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SEND_RANDOMLY, finalState, sender).callEvent()) { + npc.getData().setSendMessagesRandomly(finalState); + npc.updateForAll(); + translator.translate(finalState ? "npc_message_send_randomly_set_true" : "npc_message_send_randomly_set_false").replace("npc", npc.getData().getName()).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); } - if (currentWord.length() > 0 && !currentWord.equals(" ")) - tokens.add(currentWord); + } - while (!tokens.isEmpty()) { - if (((String) tokens.poll()).equalsIgnoreCase("run_command") && ((String) tokens.poll()).equalsIgnoreCase(":")) { - String command = tokens.poll(); - command = command.replace("\"", ""); - command = command.replace("'", ""); - command = command.replace("´", ""); - command = command.replace("`", ""); - for (String blockedCommand : blockedCommands) { - if (command.toLowerCase().startsWith(blockedCommand.toLowerCase())) { - return true; - } - } + // Returns 'true' if specified component contains blocked command, 'false' otherwise. + private boolean hasBlockedCommands(final @NotNull String message) { + // Converting message to a Component. + final Component component = ModernChatColorHandler.translate(message); + // Getting the list of all blocked commands. + final List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); + // Iterating over all children of the component... + return StreamSupport.stream(component.iterable(ComponentIteratorType.DEPTH_FIRST).spliterator(), false).anyMatch(it -> { + final ClickEvent event = it.clickEvent(); + // We only care about click events with run_command as an action. Continuing if not found. + if (event == null || event.action() != Action.RUN_COMMAND) + return false; + // Iterating over list of blocked commands... + for (final String blockedCommand : blockedCommands) { + // Transforming the command to a base command with trailed whitespaces and slashes. This also removes namespaced part from the beginning of the command. + final String transformedBaseCommand = blockedCommand.replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", ""); + // Comparing click event value with the transformed base command. Returning the result. + if (event.value().replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", "").equalsIgnoreCase(transformedBaseCommand)) + return true; } - } - - return false; + // Returning false as no blocked commands has been found. + return false; + }); } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index c5a23e14..c16be97c 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -44,6 +44,7 @@ messages: command_invalid_world: "› {errorColor}World named {warningColor}{input}{errorColor} does not exist." command_invalid_npc: "› {errorColor}NPC named {warningColor}{input}{errorColor} does not exist." command_unsupported_npc_type: "› This NPC type does not support this feature." + command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." # Commands fancynpcs_syntax: "Syntax: {primaryColor}/fancynpcs {secondaryColor}(version | reload | save | feature_flags)" @@ -84,8 +85,8 @@ messages: npc_attribute_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." npc_collidable_syntax: "Syntax: {primaryColor}/npc collidable {secondaryColor}(npc) (state)" - npc_collidable_set_true: "NPC named {warningColor}{npc} is now {successColor}collidable." - npc_collidable_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}collidable." + npc_collidable_set_true: "NPC named {warningColor}{npc} is now collidable." + npc_collidable_set_false: "NPC named {warningColor}{npc} is no longer collidable." npc_copy_syntax: "Syntax: {primaryColor}/npc copy {secondaryColor}(npc) (new_name)" npc_copy_success: "NPC named {warningColor}{npc} has been copied to {warningColor}{new_npc}." @@ -104,8 +105,8 @@ messages: npc_fix_success: "Attempted to fix NPC named {warningColor}{npc}... Still having issues? Please let us know." npc_glowing_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color)" - npc_glowing_set_true: "NPC named {warningColor}{npc} is now {successColor}glowing." - npc_glowing_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}glowing." + npc_glowing_set_true: "NPC named {warningColor}{npc} is now glowing." + npc_glowing_set_false: "NPC named {warningColor}{npc} is no longer glowing." npc_glowing_set_color_success: "NPC named {warningColor}{npc} is now glowing in {color}." npc_glowing_set_color_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." @@ -182,9 +183,27 @@ messages: npc_teleport_failure_world_not_loaded: "› {errorColor}An error occurred while trying to teleport to NPC. Destination world is not loaded." npc_turn_to_player_syntax: "Syntax: {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" - npc_turn_to_player_set_true: "NPC named {warningColor}{npc} is now {successColor}turning to player." - npc_turn_to_player_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}turning to player." + npc_turn_to_player_set_true: "NPC named {warningColor}{npc} is now turning to player." + npc_turn_to_player_set_false: "NPC named {warningColor}{npc} is no longer turning to player." npc_show_in_tab_syntax: "Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" - npc_show_in_tab_set_true: "NPC named {warningColor}{npc} is now {successColor}shown in player-list." - npc_show_in_tab_set_false: "NPC named {warningColor}{npc} is no longer {errorColor}shown in player-list." + npc_show_in_tab_set_true: "NPC named {warningColor}{npc} is now shown in player-list." + npc_show_in_tab_set_false: "NPC named {warningColor}{npc} is no longer shown in player-list." + + npc_message_add_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) add (none | message)" + npc_message_add_success: "Message has been added. There is {warningColor}{total} messages in total." + + npc_message_set_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) set (number) (none | message)" + npc_message_set_success: "Message {warningColor}{number} has been updated. There is {warningColor}{total} messages in total." + npc_message_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." + npc_message_set_failure_list_is_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." + + npc_message_remove_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) remove (number)" + npc_message_remove_success: "Message {warningColor}{number} has been removed. There is {warningColor}{total} messages in total." + npc_message_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." + npc_message_remove_failure_list_is_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." + + npc_message_clear_success: "Messages have been cleared. There was {warningColor}{total} messages in total." + + npc_message_send_randomly_set_true: "NPC named {warningColor}{npc} is now sending messages randomly." + npc_message_send_randomly_set_false: "NPC named {warningColor}{npc} is no longer sending messages randomly." From 6a55f870d3b982467e2d9b471eb4653cff0bfb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 4 May 2024 15:08:51 +0200 Subject: [PATCH 44/94] fix `npc_attribute_set` color --- src/main/resources/languages/en.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index c16be97c..2ef4c6f1 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -54,7 +54,7 @@ messages: fancynpcs_feature_flags_header: "Feature Flags:" fancynpcs_feature_flags_entry: "› <#848484>{number}. {warningColor}{name} <#848484>({id}): {state}" fancynpcs_feature_flags_footer: "" - npc_help_page_header: "Commands for {primaryColor}FancyNpcs plugin: ({primaryColor}{page}/{primaryColor}{max_page})" + npc_help_page_header: "―――――― {primaryColor}FancyNpcs plugin help: ({primaryColor}{page}/{primaryColor}{max_page})" npc_help_page_footer: "Full command reference available {primaryColor}here." npc_help_contents: - "› {primaryColor}/npc create {secondaryColor}(npc) - Creates a new NPC at your location." @@ -79,7 +79,7 @@ messages: - "› {primaryColor}/npc attribute {secondaryColor}(npc) (attr) (value) - Sets entity attribute." - "› {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." npc_attribute_syntax: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) (attribute) (value)" - npc_attribute_set: "Attribute {primaryColor}{attribute} has been set to {primaryColor}{value}." + npc_attribute_set: "Attribute {warningColor}{attribute} has been set to {warningColor}{value}." npc_attribute_invalid_attribute: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid attribute." npc_attribute_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." npc_attribute_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." From dbaf665eed499c626e90e1487aa43f678079f090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 4 May 2024 15:14:13 +0200 Subject: [PATCH 45/94] stricter regex for new NPC names --- src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index 5bd04043..35604e20 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -29,7 +29,7 @@ public enum CreateCMD { @Command("npc create ") @Permission("fancynpcs.command.npc.create") public void onCreateCommand(final @NotNull CommandSender sender, - final @NotNull @Regex("^[^.]*$") String name, + final @NotNull @Regex("^[A-Za-z0-9_-]*$") String name, final @Nullable @Flag("type") @Default("player") EntityType type, // NOTE: @Default annotation doesn't work, waiting for a fix. final @Nullable @Flag(value = "position") Location position, final @Nullable @Flag(value = "world") World world From aeada4a36532196f7961b8b6853ca00570ac4f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 4 May 2024 15:22:57 +0200 Subject: [PATCH 46/94] temp fix for default flag values --- .../de/oliver/fancynpcs/commands/npc/CreateCMD.java | 10 +++++----- .../java/de/oliver/fancynpcs/commands/npc/ListCMD.java | 5 ++--- .../de/oliver/fancynpcs/commands/npc/NearbyCMD.java | 7 +++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index 35604e20..a853e6e1 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -11,7 +11,6 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; -import org.incendo.cloud.annotations.Default; import org.incendo.cloud.annotations.Flag; import org.incendo.cloud.annotations.Permission; import org.incendo.cloud.annotations.Regex; @@ -30,14 +29,15 @@ public enum CreateCMD { @Permission("fancynpcs.command.npc.create") public void onCreateCommand(final @NotNull CommandSender sender, final @NotNull @Regex("^[A-Za-z0-9_-]*$") String name, - final @Nullable @Flag("type") @Default("player") EntityType type, // NOTE: @Default annotation doesn't work, waiting for a fix. - final @Nullable @Flag(value = "position") Location position, - final @Nullable @Flag(value = "world") World world + final @Nullable @Flag("type") EntityType type, // NOTE: Replace with @Default once fixed. + final @Nullable @Flag("position") Location position, + final @Nullable @Flag("world") World world ) { if (FancyNpcs.getInstance().getNpcManager().getNpc(name) != null) { translator.translate("npc_create_failure_already_exists").replace("npc", FancyNpcs.getInstance().getNpcManager().getNpc(name).getData().getName()).send(sender); return; } + final EntityType finalType = (type != null) ? type : EntityType.PLAYER; // Getting the Location where NPC will be created at. final Location location = (position == null && sender instanceof Player player) ? player.getLocation() : position; // Setting the world of specified location. @@ -50,7 +50,7 @@ public void onCreateCommand(final @NotNull CommandSender sender, } final Npc npc = FancyNpcs.getInstance().getNpcAdapter().apply(new NpcData(name, (sender instanceof Player player) ? player.getUniqueId() : UUID.nameUUIDFromBytes(new byte[0]), location)); // Setting the type of NPC. Default type is EntityType.PLAYER. - npc.getData().setType(type); // TO-DO: FIX IT + npc.getData().setType(finalType); // Calling event and creating NPC if not cancelled, sending error message otherwise. if (new NpcCreateEvent(npc, sender).callEvent()) { npc.create(); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java index 996d125d..ab8505b6 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java @@ -8,7 +8,6 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; -import org.incendo.cloud.annotations.Default; import org.incendo.cloud.annotations.Flag; import org.incendo.cloud.annotations.Permission; @@ -35,7 +34,7 @@ public enum ListCMD { public void onCommand( final CommandSender sender, final @Nullable @Flag("type") EntityType type, - final @Flag("sort") @Default("name") SortType sort // NOTE: @Default annotation doesn't work, waiting for a fix. + final @Nullable @Flag("sort") SortType sort // NOTE: Replace with @Default once fixed. ) { Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); // Excluding NPCs not created by the sender, if PLAYER_NPCS_FEATURE_FLAG is enabled and sender is a player. @@ -45,7 +44,7 @@ public void onCommand( if (type != null) npcs = npcs.filter(npc -> npc.getData().getType() == type); // Sorting... - switch (sort) { + switch (sort != null ? sort : SortType.NAME) { case NAME -> npcs = npcs.sorted(Comparator.comparing(npc -> npc.getData().getName())); case NAME_REVERSED -> npcs = npcs.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); // This needs a cast for some reason. } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java index df549d29..a16fd1cf 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java @@ -7,7 +7,6 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; -import org.incendo.cloud.annotations.Default; import org.incendo.cloud.annotations.Flag; import org.incendo.cloud.annotations.Permission; @@ -30,13 +29,13 @@ public enum NearbyCMD { COORDS_FORMAT.setMinimumFractionDigits(2); } - @Command("npc nearby") + @Command(value = "npc nearby", requiredSender = Player.class) @Permission("fancynpcs.command.npc.nearby") public void onCommand( final Player sender, final @Nullable @Flag("radius") Long radius, final @Nullable @Flag("type") EntityType type, - final @Nullable @Flag("sort") @Default("nearest") SortType sort // NOTE: @Default annotation doesn't work, waiting for a fix. + final @Nullable @Flag("sort") SortType sort // NOTE: Replace with @Default once fixed. ) { Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); // Getting location of the sender. @@ -61,7 +60,7 @@ public void onCommand( if (type != null) npcs = npcs.filter(npc -> npc.getData().getType() == type); // Sorting... - switch (sort) { // This should never produce NPE. + switch (sort != null ? sort : SortType.NEAREST) { // This should never produce NPE. case NAME -> npcs = npcs.sorted(Comparator.comparing(npc -> npc.getData().getName())); case NAME_REVERSED -> npcs = npcs.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); case NEAREST -> npcs = npcs.sorted(Comparator.comparingDouble(npc -> npc.getData().getLocation().distance(location))); From 66ed094d2184bd45a6911a0442a81539146e7e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 4 May 2024 21:44:49 +0200 Subject: [PATCH 47/94] allow uuid in npc argument --- .../commands/arguments/NpcArgument.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java index 4b4046ab..068a46cd 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java +++ b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java @@ -13,8 +13,10 @@ import org.incendo.cloud.context.CommandInput; import java.util.List; +import java.util.UUID; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public enum NpcArgument { INSTANCE; // SINGLETON @@ -26,7 +28,11 @@ public enum NpcArgument { // Reading next argument as single/literal String. final String value = input.readString(); // Getting the NPC from the manager. - final Npc npc = FancyNpcs.getInstance().getNpcManager().getNpc(value); + final @Nullable Npc npc = !isUUID(value) + ? FancyNpcs.getInstance().getNpcManager().getNpc(value) + : !FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() || context.sender().hasPermission("fancynpcs.admin") + ? FancyNpcs.getInstance().getNpcManager().getNpcById(value) + : null; // Throwing exception if NPC does not exist. if (npc == null) throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replace("input", value).send(context.sender())); @@ -50,4 +56,13 @@ public List suggestions(final CommandContext context, final CommandIn : FancyNpcs.getInstance().getNpcManager().getAllNpcs().stream().map(npc -> npc.getData().getName()).sorted().toList(); } + private static boolean isUUID(final @NotNull String string) { + try { + UUID.fromString(string); + return true; + } catch (final IllegalArgumentException e) { + return false; + } + } + } From 1fdf9123afdf9fd5dd6ef1eded288673252872d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 4 May 2024 23:35:04 +0200 Subject: [PATCH 48/94] extract GlowingColor enum, minor tweak to formatting --- .../fancynpcs/commands/npc/GlowingCMD.java | 41 +------------- .../fancynpcs/commands/npc/InfoCMD.java | 37 ++++--------- .../oliver/fancynpcs/util/GlowingColor.java | 54 +++++++++++++++++++ src/main/resources/languages/en.yml | 15 +++--- 4 files changed, 72 insertions(+), 75 deletions(-) create mode 100644 src/main/java/de/oliver/fancynpcs/util/GlowingColor.java diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java index b1d77eb8..73e993a9 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java @@ -5,12 +5,11 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import net.kyori.adventure.text.format.NamedTextColor; +import de.oliver.fancynpcs.util.GlowingColor; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum GlowingCMD { @@ -63,7 +62,7 @@ else if (color == GlowingColor.DISABLED) { npc.updateForAll(); translator.translate("npc_glowing_set_color_success") .replace("npc", npc.getData().getName()) - .replace("color", ((SimpleMessage) translator.translate(color.translationKey)).getMessage()) + .replace("color", ((SimpleMessage) translator.translate(color.getTranslationKey())).getMessage()) .send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); @@ -73,40 +72,4 @@ else if (color == GlowingColor.DISABLED) { } } - // NOTE: Perhaps this could be moved somewhere or be a standalone class. - public enum GlowingColor { - DISABLED(null, ""), - BLACK(NamedTextColor.BLACK, "color_black"), - DARK_BLUE(NamedTextColor.DARK_BLUE, "color_dark_blue"), - DARK_GREEN(NamedTextColor.DARK_GREEN, "color_dark_green"), - DARK_AQUA(NamedTextColor.DARK_AQUA, "color_dark_aqua"), - DARK_RED(NamedTextColor.DARK_RED, "color_dark_red"), - DARK_PURPLE(NamedTextColor.DARK_PURPLE, "color_dark_purple"), - GOLD(NamedTextColor.GOLD, "color_gold"), - GRAY(NamedTextColor.GRAY, "color_gray"), - DARK_GRAY(NamedTextColor.DARK_GRAY, "color_dark_gray"), - BLUE(NamedTextColor.BLUE, "color_blue"), - GREEN(NamedTextColor.GREEN, "color_green"), - AQUA(NamedTextColor.AQUA, "color_aqua"), - RED(NamedTextColor.RED, "color_red"), - LIGHT_PURPLE(NamedTextColor.LIGHT_PURPLE, "color_light_purple"), - YELLOW(NamedTextColor.YELLOW, "color_yellow"), - WHITE(NamedTextColor.WHITE, "color_white"); - - // Handled as 'disabled' if set to null. - private final @Nullable NamedTextColor color; - - private final @NotNull String translationKey; - - private GlowingColor(final @Nullable NamedTextColor color, final @NotNull String translationKey) { - this.color = color; - this.translationKey = translationKey; - } - - public @Nullable NamedTextColor getColor() { - return color; - } - - } - } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index f9e091e7..c38c2a6e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -5,7 +5,7 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; -import net.kyori.adventure.text.format.NamedTextColor; +import de.oliver.fancynpcs.util.GlowingColor; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Location; import org.bukkit.Material; @@ -35,19 +35,24 @@ public void onDefault(final CommandSender sender) { @Permission("fancynpcs.command.npc.info") public void onCommand(final CommandSender sender, final Npc npc) { final Location loc = npc.getData().getLocation(); - + // Getting the translated glowing state. This should never throw because all supported NamedTextColor objects has their mapping in GlowingColor enum. + final String glowingStateTranslated = (!npc.getData().isGlowing() || npc.getData().getGlowingColor() != null) + ? ((SimpleMessage) translator.translate(GlowingColor.fromAdventure(npc.getData().getGlowingColor()).getTranslationKey())).getMessage() + : ((SimpleMessage) translator.translate("disabled")).getMessage(); + // Sending general info to the sender. translator.translate("npc_info_general") .replace("name", npc.getData().getName()) .replace("id", npc.getData().getId()) + .replace("id_short", npc.getData().getId().substring(0, 13) + "...") .replace("creator", npc.getData().getCreator().toString()) + .replace("creator_short", npc.getData().getCreator().toString().substring(0, 13) + "...") .replace("displayname", npc.getData().getDisplayName()) .replace("type", "") // Not ideal solution but should work fine for now. .replace("location_x", COORDS_FORMAT.format(loc.x())) .replace("location_y", COORDS_FORMAT.format(loc.y())) .replace("location_z", COORDS_FORMAT.format(loc.z())) .replace("world", loc.getWorld().getName()) - .replace("is_glowing", getTranslatedBoolean(npc.getData().isGlowing())) - .replace("glowing_color", getFormattedColor(npc.getData().getGlowingColor())) + .replace("glow", glowingStateTranslated) .replace("is_collidable", getTranslatedBoolean(npc.getData().isCollidable())) .replace("is_turn_to_player", getTranslatedBoolean(npc.getData().isTurnToPlayer())) .replace("is_show_in_tab", getTranslatedBoolean(npc.getData().isShowInTab())) @@ -118,28 +123,4 @@ public void onCommand(final CommandSender sender, final Npc npc) { )).getMessage(); } - // NOTE: Might need to be improved later down the line, should get work done for now. - private static @NotNull String getFormattedColor(final @NotNull NamedTextColor color) { - final int colorCode = color.value(); - return switch (colorCode) { - case 0 -> "Black"; - case 170 -> "Dark Blue"; - case 43520 -> "Dark Green"; - case 43690 -> "Dark Aqua"; - case 11141120 -> "Dark Red"; - case 11141290 -> "Dark Purple"; - case 16755200 -> "Gold"; - case 11184810 -> "Gray"; - case 5592405 -> "Dark Gray"; - case 5592575 -> "Blue"; - case 5635925 -> "Green"; - case 5636095 -> "Aqua"; - case 16733525 -> "Red"; - case 16733695 -> "Light Purple"; - case 16777045 -> "Yellow"; - case 16777215 -> "White"; - default -> "Unknown"; - }; - } - } diff --git a/src/main/java/de/oliver/fancynpcs/util/GlowingColor.java b/src/main/java/de/oliver/fancynpcs/util/GlowingColor.java new file mode 100644 index 00000000..2fc2e660 --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/util/GlowingColor.java @@ -0,0 +1,54 @@ +package de.oliver.fancynpcs.util; + +import net.kyori.adventure.text.format.NamedTextColor; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +// Used by commands. +public enum GlowingColor { + DISABLED(null, ""), + BLACK(NamedTextColor.BLACK, "color_black"), + DARK_BLUE(NamedTextColor.DARK_BLUE, "color_dark_blue"), + DARK_GREEN(NamedTextColor.DARK_GREEN, "color_dark_green"), + DARK_AQUA(NamedTextColor.DARK_AQUA, "color_dark_aqua"), + DARK_RED(NamedTextColor.DARK_RED, "color_dark_red"), + DARK_PURPLE(NamedTextColor.DARK_PURPLE, "color_dark_purple"), + GOLD(NamedTextColor.GOLD, "color_gold"), + GRAY(NamedTextColor.GRAY, "color_gray"), + DARK_GRAY(NamedTextColor.DARK_GRAY, "color_dark_gray"), + BLUE(NamedTextColor.BLUE, "color_blue"), + GREEN(NamedTextColor.GREEN, "color_green"), + AQUA(NamedTextColor.AQUA, "color_aqua"), + RED(NamedTextColor.RED, "color_red"), + LIGHT_PURPLE(NamedTextColor.LIGHT_PURPLE, "color_light_purple"), + YELLOW(NamedTextColor.YELLOW, "color_yellow"), + WHITE(NamedTextColor.WHITE, "color_white"); + + // Handled as 'disabled' if set to null. + private final @Nullable NamedTextColor color; + + private final @NotNull String translationKey; + + private GlowingColor(final @Nullable NamedTextColor color, final @NotNull String translationKey) { + this.color = color; + this.translationKey = translationKey; + } + + public @Nullable NamedTextColor getColor() { + return color; + } + + public @NotNull String getTranslationKey() { + return translationKey; + } + + public static @NotNull GlowingColor fromAdventure(final @NotNull NamedTextColor color) { + for (final GlowingColor glowingColor : GlowingColor.values()) + if (glowingColor.color != null && glowingColor.color.value() == color.value()) + return glowingColor; + // Throwing exception if specified color is not mapped. + throw new IllegalArgumentException("UNSUPPORTED COLOR"); + } + +} diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 2ef4c6f1..a36f8beb 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -54,8 +54,8 @@ messages: fancynpcs_feature_flags_header: "Feature Flags:" fancynpcs_feature_flags_entry: "› <#848484>{number}. {warningColor}{name} <#848484>({id}): {state}" fancynpcs_feature_flags_footer: "" - npc_help_page_header: "―――――― {primaryColor}FancyNpcs plugin help: ({primaryColor}{page}/{primaryColor}{max_page})" - npc_help_page_footer: "Full command reference available {primaryColor}here." + npc_help_page_header: "------------- {primaryColor}FancyNpcs Commands ({primaryColor}{page}/{primaryColor}{max_page}) --------------" + npc_help_page_footer: "----------- Click {primaryColor}here to open documentation -----------" npc_help_contents: - "› {primaryColor}/npc create {secondaryColor}(npc) - Creates a new NPC at your location." - "› {primaryColor}/npc remove {secondaryColor}(npc) - Removes specified NPC." @@ -112,15 +112,14 @@ messages: npc_info_syntax: "Syntax: {primaryColor}/npc info {secondaryColor}(npc)" npc_info_general: - - "Information about NPC named {primaryColor}{name}:" + - "------------ Information about {primaryColor}{name} ------------" - " " - - "Unique, permanent identifier of the NPC.'>Identifier: Click to copy identifier to clipboard.'>{warningColor}{id}" - - "Identifier of player who created this NPC.'>Creator: Click to copy creator to clipboard.'>{warningColor}{creator}" + - "Unique, permanent identifier of the NPC.'>Identifier: Click to copy identifier to clipboard.'>{warningColor}{id_short} Identifier of player who created this NPC.'>Creator: Click to copy creator to clipboard.'>{warningColor}{creator_short}" - "Current location of the NPC.'>Location: Click to copy location to clipboard.'>{warningColor}{location_x}, {warningColor}{location_y}, {warningColor}{location_z} in {warningColor}{world}" - "Display name of the NPC, displayed above their head.'>Display Name: {displayname}" - - "Entity type of the NPC.'>Type: {warningColor}{type} Glowing state of the NPC. Can be {successColor}true or {errorColor}false.'>Glowing: {is_glowing} Glowing color of the NPC.'>Glowing Color: {warningColor}{glowing_color}" - - "Whether the NPC should be shown in player-list. Can be {successColor}true or {errorColor}false.'>Shown in TAB: {is_show_in_tab} Collidable state of the NPC. Can be {successColor}true or {errorColor}false.'>Collidable: {is_collidable} Whether the NPC should turn to player. Can be {successColor}true or {errorColor}false.'>Turns to Player: {is_turn_to_player}" - - "Skin mirroring state of the NPC.. Can be {successColor}true or {errorColor}false.'>Skin Mirroring: {warningColor}{is_skin_mirror} Interaction cooldown between interactions. In seconds.'>Interaction Cooldown: {warningColor}{interaction_cooldown}" + - "Entity type of the NPC.'>Type: {warningColor}{type} Glowing state of the NPC. Can be a {warningColor}color or {errorColor}disabled.'>Glow: {glow} Whether the NPC should turn to player. Can be {successColor}true or {errorColor}false.'>Turns to Player: {is_turn_to_player}" + - "Whether the NPC should be shown in player-list. Can be {successColor}true or {errorColor}false.'>Shown in TAB: {is_show_in_tab} Collidable state of the NPC. Can be {successColor}true or {errorColor}false.'>Collidable: {is_collidable} Skin mirroring state of the NPC.. Can be {successColor}true or {errorColor}false.'>Skin Mirroring: {warningColor}{is_skin_mirror}" + - "Interaction cooldown between interactions. In seconds.'>Interaction Cooldown: {warningColor}{interaction_cooldown}" - " " npc_info_messages_header: "Messages:" From 6c3ebd456edcd65db570f2809fd115c20b8a8480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 7 May 2024 23:20:53 +0200 Subject: [PATCH 49/94] tweak `/npc info` format --- .../fancynpcs/commands/npc/InfoCMD.java | 3 ++ src/main/resources/languages/en.yml | 32 ++++++++++++------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index c38c2a6e..fcba813f 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -58,6 +58,9 @@ public void onCommand(final CommandSender sender, final Npc npc) { .replace("is_show_in_tab", getTranslatedBoolean(npc.getData().isShowInTab())) .replace("is_skin_mirror", getTranslatedBoolean(npc.getData().isMirrorSkin())) .replace("interaction_cooldown", SECONDS_FORMAT.format(npc.getData().getInteractionCooldown()) + "s") + .replace("messages_total", String.valueOf(npc.getData().getMessages().size())) + .replace("player_commands_total", String.valueOf(npc.getData().getPlayerCommands().size())) + .replace("server_commands_total", String.valueOf(0)) // TODO .send(sender); if (npc.getData().getServerCommand() != null) { diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index a36f8beb..80ba5cc9 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -112,19 +112,29 @@ messages: npc_info_syntax: "Syntax: {primaryColor}/npc info {secondaryColor}(npc)" npc_info_general: - - "------------ Information about {primaryColor}{name} ------------" - - " " - - "Unique, permanent identifier of the NPC.'>Identifier: Click to copy identifier to clipboard.'>{warningColor}{id_short} Identifier of player who created this NPC.'>Creator: Click to copy creator to clipboard.'>{warningColor}{creator_short}" - - "Current location of the NPC.'>Location: Click to copy location to clipboard.'>{warningColor}{location_x}, {warningColor}{location_y}, {warningColor}{location_z} in {warningColor}{world}" + - "" + - "Unique, permanent identifier of the NPC.'><#848484>Identifier: Click to copy identifier to clipboard.'>{warningColor}{id_short}" + - "Identifier of player who created this NPC.'>Creator: Click to copy creator to clipboard.'>{warningColor}{creator_short}" + - "Name of the NPC, used in commands and displayed above their head if display name is not set.'><#848484>Name: {warningColor}{name}" - "Display name of the NPC, displayed above their head.'>Display Name: {displayname}" - - "Entity type of the NPC.'>Type: {warningColor}{type} Glowing state of the NPC. Can be a {warningColor}color or {errorColor}disabled.'>Glow: {glow} Whether the NPC should turn to player. Can be {successColor}true or {errorColor}false.'>Turns to Player: {is_turn_to_player}" - - "Whether the NPC should be shown in player-list. Can be {successColor}true or {errorColor}false.'>Shown in TAB: {is_show_in_tab} Collidable state of the NPC. Can be {successColor}true or {errorColor}false.'>Collidable: {is_collidable} Skin mirroring state of the NPC.. Can be {successColor}true or {errorColor}false.'>Skin Mirroring: {warningColor}{is_skin_mirror}" + - "Entity type of the NPC.'><#848484>Type: {warningColor}{type}" + - "Current location of the NPC.'>Location: Click to copy location to clipboard.'>{warningColor}{location_x}, {warningColor}{location_y}, {warningColor}{location_z} in {warningColor}{world}" + - "Glowing state of the NPC. Can be a {warningColor}color or {errorColor}disabled.'><#848484>Glow: {glow}" + - "Whether the NPC should turn to player. Can be {successColor}true or {errorColor}false.'>Turns to Player: {is_turn_to_player}" + - "Whether the NPC should be shown in player-list. Can be {successColor}true or {errorColor}false.'><#848484>Shown in TAB: {is_show_in_tab}" + - "Collidable state of the NPC. Can be {successColor}true or {errorColor}false.'>Collidable: {is_collidable}" + - "Skin mirroring state of the NPC.. Can be {successColor}true or {errorColor}false.'><#848484>Skin Mirroring: {warningColor}{is_skin_mirror}" - "Interaction cooldown between interactions. In seconds.'>Interaction Cooldown: {warningColor}{interaction_cooldown}" - - " " - - npc_info_messages_header: "Messages:" - npc_info_messages_entry: "{message}" - npc_info_messages_footer: " " + - "" + - "Click here to browse equipment.'><#848484>Equipment: {warningColor}[Click Here]" + - "Click here to browse attributes.'><#848484>Attributes: {warningColor}[Click Here]" + - "Click here to browse list of messages.'>Messages: {warningColor}[Click Here] ({messages_total} total)" + - "Click here to browse list of player commands.'><#848484>Player Commands: {warningColor}[Click Here] ({player_commands_total} total)" + - "Click here to browse list of server commands.'>Server Commands: {warningColor}[Click Here] ({server_commands_total} total)" + - "" + - "› {primaryColor}Can't find what you're looking for?" + - "Open the chat window to see all information." + - "" npc_info_playerCommands_header: "Player Commands:" npc_info_playerCommands_entry: "{command}" From f4d062e3c38e3ab3c4ca98962662983d10ca0c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 7 May 2024 23:21:39 +0200 Subject: [PATCH 50/94] use snapshot version of cloud --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 9035d766..2b0af1cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ minecraftVersion=1.20.6 fancyLibVersion=1.0.21 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 -cloudVersion=2.0.0-beta.5 \ No newline at end of file +cloudVersion=2.0.0-SNAPSHOT \ No newline at end of file From 7cc28ffa60cced7bff3973a50a621a33caf2378f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 7 May 2024 23:22:50 +0200 Subject: [PATCH 51/94] complete `/npc message` command (hopefully) --- .../fancynpcs/commands/npc/InfoCMD.java | 8 -- .../fancynpcs/commands/npc/MessageCMD.java | 90 +++++++++++++++---- src/main/resources/languages/en.yml | 9 +- 3 files changed, 78 insertions(+), 29 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index fcba813f..733f7659 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -77,14 +77,6 @@ public void onCommand(final CommandSender sender, final Npc npc) { translator.translate("npc_info_playerCommands_footer").send(sender); } - if (!npc.getData().getMessages().isEmpty()) { - translator.translate("npc_info_messages_header").send(sender); - npc.getData().getMessages().forEach(message -> - translator.translate("npc_info_messages_entry").replace("message", message).send(sender) - ); - translator.translate("npc_info_messages_footer").send(sender); - } - if (!npc.getData().getEquipment().isEmpty()) { translator.translate("npc_info_equipment_header").send(sender); npc.getData().getEquipment().forEach((slot, item) -> { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index 23e449ea..e73a4eab 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -11,8 +11,12 @@ import net.kyori.adventure.text.event.ClickEvent.Action; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotation.specifier.Greedy; +import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; import java.util.List; import java.util.stream.StreamSupport; @@ -25,6 +29,11 @@ public enum MessageCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); + // Storing in a static variable to avoid re-creating the array each time suggestion is requested. + private static final List NONE_SUGGESTIONS = List.of("@none"); + + /* MESSAGE ADD */ + @Command("npc message add") @Permission("fancynpcs.command.npc.message.add") public void onMessageAdd(final CommandSender sender, final Npc npc) { @@ -33,27 +42,39 @@ public void onMessageAdd(final CommandSender sender, final Npc npc) { @Command("npc message add ") @Permission("fancynpcs.command.npc.message.add") - public void onMessageAdd(final CommandSender sender, final Npc npc, final @Greedy String message) { + public void onMessageAdd(final CommandSender sender, final Npc npc, final @Argument(suggestions = "@none") @Greedy String message) { + // Handling '@none' as an empty message. + final String finalMessage = message.equalsIgnoreCase("@none") ? "" : message; // Exiting the command block in case banned command has been found in the message. - if (hasBlockedCommands(message)) { + if (hasBlockedCommands(finalMessage)) { translator.translate("command_input_contains_blocked_command").send(sender); return; } - // ... - if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SET, message, sender).callEvent()) { - npc.getData().getMessages().add(message); - // ... + // Calling the event and adding message if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_ADD, finalMessage, sender).callEvent()) { + npc.getData().getMessages().add(finalMessage); + // Sending success message to the sender. translator.translate("npc_message_add_success").replace("total", String.valueOf(npc.getData().getMessages().size())).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } } + /* MESSAGE SET */ + + @Command("npc message set") + @Permission("fancynpcs.command.npc.message.set") + public void onMessageSet(final CommandSender sender, final Npc npc) { + translator.translate("npc_message_set_syntax").send(sender); + } + @Command("npc message set ") @Permission("fancynpcs.command.npc.message.set") - public void onMessageSet(final CommandSender sender, final Npc npc, final int number, final @Greedy String message) { + public void onMessageSet(final CommandSender sender, final Npc npc, final int number, final @Argument(suggestions = "@none") @Greedy String message) { + // Handling '@none' as an empty message. + final String finalMessage = message.equalsIgnoreCase("@none") ? "" : message; // Sending error message in case banned command has been found in the message. - if (hasBlockedCommands(message)) { + if (hasBlockedCommands(finalMessage)) { translator.translate("command_input_contains_blocked_command").send(sender); return; } @@ -71,10 +92,10 @@ public void onMessageSet(final CommandSender sender, final Npc npc, final int nu } // User-specified number starts from 1, while index starts from 0. Subtracting 1 from the provided number to get the list index. final int index = number - 1; - // ... - if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SET, new Object[]{index, message}, sender).callEvent()) { - npc.getData().getMessages().set(index, message); - // ... + // Calling the event and setting message if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SET, new Object[]{index, finalMessage}, sender).callEvent()) { + npc.getData().getMessages().set(index, finalMessage); + // Sending success message to the sender. translator.translate("npc_message_set_success") .replace("number", String.valueOf(number)) .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. @@ -84,6 +105,8 @@ public void onMessageSet(final CommandSender sender, final Npc npc, final int nu } } + /* MESSAGE REMOVE */ + @Command("npc message remove") @Permission("fancynpcs.command.npc.message.remove") public void onMessageRemoveSyntax(final CommandSender sender, final Npc npc) { @@ -109,10 +132,10 @@ public void onMessageRemove(final CommandSender sender, final Npc npc, final int final int index = number - 1; // Getting the message to pass to the NpcModifyEvent. final String message = npc.getData().getMessages().get(index); - // ... + // Calling the event and removing message if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_REMOVE, new Object[]{index, message}, sender).callEvent()) { npc.getData().getMessages().remove(index); - // ... + // Sending success message to the sender. translator.translate("npc_message_remove_success") .replace("number", String.valueOf(number)) .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. @@ -122,11 +145,13 @@ public void onMessageRemove(final CommandSender sender, final Npc npc, final int } } + /* MESSAGE CLEAR */ + @Command("npc message clear") @Permission("fancynpcs.command.npc.message.clear") public void onMessageClear(final CommandSender sender, final Npc npc) { final int total = npc.getData().getMessages().size(); - // ... + // Calling the event and clearing messages if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_CLEAR, null, sender).callEvent()) { npc.getData().getMessages().clear(); translator.translate("npc_message_clear_success").replace("total", String.valueOf(total)).send(sender); @@ -135,12 +160,33 @@ public void onMessageClear(final CommandSender sender, final Npc npc) { } } + /* MESSAGE LIST */ + @Command("npc message list") @Permission("fancynpcs.command.npc.message.list") public void onMessageList(final CommandSender sender, final Npc npc) { - throw new UnsupportedOperationException("NOT IMPLEMENTED"); + // Sending error message if the list is empty. + if (npc.getData().getMessages().isEmpty()) { + translator.translate("npc_message_list_failure_empty").send(sender); + return; + } + // Sending header to the sender. + translator.translate("npc_message_list_header").send(sender); + // Iterating over all messages attached to this NPC. + for (int i = 0; i < npc.getData().getMessages().size(); i++) { + final String message = npc.getData().getMessages().get(i); + // Sending message entry to the sender. + translator.translate("npc_message_list_entry") + .replace("number", String.valueOf(i + 1)) + .replace("message", message) + .send(sender); + } + // Sending footer to the sender. + translator.translate("npc_message_list_footer").send(sender); } + /* MESSAGE SEND_RANDOMLY */ + @Command("npc message send_randomly [state]") @Permission("fancynpcs.command.npc.message.send_randomly") public void onMessageSendRandomly(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { @@ -149,13 +195,23 @@ public void onMessageSendRandomly(final CommandSender sender, final Npc npc, fin if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SEND_RANDOMLY, finalState, sender).callEvent()) { npc.getData().setSendMessagesRandomly(finalState); npc.updateForAll(); + // Sending success message to the sender. translator.translate(finalState ? "npc_message_send_randomly_set_true" : "npc_message_send_randomly_set_false").replace("npc", npc.getData().getName()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } } - // Returns 'true' if specified component contains blocked command, 'false' otherwise. + /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ + + @Suggestions("@none") + public List suggest(final CommandContext context, final CommandInput input) { + return NONE_SUGGESTIONS; + } + + /* UTILITY METHODS */ + + /** Returns {@code true} if specified component contains blocked command, {@code false} otherwise. */ private boolean hasBlockedCommands(final @NotNull String message) { // Converting message to a Component. final Component component = ModernChatColorHandler.translate(message); diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 80ba5cc9..56289a4f 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -144,10 +144,6 @@ messages: npc_info_serverCommands_entry: "{command}" npc_info_serverCommands_footer: " " - npc_info_equipment_header: "Equipment:" - npc_info_equipment_entry: "› <#848484>{slot}: {warningColor}" # DEV NOTE: This uses <> brackets because this must be a MiniMessage placeholder (TagResolver). - npc_info_equipment_footer: " " - npc_info_attributes_header: "Attributes:" npc_info_attributes_entry: "› <#848484>{attribute}: {warningColor}{value}" npc_info_attributes_footer: " " @@ -216,3 +212,8 @@ messages: npc_message_send_randomly_set_true: "NPC named {warningColor}{npc} is now sending messages randomly." npc_message_send_randomly_set_false: "NPC named {warningColor}{npc} is no longer sending messages randomly." + + npc_message_list_header: "-------------------- Messages --------------------" + npc_message_list_entry: " <#848484>{number}. {message}" + npc_message_list_footer: "---------------------------------------------------" + npc_message_list_failure_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." From cba20eaf43f31d06b07b2c3899aeeb245df41a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 7 May 2024 23:37:57 +0200 Subject: [PATCH 52/94] add missing context aware completions for `/npc message` --- .../fancynpcs/commands/npc/MessageCMD.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index e73a4eab..140aa6b4 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -18,6 +18,8 @@ import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.stream.StreamSupport; @@ -42,7 +44,7 @@ public void onMessageAdd(final CommandSender sender, final Npc npc) { @Command("npc message add ") @Permission("fancynpcs.command.npc.message.add") - public void onMessageAdd(final CommandSender sender, final Npc npc, final @Argument(suggestions = "@none") @Greedy String message) { + public void onMessageAdd(final CommandSender sender, final Npc npc, final @Argument(suggestions = "MessageCMD/none") @Greedy String message) { // Handling '@none' as an empty message. final String finalMessage = message.equalsIgnoreCase("@none") ? "" : message; // Exiting the command block in case banned command has been found in the message. @@ -70,7 +72,7 @@ public void onMessageSet(final CommandSender sender, final Npc npc) { @Command("npc message set ") @Permission("fancynpcs.command.npc.message.set") - public void onMessageSet(final CommandSender sender, final Npc npc, final int number, final @Argument(suggestions = "@none") @Greedy String message) { + public void onMessageSet(final CommandSender sender, final Npc npc, final @Argument(suggestions = "MessageCMD/number_range") int number, final @Argument(suggestions = "MessageCMD/none") @Greedy String message) { // Handling '@none' as an empty message. final String finalMessage = message.equalsIgnoreCase("@none") ? "" : message; // Sending error message in case banned command has been found in the message. @@ -115,7 +117,7 @@ public void onMessageRemoveSyntax(final CommandSender sender, final Npc npc) { @Command("npc message remove ") @Permission("fancynpcs.command.npc.message.remove") - public void onMessageRemove(final CommandSender sender, final Npc npc, final int number) { + public void onMessageRemove(final CommandSender sender, final Npc npc, final @Argument(suggestions = "MessageCMD/number_range") int number) { // Getting the total count of messages that are currently in the list. final int totalCount = npc.getData().getMessages().size(); // Sending error message if the list is empty. @@ -204,11 +206,23 @@ public void onMessageSendRandomly(final CommandSender sender, final Npc npc, fin /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ - @Suggestions("@none") - public List suggest(final CommandContext context, final CommandInput input) { + @Suggestions("MessageCMD/none") + public List suggestNone(final CommandContext context, final CommandInput input) { return NONE_SUGGESTIONS; } + @Suggestions("MessageCMD/number_range") + public List suggestNumber(final CommandContext context, final CommandInput input) { + final Npc npc = context.getOrDefault("npc", null); + // Returning... + return npc == null || npc.getData().getMessages().isEmpty() + ? Collections.emptyList() + : new ArrayList<>() {{ + for (int i = 0; i < npc.getData().getMessages().size(); i++) + add(String.valueOf(i + 1)); + }}; + } + /* UTILITY METHODS */ /** Returns {@code true} if specified component contains blocked command, {@code false} otherwise. */ From a6b1c155fb80ff43e28573b86be19977f73ff2a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 8 May 2024 11:50:58 +0200 Subject: [PATCH 53/94] update regex matching in `/npc copy` --- src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java index 41fb8d91..cf45c8cf 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java @@ -26,8 +26,8 @@ public void onDefault(final Player sender) { @Command(value = "npc copy ", requiredSender = Player.class) @Permission("fancynpcs.command.npc.copy") - public void onCommand(final Player sender, final Npc npc, final @Regex("^[^.]*$") String name) { - // Copying the NPC. + public void onCommand(final Player sender, final Npc npc, final @Regex("^[A-Za-z0-9_-]*$") String name) { + // Creating a copy of an NPC and all it's data. The only different thing is it's UUID. final Npc copied = FancyNpcs.getInstance().getNpcAdapter().apply( new NpcData( UUID.randomUUID().toString(), From a388466eb9c3961f128b968061618a3f8dc6bb5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 8 May 2024 11:52:33 +0200 Subject: [PATCH 54/94] use `@none` as an addition to `` in `/npc displayname`, split message in two --- .../commands/npc/DisplayNameCMD.java | 26 ++++++++++++------- src/main/resources/languages/en.yml | 3 ++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java index fb812ae8..96268d6d 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java @@ -20,12 +20,8 @@ public enum DisplayNameCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private static final List SUGGESTIONS = List.of(""); - - @Suggestions("empty") - public List suggestions(final CommandContext sender, CommandInput input) { - return SUGGESTIONS; - } + // Storing in a static variable to avoid re-creating the array each time suggestion is requested. + private static final List NONE_SUGGESTIONS = List.of("@none"); @Command("npc displayname") @Permission("fancynpcs.command.npc.displayname") @@ -35,15 +31,25 @@ public void onDefault(final CommandSender sender) { @Command("npc displayname ") @Permission("fancynpcs.command.npc.displayname") - public void onCommand(final CommandSender sender, final Npc npc, final @Argument(suggestions = "empty") @Greedy String name) { + public void onCommand(final CommandSender sender, final Npc npc, final @Argument(suggestions = "DisplayNameCMD/none") @Greedy String name) { + // Finalizing the name. In case input is '@none', it gets replaced with '' for backwards compatibility. + final String finalName = name.equalsIgnoreCase("@none") ? "" : name; // Calling the event and updating the state if not cancelled. - if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.DISPLAY_NAME, name, sender).callEvent()) { - npc.getData().setDisplayName(name); + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.DISPLAY_NAME, finalName, sender).callEvent()) { + npc.getData().setDisplayName(finalName); npc.updateForAll(); - translator.translate("npc_displayname_success").replace("npc", npc.getData().getName()).send(sender); + translator.translate(finalName.equalsIgnoreCase("") ? "npc_displayname_set_empty" : "npc_displayname_set_name") + .replace("npc", npc.getData().getName()) + .replace("name", finalName) + .send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } } + @Suggestions("DisplayNameCMD/none") + public List suggestions(final CommandContext sender, CommandInput input) { + return NONE_SUGGESTIONS; + } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 56289a4f..6b7237cd 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -96,7 +96,8 @@ messages: npc_create_failure_already_exists: "› {errorColor}NPC named {warningColor}{npc}{errorColor} already exists." npc_displayname_syntax: "Syntax: {primaryColor}/npc displayname {secondaryColor}(npc) (name)" - npc_displayname_success: "NPC named {warningColor}{npc} has had their display-name updated." + npc_displayname_set_name: "NPC {warningColor}{npc} is now using {name} as their display name." + npc_displayname_set_empty: "NPC {warningColor}{npc} is no longer showing display name." npc_equipment_syntax: "Syntax: {primaryColor}/npc equipment {secondaryColor}(npc) (slot)" npc_equipment_success: "NPC named {warningColor}{npc} has had their equipment updated." From 95c0dbd4d58b84ac4f1486f49ac0108b9aaac170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 8 May 2024 11:53:09 +0200 Subject: [PATCH 55/94] small message format changes --- src/main/resources/languages/en.yml | 51 +++++++++++++++-------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 6b7237cd..1c40ce6e 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -42,7 +42,7 @@ messages: command_invalid_number: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid number." command_invalid_integer: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid integer." command_invalid_world: "› {errorColor}World named {warningColor}{input}{errorColor} does not exist." - command_invalid_npc: "› {errorColor}NPC named {warningColor}{input}{errorColor} does not exist." + command_invalid_npc: "› {errorColor}NPC {warningColor}{input}{errorColor} does not exist." command_unsupported_npc_type: "› This NPC type does not support this feature." command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." @@ -85,15 +85,15 @@ messages: npc_attribute_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." npc_collidable_syntax: "Syntax: {primaryColor}/npc collidable {secondaryColor}(npc) (state)" - npc_collidable_set_true: "NPC named {warningColor}{npc} is now collidable." - npc_collidable_set_false: "NPC named {warningColor}{npc} is no longer collidable." + npc_collidable_set_true: "NPC {warningColor}{npc} is now collidable." + npc_collidable_set_false: "NPC {warningColor}{npc} is no longer collidable." npc_copy_syntax: "Syntax: {primaryColor}/npc copy {secondaryColor}(npc) (new_name)" - npc_copy_success: "NPC named {warningColor}{npc} has been copied to {warningColor}{new_npc}." + npc_copy_success: "NPC {warningColor}{npc} has been copied to {warningColor}{new_npc}." npc_create_syntax: "Syntax: {primaryColor}/npc create {secondaryColor}(npc)" - npc_create_success: "NPC named {warningColor}{npc} has been created." - npc_create_failure_already_exists: "› {errorColor}NPC named {warningColor}{npc}{errorColor} already exists." + npc_create_success: "NPC {warningColor}{npc} has been created." + npc_create_failure_already_exists: "› {errorColor}NPC {warningColor}{npc}{errorColor} already exists." npc_displayname_syntax: "Syntax: {primaryColor}/npc displayname {secondaryColor}(npc) (name)" npc_displayname_set_name: "NPC {warningColor}{npc} is now using {name} as their display name." @@ -103,12 +103,13 @@ messages: npc_equipment_success: "NPC named {warningColor}{npc} has had their equipment updated." npc_equipment_failure_invalid_slot: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid equipment slot." - npc_fix_success: "Attempted to fix NPC named {warningColor}{npc}... Still having issues? Please let us know." + + npc_fix_success: "Attempted to fix NPC {warningColor}{npc}... Still having issues? Please let us know." npc_glowing_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color)" - npc_glowing_set_true: "NPC named {warningColor}{npc} is now glowing." - npc_glowing_set_false: "NPC named {warningColor}{npc} is no longer glowing." - npc_glowing_set_color_success: "NPC named {warningColor}{npc} is now glowing in {color}." + npc_glowing_set_true: "NPC {warningColor}{npc} is now glowing." + npc_glowing_set_false: "NPC {warningColor}{npc} is no longer glowing." + npc_glowing_set_color_success: "NPC {warningColor}{npc} is now glowing in {color}." npc_glowing_set_color_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." npc_info_syntax: "Syntax: {primaryColor}/npc info {secondaryColor}(npc)" @@ -150,22 +151,22 @@ messages: npc_info_attributes_footer: " " npc_interaction_cooldown_syntax: "Syntax: {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (seconds)" - npc_interaction_cooldown_success: "NPC named {warningColor}{npc} has had their interaction cooldown updated." + npc_interaction_cooldown_success: "NPC {warningColor}{npc} has had their interaction cooldown updated." npc_skin_syntax: "Syntax: {primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" - npc_skin_set_name: "NPC named {warningColor}{npc} is now using {warningColor}{name}'s skin." - npc_skin_set_url: "NPC named {warningColor}{npc} is now using skin from specified URL." - npc_skin_set_mirror: "NPC named {warningColor}{npc} is now mirroring player skin." - npc_skin_set_none: "NPC named {warningColor}{npc} is no longer using any skin." + npc_skin_set_name: "NPC {warningColor}{npc} is now using {warningColor}{name}'s skin." + npc_skin_set_url: "NPC {warningColor}{npc} is now using skin from specified URL." + npc_skin_set_mirror: "NPC {warningColor}{npc} is now mirroring player skin." + npc_skin_set_none: "NPC {warningColor}{npc} is no longer using any skin." npc_skin_failure_invalid_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is invalid or unsupported URL." npc_skin_failure_invalid_name_or_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid player name or URL." npc_skin_failure_invalid_name_or_rate_limit: "› {errorColor}Could not find {warningColor}{input}'s{errorColor} skin. Either the account does not exist or you're being rate limited." npc_move_here_syntax: "Syntax: {primaryColor}/npc move_here {secondaryColor}(npc)" - npc_move_here_success: "NPC named {warningColor}{npc} has been moved to your location." + npc_move_here_success: "NPC {warningColor}{npc} has been moved to your location." npc_remove_syntax: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" - npc_remove_success: "NPC named {warningColor}{npc} has been removed." + npc_remove_success: "NPC {warningColor}{npc} has been removed." npc_list_syntax: "Syntax: {primaryColor}/npc list {secondaryColor}[filters...]" npc_list_header: "Listing results for requested query:" @@ -181,20 +182,20 @@ messages: npc_list_failure_requires_world_flag: "› {errorColor}You must specify a {warningColor}--world{errorColor} flag when running this command from the console." npc_move_to_syntax: "Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" - npc_move_to_success: "NPC named {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." + npc_move_to_success: "NPC {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." npc_teleport_syntax: "Syntax: {primaryColor}/npc teleport {secondaryColor}(npc)" - npc_teleport_success: "You have been teleported to NPC named {warningColor}{npc}." + npc_teleport_success: "You have been teleported to NPC {warningColor}{npc}." npc_teleport_failure_exception: "› {errorColor}An error occurred while trying to teleport to NPC. Check console for errors." npc_teleport_failure_world_not_loaded: "› {errorColor}An error occurred while trying to teleport to NPC. Destination world is not loaded." npc_turn_to_player_syntax: "Syntax: {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" - npc_turn_to_player_set_true: "NPC named {warningColor}{npc} is now turning to player." - npc_turn_to_player_set_false: "NPC named {warningColor}{npc} is no longer turning to player." + npc_turn_to_player_set_true: "NPC {warningColor}{npc} is now turning to player." + npc_turn_to_player_set_false: "NPC {warningColor}{npc} is no longer turning to player." npc_show_in_tab_syntax: "Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" - npc_show_in_tab_set_true: "NPC named {warningColor}{npc} is now shown in player-list." - npc_show_in_tab_set_false: "NPC named {warningColor}{npc} is no longer shown in player-list." + npc_show_in_tab_set_true: "NPC {warningColor}{npc} is now shown in player-list." + npc_show_in_tab_set_false: "NPC {warningColor}{npc} is no longer shown in player-list." npc_message_add_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) add (none | message)" npc_message_add_success: "Message has been added. There is {warningColor}{total} messages in total." @@ -211,8 +212,8 @@ messages: npc_message_clear_success: "Messages have been cleared. There was {warningColor}{total} messages in total." - npc_message_send_randomly_set_true: "NPC named {warningColor}{npc} is now sending messages randomly." - npc_message_send_randomly_set_false: "NPC named {warningColor}{npc} is no longer sending messages randomly." + npc_message_send_randomly_set_true: "NPC {warningColor}{npc} is now sending messages randomly." + npc_message_send_randomly_set_false: "NPC {warningColor}{npc} is no longer sending messages randomly." npc_message_list_header: "-------------------- Messages --------------------" npc_message_list_entry: " <#848484>{number}. {message}" From 59579a139c7c6b2f02845e81f7c617b903146471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 8 May 2024 12:06:52 +0200 Subject: [PATCH 56/94] more sensible comments for `NpcArgument` --- .../fancynpcs/commands/arguments/NpcArgument.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java index 068a46cd..c026feb9 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java +++ b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java @@ -27,19 +27,20 @@ public enum NpcArgument { public @NotNull Npc parse(final CommandContext context, final CommandInput input) { // Reading next argument as single/literal String. final String value = input.readString(); - // Getting the NPC from the manager. + // Getting the NPC from the manager. This can be name or optionally (under certain circumstances) UUID of the NPC. final @Nullable Npc npc = !isUUID(value) + // Not an UUID, getting NPC from name. ? FancyNpcs.getInstance().getNpcManager().getNpc(value) + // Input is UUID, getting the NPC that way. If PLAYER NPCS FLAG is enabled, sender is required to have 'fancynpcs.admin' permission. : !FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() || context.sender().hasPermission("fancynpcs.admin") ? FancyNpcs.getInstance().getNpcManager().getNpcById(value) : null; - // Throwing exception if NPC does not exist. + // Throwing exception if no NPC with given name or UUID exist. if (npc == null) throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replace("input", value).send(context.sender())); - // Throwing exception if PLAYER NPCS FLAG is enabled and sender (player) is not creator of the specified NPC. + // Throwing exception if PLAYER NPCS FLAG is enabled and sender is not creator of the specified NPC. if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && context.sender() instanceof Player sender && !npc.getData().getCreator().equals(sender.getUniqueId())) throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replace("input", value).send(context.sender())); - // Returning... return npc; } @@ -50,12 +51,14 @@ public List suggestions(final CommandContext context, final CommandIn ? FancyNpcs.getInstance().getNpcManager().getAllNpcs().stream() .filter(npc -> npc.getData().getCreator().equals(sender.getUniqueId())) .map(npc -> npc.getData().getName()) - .sorted() .toList() // PLAYER NPCS FLAG is disabled or sender is console; Showing all NPCs. - : FancyNpcs.getInstance().getNpcManager().getAllNpcs().stream().map(npc -> npc.getData().getName()).sorted().toList(); + : FancyNpcs.getInstance().getNpcManager().getAllNpcs().stream().map(npc -> npc.getData().getName()).toList(); } + /** + * Returns {@code true} if provided {@link String} can be converted to a valid {@link UUID}. Otherwise {@code false} is returned. + * */ private static boolean isUUID(final @NotNull String string) { try { UUID.fromString(string); From c676bd3c31e2b682b32af5b6339d439d94e17bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 8 May 2024 13:26:04 +0200 Subject: [PATCH 57/94] remove notes regarding `@Default` annotation --- src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java | 2 +- src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java | 2 +- src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index a853e6e1..d5ebb00e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -29,7 +29,7 @@ public enum CreateCMD { @Permission("fancynpcs.command.npc.create") public void onCreateCommand(final @NotNull CommandSender sender, final @NotNull @Regex("^[A-Za-z0-9_-]*$") String name, - final @Nullable @Flag("type") EntityType type, // NOTE: Replace with @Default once fixed. + final @Nullable @Flag("type") EntityType type, final @Nullable @Flag("position") Location position, final @Nullable @Flag("world") World world ) { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java index ab8505b6..f93bc933 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java @@ -34,7 +34,7 @@ public enum ListCMD { public void onCommand( final CommandSender sender, final @Nullable @Flag("type") EntityType type, - final @Nullable @Flag("sort") SortType sort // NOTE: Replace with @Default once fixed. + final @Nullable @Flag("sort") SortType sort ) { Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); // Excluding NPCs not created by the sender, if PLAYER_NPCS_FEATURE_FLAG is enabled and sender is a player. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java index a16fd1cf..7a07d697 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java @@ -35,7 +35,7 @@ public void onCommand( final Player sender, final @Nullable @Flag("radius") Long radius, final @Nullable @Flag("type") EntityType type, - final @Nullable @Flag("sort") SortType sort // NOTE: Replace with @Default once fixed. + final @Nullable @Flag("sort") SortType sort ) { Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); // Getting location of the sender. From 911ff91a1fc5c6ab66bcacb98cd5ad0986f17916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 8 May 2024 13:27:39 +0200 Subject: [PATCH 58/94] add missing error message when creating npc and no world has been specified (console only) --- src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java | 2 +- src/main/resources/languages/en.yml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index d5ebb00e..5f093ee0 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -43,7 +43,7 @@ public void onCreateCommand(final @NotNull CommandSender sender, // Setting the world of specified location. if (location.getWorld() == null) { if (world == null) { - sender.sendMessage("must specify world"); + translator.translate("npc_create_failure_must_specify_world").send(sender); return; } location.setWorld(world); diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 1c40ce6e..1e2b74c8 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -94,6 +94,7 @@ messages: npc_create_syntax: "Syntax: {primaryColor}/npc create {secondaryColor}(npc)" npc_create_success: "NPC {warningColor}{npc} has been created." npc_create_failure_already_exists: "› {errorColor}NPC {warningColor}{npc}{errorColor} already exists." + npc_create_failure_must_specify_world: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." npc_displayname_syntax: "Syntax: {primaryColor}/npc displayname {secondaryColor}(npc) (name)" npc_displayname_set_name: "NPC {warningColor}{npc} is now using {name} as their display name." @@ -179,7 +180,7 @@ messages: npc_nearby_footer: "Showing {warningColor}{count} out of total {warningColor}{total} entries in your world." npc_list_failure_sort_requires_player: "› {errorColor}This sort type cannot be used from the console." - npc_list_failure_requires_world_flag: "› {errorColor}You must specify a {warningColor}--world{errorColor} flag when running this command from the console." + npc_list_failure_requires_world_flag: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." npc_move_to_syntax: "Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" npc_move_to_success: "NPC {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." From fe51a4c9d596046a5796f7b5b44cdeab92ccd7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 8 May 2024 15:21:44 +0200 Subject: [PATCH 59/94] make `/npc list` and `/npc nearby` look better --- .../fancynpcs/commands/npc/ListCMD.java | 35 ++++++++-------- .../fancynpcs/commands/npc/NearbyCMD.java | 41 ++++++++++--------- src/main/resources/languages/en.yml | 12 +++--- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java index f93bc933..92d5b453 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java @@ -3,7 +3,6 @@ import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; -import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -36,40 +35,44 @@ public void onCommand( final @Nullable @Flag("type") EntityType type, final @Nullable @Flag("sort") SortType sort ) { - Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); + Stream stream = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); // Excluding NPCs not created by the sender, if PLAYER_NPCS_FEATURE_FLAG is enabled and sender is a player. if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && sender instanceof Player player) - npcs = npcs.filter(npc -> npc.getData().getCreator().equals(player.getUniqueId())); + stream = stream.filter(npc -> npc.getData().getCreator().equals(player.getUniqueId())); // Excluding NPCs that are not of a specified type, if desired. if (type != null) - npcs = npcs.filter(npc -> npc.getData().getType() == type); - // Sorting... + stream = stream.filter(npc -> npc.getData().getType() == type); + // Sorting based on SortType choice. Defaults to SortType.NAME. There might be more sort types in the future which should be handled here accordingly. switch (sort != null ? sort : SortType.NAME) { - case NAME -> npcs = npcs.sorted(Comparator.comparing(npc -> npc.getData().getName())); - case NAME_REVERSED -> npcs = npcs.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); // This needs a cast for some reason. + case NAME -> stream = stream.sorted(Comparator.comparing(npc -> npc.getData().getName())); + case NAME_REVERSED -> stream = stream.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); // This needs a cast for some reason. } translator.translate("npc_list_header").send(sender); + // Using AtomicInteger counter because streams don't expose entry index. final AtomicInteger count = new AtomicInteger(0); - // ... - npcs.toList().forEach(npc -> { - final Location location = npc.getData().getLocation(); - // ... + // Iterating over each NPC referenced in the stream. Usage of forEachOrdered should presumably preserve element order. + stream.forEachOrdered(npc -> { translator.translate("npc_list_entry") .replace("number", String.valueOf(count.incrementAndGet())) .replace("npc", npc.getData().getName()) - .replace("location_x", COORDS_FORMAT.format(location.x())) - .replace("location_y", COORDS_FORMAT.format(location.y())) - .replace("location_z", COORDS_FORMAT.format(location.z())) - .replace("world", location.getWorld().getName()) + .replace("location_x", COORDS_FORMAT.format(npc.getData().getLocation().x())) + .replace("location_y", COORDS_FORMAT.format(npc.getData().getLocation().y())) + .replace("location_z", COORDS_FORMAT.format(npc.getData().getLocation().z())) + .replace("world", npc.getData().getLocation().getWorld().getName()) .send(sender); }); + final int totalCount = FancyNpcs.getInstance().getNpcManager().getAllNpcs().size(); translator.translate("npc_list_footer") .replace("count", String.valueOf(count)) + .replace("count_formatted", "· ".repeat(3 - String.valueOf(count).length()) + count) .replace("total", String.valueOf(FancyNpcs.getInstance().getNpcManager().getAllNpcs().size())) + .replace("total_formatted", "· ".repeat(3 - String.valueOf(totalCount).length()) + totalCount) .send(sender); } - // SortType enum contains all possible sort types for the '/npc list' command. + /** + * {@link SortType ListCMD.SortType} enum contains all possible sort types for the {@code /npc list} command. + */ public enum SortType { NAME, NAME_REVERSED } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java index 7a07d697..24454e7c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java @@ -37,14 +37,14 @@ public void onCommand( final @Nullable @Flag("type") EntityType type, final @Nullable @Flag("sort") SortType sort ) { - Stream npcs = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); - // Getting location of the sender. - final Location location = sender.getLocation(); + Stream stream = FancyNpcs.getInstance().getNpcManagerImpl().getAllNpcs().stream(); + // Getting senderLocation of the sender. + final Location senderLocation = sender.getLocation(); // Creating a counter which is increased by 1 for every NPC present in player's world. final AtomicInteger totalCount = new AtomicInteger(0); // Excluding NPCs from different worlds. This also increments the counter defined above. - npcs = npcs.filter(npc -> { - if (npc.getData().getLocation().getWorld().equals(location.getWorld())) { + stream = stream.filter(npc -> { + if (npc.getData().getLocation().getWorld().equals(senderLocation.getWorld())) { totalCount.incrementAndGet(); return true; } @@ -52,39 +52,40 @@ public void onCommand( }); // Excluding NPCs not created by the sender, if PLAYER_NPCS_FEATURE_FLAG is enabled and sender is a player. if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled()) - npcs = npcs.filter(npc -> npc.getData().getCreator().equals(sender.getUniqueId())); - // Excluding NPCs that are not in radius, if specified and sender is a player. (radius is calculated from the location of player) + stream = stream.filter(npc -> npc.getData().getCreator().equals(sender.getUniqueId())); + // Excluding NPCs that are not in radius, if specified and sender is a player. (radius is calculated from the senderLocation of player) if (radius != null) - npcs = npcs.filter(npc -> npc.getData().getLocation().distance(location) <= radius); + stream = stream.filter(npc -> npc.getData().getLocation().distance(senderLocation) <= radius); // Excluding NPCs that are not of a specified type, if desired. if (type != null) - npcs = npcs.filter(npc -> npc.getData().getType() == type); - // Sorting... + stream = stream.filter(npc -> npc.getData().getType() == type); + // Sorting based on SortType choice. Defaults to SortType.NEAREST. There might be more sort types in the future which should be handled here accordingly. switch (sort != null ? sort : SortType.NEAREST) { // This should never produce NPE. - case NAME -> npcs = npcs.sorted(Comparator.comparing(npc -> npc.getData().getName())); - case NAME_REVERSED -> npcs = npcs.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); - case NEAREST -> npcs = npcs.sorted(Comparator.comparingDouble(npc -> npc.getData().getLocation().distance(location))); - case FARTHEST -> npcs = npcs.sorted(Comparator.comparingDouble(npc -> ((Npc) npc).getData().getLocation().distance(location)).reversed()); + case NAME -> stream = stream.sorted(Comparator.comparing(npc -> npc.getData().getName())); + case NAME_REVERSED -> stream = stream.sorted(Comparator.comparing(npc -> ((Npc) npc).getData().getName()).reversed()); + case NEAREST -> stream = stream.sorted(Comparator.comparingDouble(npc -> npc.getData().getLocation().distance(senderLocation))); + case FARTHEST -> stream = stream.sorted(Comparator.comparingDouble(npc -> ((Npc) npc).getData().getLocation().distance(senderLocation)).reversed()); } - // Printing the header. translator.translate("npc_nearby_header").send(sender); - // Creating a counter which is increased by 1 for every NPC that is "selected" in this query. + // Using AtomicInteger counter because streams don't expose entry index. final AtomicInteger count = new AtomicInteger(0); - // Printing each entry. - npcs.toList().forEach(npc -> { + // Iterating over each NPC referenced in the stream. Usage of forEachOrdered should presumably preserve element order. + stream.forEachOrdered(npc -> { translator.translate("npc_nearby_entry") .replace("number", String.valueOf(count.incrementAndGet())) .replace("npc", npc.getData().getName()) - .replace("distance", DISTANCE_FORMAT.format(npc.getData().getLocation().distance(location))) + .replace("distance", DISTANCE_FORMAT.format(npc.getData().getLocation().distance(senderLocation))) .replace("location_x", COORDS_FORMAT.format(npc.getData().getLocation().x())) .replace("location_y", COORDS_FORMAT.format(npc.getData().getLocation().y())) .replace("location_z", COORDS_FORMAT.format(npc.getData().getLocation().z())) + .replace("world", npc.getData().getLocation().getWorld().getName()) .send(sender); }); - // Printing the footer. translator.translate("npc_nearby_footer") .replace("count", String.valueOf(count)) + .replace("count_formatted", "· ".repeat(3 - String.valueOf(count).length()) + count) .replace("total", String.valueOf(totalCount)) + .replace("total_formatted", "· ".repeat(3 - String.valueOf(totalCount).length()) + totalCount) .send(sender); } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 1e2b74c8..e8869982 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -170,14 +170,14 @@ messages: npc_remove_success: "NPC {warningColor}{npc} has been removed." npc_list_syntax: "Syntax: {primaryColor}/npc list {secondaryColor}[filters...]" - npc_list_header: "Listing results for requested query:" - npc_list_entry: "› <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({location_x}, {location_y}, {location_z} in {world})" - npc_list_footer: "Showing {warningColor}{count} out of total {warningColor}{total} entries in all worlds." + npc_list_header: "------------------ List Query Result ------------------" + npc_list_entry: " <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({location_x}, {location_y}, {location_z} in {world})" + npc_list_footer: "---------- Showing {warningColor}{count_formatted} out of total {warningColor}{total_formatted} entries ----------" npc_nearby_syntax: "Syntax: {primaryColor}/npc nearby {secondaryColor}[filters...]" - npc_nearby_header: "Listing results for requested query:" - npc_nearby_entry: "› <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({distance} blocks away)" - npc_nearby_footer: "Showing {warningColor}{count} out of total {warningColor}{total} entries in your world." + npc_nearby_header: "---------------- Nearby Query Result -----------------" + npc_nearby_entry: " <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({distance} blocks away)" + npc_nearby_footer: "---------- Showing {warningColor}{count_formatted} out of total {warningColor}{total_formatted} entries ----------" npc_list_failure_sort_requires_player: "› {errorColor}This sort type cannot be used from the console." npc_list_failure_requires_world_flag: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." From 149889fce0551d4bbdd27f183d129ee014251f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Thu, 9 May 2024 22:01:56 +0200 Subject: [PATCH 60/94] fix comments and translations for `/npc message` --- .../fancynpcs/commands/npc/MessageCMD.java | 24 +++++++------------ src/main/resources/languages/en.yml | 4 ++-- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index 140aa6b4..8ba90199 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -47,7 +47,7 @@ public void onMessageAdd(final CommandSender sender, final Npc npc) { public void onMessageAdd(final CommandSender sender, final Npc npc, final @Argument(suggestions = "MessageCMD/none") @Greedy String message) { // Handling '@none' as an empty message. final String finalMessage = message.equalsIgnoreCase("@none") ? "" : message; - // Exiting the command block in case banned command has been found in the message. + // Sending error message in case banned command has been found in the input. if (hasBlockedCommands(finalMessage)) { translator.translate("command_input_contains_blocked_command").send(sender); return; @@ -55,7 +55,6 @@ public void onMessageAdd(final CommandSender sender, final Npc npc, final @Argum // Calling the event and adding message if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_ADD, finalMessage, sender).callEvent()) { npc.getData().getMessages().add(finalMessage); - // Sending success message to the sender. translator.translate("npc_message_add_success").replace("total", String.valueOf(npc.getData().getMessages().size())).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); @@ -75,7 +74,7 @@ public void onMessageSet(final CommandSender sender, final Npc npc) { public void onMessageSet(final CommandSender sender, final Npc npc, final @Argument(suggestions = "MessageCMD/number_range") int number, final @Argument(suggestions = "MessageCMD/none") @Greedy String message) { // Handling '@none' as an empty message. final String finalMessage = message.equalsIgnoreCase("@none") ? "" : message; - // Sending error message in case banned command has been found in the message. + // Sending error message in case banned command has been found in the input. if (hasBlockedCommands(finalMessage)) { translator.translate("command_input_contains_blocked_command").send(sender); return; @@ -87,7 +86,7 @@ public void onMessageSet(final CommandSender sender, final Npc npc, final @Argum translator.translate("npc_message_set_failure_list_is_empty").send(sender); return; } - // Sending error message Exiting command block if provided number is lower than 0 or higher than the list size. + // Sending error message if provided number is lower than 0 or higher than the list size. if (number < 1 || number > totalCount) { translator.translate("npc_message_set_failure_not_in_range").replace("input", String.valueOf(number)).replace("max", String.valueOf(totalCount)).send(sender); return; @@ -97,7 +96,6 @@ public void onMessageSet(final CommandSender sender, final Npc npc, final @Argum // Calling the event and setting message if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SET, new Object[]{index, finalMessage}, sender).callEvent()) { npc.getData().getMessages().set(index, finalMessage); - // Sending success message to the sender. translator.translate("npc_message_set_success") .replace("number", String.valueOf(number)) .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. @@ -111,7 +109,7 @@ public void onMessageSet(final CommandSender sender, final Npc npc, final @Argum @Command("npc message remove") @Permission("fancynpcs.command.npc.message.remove") - public void onMessageRemoveSyntax(final CommandSender sender, final Npc npc) { + public void onMessageRemove(final CommandSender sender, final Npc npc) { translator.translate("npc_message_remove_syntax").send(sender); } @@ -125,7 +123,7 @@ public void onMessageRemove(final CommandSender sender, final Npc npc, final @Ar translator.translate("npc_message_remove_failure_list_is_empty").send(sender); return; } - // Sending error message Exiting command block if provided number is lower than 0 or higher than the list size. + // Sending error message if provided number is lower than 0 or higher than the list size. if (number < 1 || number > totalCount) { translator.translate("npc_message_remove_failure_not_in_range").replace("input", String.valueOf(number)).replace("max", String.valueOf(totalCount)).send(sender); return; @@ -137,7 +135,6 @@ public void onMessageRemove(final CommandSender sender, final Npc npc, final @Ar // Calling the event and removing message if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_REMOVE, new Object[]{index, message}, sender).callEvent()) { npc.getData().getMessages().remove(index); - // Sending success message to the sender. translator.translate("npc_message_remove_success") .replace("number", String.valueOf(number)) .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. @@ -172,18 +169,15 @@ public void onMessageList(final CommandSender sender, final Npc npc) { translator.translate("npc_message_list_failure_empty").send(sender); return; } - // Sending header to the sender. translator.translate("npc_message_list_header").send(sender); - // Iterating over all messages attached to this NPC. + // Iterating over all messages attached to this NPC and sending them to the sender. for (int i = 0; i < npc.getData().getMessages().size(); i++) { final String message = npc.getData().getMessages().get(i); - // Sending message entry to the sender. translator.translate("npc_message_list_entry") .replace("number", String.valueOf(i + 1)) .replace("message", message) .send(sender); } - // Sending footer to the sender. translator.translate("npc_message_list_footer").send(sender); } @@ -193,11 +187,10 @@ public void onMessageList(final CommandSender sender, final Npc npc) { @Permission("fancynpcs.command.npc.message.send_randomly") public void onMessageSendRandomly(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { final boolean finalState = state != null ? state : !npc.getData().isSendMessagesRandomly(); - // ... + // Calling the event and setting send_randomly state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SEND_RANDOMLY, finalState, sender).callEvent()) { npc.getData().setSendMessagesRandomly(finalState); npc.updateForAll(); - // Sending success message to the sender. translator.translate(finalState ? "npc_message_send_randomly_set_true" : "npc_message_send_randomly_set_false").replace("npc", npc.getData().getName()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); @@ -211,10 +204,9 @@ public List suggestNone(final CommandContext context, fin return NONE_SUGGESTIONS; } - @Suggestions("MessageCMD/number_range") + @Suggestions("MessageCMD/number_range") // Generates number range suggestions based on the number of messages. public List suggestNumber(final CommandContext context, final CommandInput input) { final Npc npc = context.getOrDefault("npc", null); - // Returning... return npc == null || npc.getData().getMessages().isEmpty() ? Collections.emptyList() : new ArrayList<>() {{ diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index e8869982..8ca9440c 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -198,10 +198,10 @@ messages: npc_show_in_tab_set_true: "NPC {warningColor}{npc} is now shown in player-list." npc_show_in_tab_set_false: "NPC {warningColor}{npc} is no longer shown in player-list." - npc_message_add_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) add (none | message)" + npc_message_add_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) add (@none | message)" npc_message_add_success: "Message has been added. There is {warningColor}{total} messages in total." - npc_message_set_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) set (number) (none | message)" + npc_message_set_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) set (number) (@none | message)" npc_message_set_success: "Message {warningColor}{number} has been updated. There is {warningColor}{total} messages in total." npc_message_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_message_set_failure_list_is_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." From e10e3979fffa07eb2a4e6d6aa43a201076eb2358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Thu, 9 May 2024 22:02:24 +0200 Subject: [PATCH 61/94] add `/npc player_command` --- .../commands/CloudCommandManager.java | 3 +- .../commands/npc/PlayerCommandCMD.java | 346 ++++++++---------- src/main/resources/languages/en.yml | 22 ++ 3 files changed, 184 insertions(+), 187 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 48ba0f2c..2e07d2ab 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -19,6 +19,7 @@ import de.oliver.fancynpcs.commands.npc.MoveToCMD; import de.oliver.fancynpcs.commands.npc.NearbyCMD; import de.oliver.fancynpcs.commands.npc.NpcCMD; +import de.oliver.fancynpcs.commands.npc.PlayerCommandCMD; import de.oliver.fancynpcs.commands.npc.RemoveCMD; import de.oliver.fancynpcs.commands.npc.ShowInTabCMD; import de.oliver.fancynpcs.commands.npc.SkinCMD; @@ -85,7 +86,7 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig annotationParser.parse(ListCMD.INSTANCE); annotationParser.parse(MessageCMD.INSTANCE); // annotationParser.parse(ServerCommandCMD.INSTANCE); - // annotationParser.parse(PlayerCommandCMD.INSTANCE); + annotationParser.parse(PlayerCommandCMD.INSTANCE); annotationParser.parse(MoveHereCMD.INSTANCE); annotationParser.parse(NearbyCMD.INSTANCE); annotationParser.parse(NpcCMD.INSTANCE); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java index a51c86bd..fc968698 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java @@ -1,228 +1,202 @@ package de.oliver.fancynpcs.commands.npc; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.LinkedList; +import org.incendo.cloud.annotation.specifier.Greedy; +import org.incendo.cloud.annotations.Argument; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; + +import java.util.ArrayList; +import java.util.Collections; import java.util.List; -public class PlayerCommandCMD implements Subcommand { - - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); - - @Override - public List tabcompletion(@NotNull Player playedr, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return List.of("add", "set", "remove", "clear"); - } else if (args.length == 4) { - if (args[2].equalsIgnoreCase("set") || args[2].equalsIgnoreCase("remove")) { - List commands = new LinkedList<>(); - for (int i = 0; i < npc.getData().getPlayerCommands().size(); i++) { - commands.add(String.valueOf(i + 1)); - } - return commands; - } - } else if (args.length == 5) { - if (args[2].equalsIgnoreCase("set")) { - int index; - try { - index = Integer.parseInt(args[3]); - } catch (NumberFormatException e) { - return null; - } - - if (index < 1 || index > npc.getData().getPlayerCommands().size()) { - return null; - } - - return List.of(npc.getData().getPlayerCommands().get(index - 1)); - } - } - - return null; - } - - @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); - return false; - } - - if (args.length == 3 && args[2].equalsIgnoreCase("clear")) { - return clearCommand(receiver, npc, args); - } +import org.jetbrains.annotations.NotNull; - if (args.length == 4 && args[2].equalsIgnoreCase("remove")) { - return removeCommand(receiver, npc, args); - } +public enum PlayerCommandCMD { + INSTANCE; // SINGLETON - if (args.length >= 4 && args[2].equalsIgnoreCase("add")) { - return addCommand(receiver, npc, args); - } + private final Translator translator = FancyNpcs.getInstance().getTranslator(); - if (args.length >= 5 && args[2].equalsIgnoreCase("set")) { - return setCommand(receiver, npc, args); - } + /* PLAYER_COMMAND ADD */ - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; + @Command("npc player_command add") + @Permission("fancynpcs.command.npc.player_command.add") + public void onPlayerCommandAdd(final CommandSender sender, final Npc npc) { + translator.translate("npc_player_command_add_syntax").send(sender); } - private boolean addCommand(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - String command = ""; - for (int i = 3; i < args.length; i++) { - command += args[i] + " "; - } - - command = command.substring(0, command.length() - 1); - - if (command.equalsIgnoreCase("none")) { - command = ""; - } - - if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && isBlockedCommand(command.toLowerCase())) { - MessageHelper.error(receiver, lang.get("illegal-command")); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND, command, receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().addPlayerCommand(command); - MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated", "npc", npc.getData().getName())); + @Command("npc player_command add ") + @Permission("fancynpcs.command.npc.player_command.add") + public void onPlayerCommandAdd(final CommandSender sender, final Npc npc, final @Greedy String command) { + // Sending error message in case banned command has been found in the input. + if (hasBlockedCommands(command)) { + translator.translate("command_input_contains_blocked_command").send(sender); + return; + } + // Calling the event and adding player command if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND_ADD, command, sender).callEvent()) { + npc.getData().getPlayerCommands().add(command); + translator.translate("npc_player_command_add_success").replace("total", String.valueOf(npc.getData().getPlayerCommands().size())).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } - private boolean setCommand(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 4) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } + /* PLAYER_COMMAND SET */ - int index; - try { - index = Integer.parseInt(args[3]); - } catch (NumberFormatException e) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - if (index < 1 || index > npc.getData().getPlayerCommands().size()) { - MessageHelper.error(receiver, lang.get("npc-command-playercommand-invalid-index", "input", String.valueOf(index))); - return false; - } - - String command = ""; - for (int i = 4; i < args.length; i++) { - command += args[i] + " "; - } - - command = command.substring(0, command.length() - 1); - - if (command.equalsIgnoreCase("none")) { - command = ""; - } - - if (isBlockedCommand(command.toLowerCase())) { - MessageHelper.error(receiver, lang.get("illegal-command")); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND, command, receiver); - npcModifyEvent.callEvent(); + @Command("npc player_command set") + @Permission("fancynpcs.command.npc.player_command.set") + public void onPlayerCommandSet(final CommandSender sender, final Npc npc) { + translator.translate("npc_player_command_set_syntax").send(sender); + } - if (!npcModifyEvent.isCancelled()) { - npc.getData().getPlayerCommands().set(index - 1, command); - MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated", "npc", npc.getData().getName())); + @Command("npc player_command set ") + @Permission("fancynpcs.command.npc.player_command.set") + public void onPlayerCommandSet(final CommandSender sender, final Npc npc, final @Argument(suggestions = "PlayerCommandCMD/number_range") int number, final @Greedy String command) { + // Sending error message in case banned command has been found in the input. + if (hasBlockedCommands(command)) { + translator.translate("command_input_contains_blocked_command").send(sender); + return; + } + // Getting the total count of player commands that are currently in the list. + final int totalCount = npc.getData().getPlayerCommands().size(); + // Sending error message if the list is empty. + if (totalCount == 0) { + translator.translate("npc_player_command_set_failure_list_is_empty").send(sender); + return; + } + // Sending error message if provided number is lower than 0 or higher than the list size. + if (number < 1 || number > totalCount) { + translator.translate("npc_player_command_set_failure_not_in_range").replace("input", String.valueOf(number)).replace("max", String.valueOf(totalCount)).send(sender); + return; + } + // User-specified number starts from 1, while index starts from 0. Subtracting 1 from the provided number to get the list index. + final int index = number - 1; + // Calling the event and setting player command if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND_SET, new Object[]{index, command}, sender).callEvent()) { + npc.getData().getPlayerCommands().set(index, command); + translator.translate("npc_player_command_set_success") + .replace("number", String.valueOf(number)) + .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. + .send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } - private boolean removeCommand(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } + /* PLAYER_COMMAND REMOVE */ - int index; - try { - index = Integer.parseInt(args[3]); - } catch (NumberFormatException e) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - if (index < 1 || index > npc.getData().getPlayerCommands().size()) { - MessageHelper.error(receiver, lang.get("npc-command-playercommand-invalid-index", "input", String.valueOf(index))); - return false; - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND, "", receiver); - npcModifyEvent.callEvent(); + @Command("npc player_command remove") + @Permission("fancynpcs.command.npc.player_command.remove") + public void onPlayerCommandRemove(final CommandSender sender, final Npc npc) { + translator.translate("npc_player_command_remove_syntax").send(sender); + } - if (!npcModifyEvent.isCancelled()) { - npc.getData().removePlayerCommand(index - 1); - MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated", "npc", npc.getData().getName())); + @Command("npc player_command remove ") + @Permission("fancynpcs.command.npc.player_command.remove") + public void onPlayerCommandRemove(final CommandSender sender, final Npc npc, final @Argument(suggestions = "PlayerCommandCMD/number_range") int number) { + // Getting the total count of player commands that are currently in the list. + final int totalCount = npc.getData().getPlayerCommands().size(); + // Sending error message if the list is empty. + if (totalCount == 0) { + translator.translate("npc_player_command_remove_failure_list_is_empty").send(sender); + return; + } + // Sending error message if provided number is lower than 0 or higher than the list size. + if (number < 1 || number > totalCount) { + translator.translate("npc_player_command_remove_failure_not_in_range").replace("input", String.valueOf(number)).replace("max", String.valueOf(totalCount)).send(sender); + return; + } + // User-specified number starts from 1, while index starts from 0. Subtracting 1 from the provided number to get the list index. + final int index = number - 1; + // Getting the message to pass to the NpcModifyEvent. + final String command = npc.getData().getPlayerCommands().get(index); + // Calling the event and removing player command if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND_REMOVE, new Object[]{index, command}, sender).callEvent()) { + npc.getData().getPlayerCommands().remove(index); + // Sending success message to the sender. + translator.translate("npc_player_command_remove_success") + .replace("number", String.valueOf(number)) + .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. + .send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } - private boolean clearCommand(CommandSender receiver, Npc npc, String[] args) { - if (args.length < 2) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } + /* PLAYER_COMMAND CLEAR */ - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND, "", receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { + @Command("npc player_command clear") + @Permission("fancynpcs.command.npc.player_command.clear") + public void onPlayerCommandClear(final CommandSender sender, final Npc npc) { + final int total = npc.getData().getPlayerCommands().size(); + // Calling the event and clearing player commands if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND_CLEAR, null, sender).callEvent()) { npc.getData().getPlayerCommands().clear(); - MessageHelper.success(receiver, lang.get("npc-command-playercommand-updated", "npc", npc.getData().getName())); + translator.translate("npc_player_command_clear_success").replace("total", String.valueOf(total)).send(sender); } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } + } + + /* PLAYER_COMMAND LIST */ + + @Command("npc player_command list") + @Permission("fancynpcs.command.npc.player_command.list") + public void onPlayerCommandList(final CommandSender sender, final Npc npc) { + // Sending error message if the list is empty. + if (npc.getData().getPlayerCommands().isEmpty()) { + translator.translate("npc_player_command_list_failure_empty").send(sender); + return; + } + translator.translate("npc_player_command_list_header").send(sender); + // Iterating over all player commands attached to this NPC and sending them to the sender. + for (int i = 0; i < npc.getData().getPlayerCommands().size(); i++) { + final String command = npc.getData().getPlayerCommands().get(i); + translator.translate("npc_player_command_list_entry") + .replace("number", String.valueOf(i + 1)) + .replace("command", command) + .send(sender); + } + translator.translate("npc_player_command_list_footer").send(sender); + } - return true; + /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ + + @Suggestions("PlayerCommandCMD/number_range") // Generates number range suggestions based on the number of player commands. + public List suggestNumber(final CommandContext context, final CommandInput input) { + final Npc npc = context.getOrDefault("npc", null); + return npc == null || npc.getData().getPlayerCommands().isEmpty() + ? Collections.emptyList() + : new ArrayList<>() {{ + for (int i = 0; i < npc.getData().getPlayerCommands().size(); i++) + add(String.valueOf(i + 1)); + }}; } - private boolean isBlockedCommand(String cmd) { - for (String blockedCommand : FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands()) { - if (cmd.equalsIgnoreCase(blockedCommand) || cmd.toLowerCase().startsWith(blockedCommand.toLowerCase() + " ")) { + /* UTILITY METHODS */ + + /** Returns {@code true} if specified string contains a blocked command, {@code false} otherwise. */ + private boolean hasBlockedCommands(final @NotNull String string) { + // Getting the list of all blocked commands. + final List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); + // Iterating over list of blocked commands... + for (final String blockedCommand : blockedCommands) { + // Transforming the command to a base command with trailed whitespaces and slashes. This also removes namespaced part from the beginning of the command. + final String transformedBaseCommand = blockedCommand.replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", ""); + // Comparing click event value with the transformed base command. Returning the result. + if (string.replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", "").equalsIgnoreCase(transformedBaseCommand)) return true; - } } - + // Returning false as no blocked commands has been found. return false; } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 8ca9440c..48fc1f66 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -220,3 +220,25 @@ messages: npc_message_list_entry: " <#848484>{number}. {message}" npc_message_list_footer: "---------------------------------------------------" npc_message_list_failure_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." + + npc_player_command_add_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) add (command)" + npc_player_command_add_success: "Command has been added. There is {warningColor}{total} commands in total." + + npc_player_command_set_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) set (number) (command)" + npc_player_command_set_success: "Command {warningColor}{number} has been updated. There is {warningColor}{total} commands in total." + npc_player_command_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." + npc_player_command_set_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." + + npc_player_command_remove_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) remove (number)" + npc_player_command_remove_success: "Command {warningColor}{number} has been removed. There is {warningColor}{total} commands in total." + npc_player_command_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." + npc_player_command_remove_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." + + npc_player_command_clear_success: "Commands have been cleared. There was {warningColor}{total} commands in total." + + npc_player_command_list_header: "----------------- Player Commands -----------------" + npc_player_command_list_entry: " <#848484>{number}. {command}" + npc_player_command_list_footer: "---------------------------------------------------" + npc_player_command_list_failure_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." + + From e2a1f8473281bbc1bebef7c8e67081b16a9e97ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 11 May 2024 01:34:28 +0200 Subject: [PATCH 62/94] `/npc attribute` and `/npc equipment` --- .../commands/CloudCommandManager.java | 2 - .../commands/arguments/NpcArgument.java | 3 +- .../arguments/NpcAttributeArgument.java | 46 ----- .../fancynpcs/commands/npc/AttributeCMD.java | 94 +++++++--- .../fancynpcs/commands/npc/EquipmentCMD.java | 162 ++++++++++++++++-- src/main/resources/languages/en.yml | 49 +++--- 6 files changed, 244 insertions(+), 112 deletions(-) delete mode 100644 src/main/java/de/oliver/fancynpcs/commands/arguments/NpcAttributeArgument.java diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 2e07d2ab..68b9f7c3 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -2,7 +2,6 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.commands.arguments.NpcArgument; -import de.oliver.fancynpcs.commands.arguments.NpcAttributeArgument; import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; import de.oliver.fancynpcs.commands.npc.AttributeCMD; import de.oliver.fancynpcs.commands.npc.CollidableCMD; @@ -63,7 +62,6 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig this.annotationParser = new AnnotationParser<>(commandManager, CommandSender.class); // Registering parsers and suggestion providers. annotationParser.parse(NpcArgument.INSTANCE); - annotationParser.parse(NpcAttributeArgument.INSTANCE); // Registering exception handlers. commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(ReplyingParseException.class)); commandManager.exceptionController().registerHandler(ReplyingParseException.class, context -> context.exception().runnable().run()); diff --git a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java index c026feb9..52c3a245 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java +++ b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java @@ -23,7 +23,8 @@ public enum NpcArgument { private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Parser(suggestions = "npc") + // This parser does not specify a name, making it default parser for the returned type. + @Parser(name = "", suggestions = "npc") public @NotNull Npc parse(final CommandContext context, final CommandInput input) { // Reading next argument as single/literal String. final String value = input.readString(); diff --git a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcAttributeArgument.java b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcAttributeArgument.java deleted file mode 100644 index 2527b4f5..00000000 --- a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcAttributeArgument.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.oliver.fancynpcs.commands.arguments; - -import de.oliver.fancylib.translations.Translator; -import de.oliver.fancynpcs.FancyNpcs; -import de.oliver.fancynpcs.api.AttributeManager; -import de.oliver.fancynpcs.api.Npc; -import de.oliver.fancynpcs.api.NpcAttribute; -import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; -import org.bukkit.command.CommandSender; -import org.incendo.cloud.annotations.parser.Parser; -import org.incendo.cloud.annotations.suggestion.Suggestions; -import org.incendo.cloud.context.CommandContext; -import org.incendo.cloud.context.CommandInput; - -import java.util.List; - -public enum NpcAttributeArgument { - INSTANCE; // SINGLETON - - private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private final AttributeManager attributeManager = FancyNpcs.getInstance().getAttributeManager(); - - @Parser(suggestions = "attribute") - public NpcAttribute parser(final CommandContext context, final CommandInput input) { - // Getting npc argument that already should exist within the command context. - final Npc npc = context.get("npc"); - // Reading the string, which is supposed to be an attribute name. - final String value = input.readString(); - // Getting the NpcAttribute from the name and npc type. - final NpcAttribute attribute = attributeManager.getAttributeByName(npc.getData().getType(), value); - // Throwing exception when non-existent attribute has been provided. - if (attribute == null) - throw ReplyingParseException.replying(() -> translator.translate("npc_attribute_invalid_for_this_entity_type").send(context.sender())); - // Otherwise, returning the attribute from the parser. - return attribute; - } - - @Suggestions("attribute") - public List suggestions(final CommandContext context, final CommandInput input) { - // Getting npc argument that already should exist within the command context. - final Npc npc = context.getOrDefault("npc", null); - // Mapping and returning list of suggestions. - return attributeManager.getAllAttributesForEntityType(npc.getData().getType()).stream().map(NpcAttribute::getName).toList(); - } - -} diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java index 0a1491bc..b453cba2 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java @@ -1,52 +1,37 @@ package de.oliver.fancynpcs.commands.npc; import de.oliver.fancylib.translations.Translator; -import de.oliver.fancynpcs.AttributeManagerImpl; import de.oliver.fancynpcs.FancyNpcs; +import de.oliver.fancynpcs.api.AttributeManager; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.NpcAttribute; import de.oliver.fancynpcs.api.events.NpcModifyEvent; +import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.parser.Parser; import org.incendo.cloud.annotations.suggestion.Suggestions; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; -import java.util.Collections; import java.util.List; public enum AttributeCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private final AttributeManagerImpl attributeManager = FancyNpcs.getInstance().getAttributeManager(); + private final AttributeManager attributeManager = FancyNpcs.getInstance().getAttributeManager(); - @Suggestions("attribute_value") - public List attributeValueSuggestions(final CommandContext context, final CommandInput input) { - final Npc npc = context.getOrDefault("npc", null); - final NpcAttribute attribute = context.getOrDefault("attribute", null); - // ... - if (attribute != null && npc != null) - return attributeManager.getAttributeByName(npc.getData().getType(), attribute.getName()).getPossibleValues(); - // ... - return Collections.emptyList(); - } - - @Command("npc attribute ") - @Permission("fancynpcs.command.npc.attribute") - public void onCommand( + @Command("npc attribute set ") + @Permission("fancynpcs.command.npc.attribute.set") + public void onAttributeSet( final CommandSender sender, final Npc npc, final NpcAttribute attribute, - final @Argument(suggestions = "attribute_value") String attributeValue + final @Argument(parserName = "AttributeCMD/attribute_value") String attributeValue ) { - if (!attribute.isValidValue(attributeValue)) { - translator.translate("npc_attribute_invalid_attribute_value").replace("input", attributeValue).send(sender); - return; - } - // ... if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.ATTRIBUTE, new Object[]{attribute, attributeValue}, sender).callEvent()) { npc.getData().addAttribute(attribute, attributeValue); npc.updateForAll(); @@ -56,4 +41,67 @@ public void onCommand( } } + @Command("npc attribute list") + @Permission("fancynpcs.command.npc.attribute.list") + public void onAttributeList(final CommandSender sender, final Npc npc) { + // Sending error message if the list is empty. + if (npc.getData().getAttributes().isEmpty()) { + translator.translate("npc_attribute_list_failure_empty").send(sender); + return; + } + translator.translate("npc_attribute_list_header").send(sender); + // Iterating over all attributes set on this NPC and sending them to the sender. + npc.getData().getAttributes().forEach((attribute, value) -> { + translator.translate("npc_attribute_list_entry") + .replace("attribute", attribute.getName()) + .replace("value", value) + .send(sender); + }); + translator.translate("npc_attribute_list_footer").send(sender); + } + + /* PARSERS AND SUGGESTION PROVIDERS */ + + // This parser does not specify a name, making it default parser for the returned type. + @Parser(name = "", suggestions = "AttributeCMD/attribute") + public NpcAttribute parseAttribute(final CommandContext context, final CommandInput input) { + // Getting the 'npc' argument that should already exist within the command context. + final Npc npc = context.get("npc"); + // Reading the string, which is supposed to be an attribute name. + final String value = input.readString(); + // Getting the NpcAttribute from the name and npc type. + final NpcAttribute attribute = attributeManager.getAttributeByName(npc.getData().getType(), value); + // Throwing exception when non-existent attribute has been provided. + if (attribute == null) + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_attribute").replace("input", value).send(context.sender())); + // Otherwise, returning the attribute from the parser. + return attribute; + } + + @Parser(name = "AttributeCMD/attribute_value", suggestions = "AttributeCMD/attribute_value") + public String parseAttributeValue(final CommandContext context, final CommandInput input) { + // Getting the 'attribute' argument that should already exist within the command context. + final NpcAttribute attribute = context.get("attribute"); + // Reading the string, which is supposed to be an attribute name. + final String value = input.readString(); + // Sending error message if attribute is null or cannot accept provided value. + if (!attribute.isValidValue(value)) + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_attribute_value").replace("input", value).send(context.sender())); + // Otherwise, returning the attribute from the parser. + return value; + } + + @Suggestions("AttributeCMD/attribute") + public List suggestAttribute(final CommandContext context, final CommandInput input) { + final Npc npc = context.getOrDefault("npc", null); + return attributeManager.getAllAttributesForEntityType(npc.getData().getType()).stream().map(NpcAttribute::getName).toList(); + } + + @Suggestions("AttributeCMD/attribute_value") + public List suggestAttributeValue(final CommandContext context, final CommandInput input) { + final Npc npc = context.get("npc"); + final NpcAttribute attribute = context.get("attribute"); + return FancyNpcs.getInstance().getAttributeManager().getAttributeByName(npc.getData().getType(), attribute.getName()).getPossibleValues(); + } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java index fdf82bd0..2cd7a4e6 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java @@ -1,40 +1,180 @@ package de.oliver.fancynpcs.commands.npc; import de.oliver.fancylib.translations.Translator; +import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; +import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.parser.Parser; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public enum EquipmentCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command(value = "npc equipment", requiredSender = Player.class) - @Permission("fancynpcs.command.npc.equipment") - public void onDefault(final Player sender) { - translator.translate("npc_equipment_syntax").send(sender); + // Storing in a static variable to avoid re-creating the array each time suggestion is requested. + private static final List SLOT_SUGGESTIONS = Arrays.stream(NpcEquipmentSlot.values()).map(slot -> slot.name().toLowerCase()).toList(); + private static final List MATERIAL_SUGGESTIONS = Registry.MATERIAL.stream().map(material -> material.key().asString()).toList(); + + @Command("npc equipment set") + @Permission("fancynpcs.command.npc.equipment.set") + public void onEquipmentSet(final CommandSender sender, final Npc npc) { + translator.translate("npc_equipment_set_syntax").send(sender); } - @Command(value = "npc equipment ", requiredSender = Player.class) - @Permission("fancynpcs.command.npc.equipment") - // NOTE: NpcEquipmentSlot and potentially other enums could use their own parser to keep the error message (somewhat) accurate. - public void onCommand(final Player sender, final Npc npc, final NpcEquipmentSlot slot) { - // Getting item player has currently in hand. - final ItemStack item = sender.getInventory().getItemInMainHand().clone(); + @Command("npc equipment set ") + @Permission("fancynpcs.command.npc.equipment.set") + public void onEquipmentSet( + final CommandSender sender, + final Npc npc, + final NpcEquipmentSlot slot, + final @Argument(parserName = "EquipmentCMD/item") ItemStack item + ) { + if (!(sender instanceof Player) && item == null) + translator.translate("command_player_only").send(sender); // Calling the event and updating equipment if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.EQUIPMENT, new Object[]{slot, item}, sender).callEvent()) { npc.getData().addEquipment(slot, item); npc.updateForAll(); - translator.translate("npc_equipment_success").replace("npc", npc.getData().getName()).send(sender); + translator.translate(item != null && item.getType() != Material.AIR ? "npc_equipment_set_item" : "npc_equipment_set_empty") + .replace("npc", npc.getData().getName()) + .replace("slot", getTranslatedSlot(slot)) + .addTagResolver(Placeholder.component("item", (item != null && item.getType() != Material.AIR) ? item.displayName().hoverEvent(item.asHoverEvent()) : Component.empty())) + .send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } } + @Command("npc equipment clear") + @Permission("fancynpcs.command.npc.equipment.clear") + public void onEquipmentClear(final CommandSender sender, final Npc npc) { + // Calling the event and clearing equipment if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.EQUIPMENT, null, sender).callEvent()) { + // Entries must be set to null manually because clearing the map would prevent equipment from being updated. (Npc#update checks if map is empty) + for (final NpcEquipmentSlot slot : NpcEquipmentSlot.values()) + npc.getData().getEquipment().put(slot, null); + npc.updateForAll(); + translator.translate("npc_equipment_clear_success").replace("npc", npc.getData().getName()).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + } + + @Command("npc equipment list") + @Permission("fancynpcs.command.npc.equipment.list") + public void onEquipmentList(final CommandSender sender, final Npc npc) { + // Sending error message if the list is empty or all items are Material.AIR. + if (npc.getData().getEquipment().isEmpty() || npc.getData().getEquipment().values().stream().allMatch(item -> item == null || item.getType() == Material.AIR)) { + translator.translate("npc_equipment_list_failure_empty").send(sender); + return; + } + translator.translate("npc_equipment_list_header").send(sender); + // Iterating over all equipment slots of this NPC and sending them to the sender. + npc.getData().getEquipment().forEach((slot, item) -> { + // Skipping null entries and Material.AIR, no need to display that. + if (item == null || item.getType() == Material.AIR) + return; + translator.translate("npc_equipment_list_entry") + .replace("slot", getTranslatedSlot(slot)) + .addTagResolver(Placeholder.component("item", item.displayName().hoverEvent(item.asHoverEvent()))) + .send(sender); + }); + translator.translate("npc_equipment_list_footer").send(sender); + } + + /* PARSER AND SUGGESTIONS */ + + // This parser does not specify a name, making it default parser for the returned type. + @Parser(name = "", suggestions = "EquipmentCMD/slot") + public NpcEquipmentSlot parseSlot(final CommandContext context, final CommandInput input) { + final String value = input.readString().toLowerCase(); + final @Nullable NpcEquipmentSlot slot = NpcEquipmentSlot.parse(value); + // Sending error message if input is not a valid NpcEquipmentSlot. + if (slot == null) + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_equipment_slot").replace("input", value).send(context.sender())); + return slot; + } + + @Parser(name = "EquipmentCMD/item", suggestions = "EquipmentCMD/item") + public ItemStack parseItem(final CommandContext context, final CommandInput input) { + final String value = input.readString().toLowerCase(); + // Handling '@none', which returns air (and effectively disables) + if (value.equals("@none")) + return new ItemStack(Material.AIR); + // Handling '@hand', which returns item player currently have in their hand. + else if (value.equals("@hand") && context.sender() instanceof Player player) + return player.getInventory().getItemInMainHand().clone(); + // Otherwise, trying to parse input as an material. + else { + // Converting input to NamespacedKey. Defaults to 'minecraft:' namespace if missing from input. + final @Nullable NamespacedKey key = NamespacedKey.fromString(value); + // Sending error message if input is not a valid NamespacedKey. + if (key == null) + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_material").replace("input", value).send(context.sender())); + // Getting material from the registry. + final @Nullable Material material = Registry.MATERIAL.get(key); + // Sending error message if no material was found. + if (material == null) + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_material").replace("input", value).send(context.sender())); + // Returning new ItemStack object from the specified Material. + return new ItemStack(material); + } + } + + @Suggestions("EquipmentCMD/item") + public List suggestItem(final CommandContext context, final CommandInput input) { + return new ArrayList<>(MATERIAL_SUGGESTIONS) {{ + // Adding '@none' placeholder which is replaced with 'minecraft:air'. + add("@none"); + // If applicable, adding '@hand' placeholder which is replaced with item player currently have in their hand. + if (context.sender() instanceof Player) + add("@hand"); + }}; + } + + @Suggestions("EquipmentCMD/slot") + public List suggestSlot(final CommandContext context, final CommandInput input) { + return SLOT_SUGGESTIONS; + } + + /* UTILITY METHODS */ + + // NOTE: Might need to be improved later down the line, should get work done for now. + private @NotNull String getTranslatedSlot(final @NotNull NpcEquipmentSlot slot) { + return ((SimpleMessage) translator.translate( + switch (slot) { + case MAINHAND -> "main_hand"; + case OFFHAND -> "off_hand"; + case HEAD -> "head"; + case CHEST -> "chest"; + case LEGS -> "legs"; + case FEET -> "feet"; + } + )).getMessage(); + } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 48fc1f66..49c696b7 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -43,6 +43,10 @@ messages: command_invalid_integer: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid integer." command_invalid_world: "› {errorColor}World named {warningColor}{input}{errorColor} does not exist." command_invalid_npc: "› {errorColor}NPC {warningColor}{input}{errorColor} does not exist." + command_invalid_material: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid material." + command_invalid_attribute: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid attribute." + command_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." + command_invalid_equipment_slot: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid slot." command_unsupported_npc_type: "› This NPC type does not support this feature." command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." @@ -78,11 +82,14 @@ messages: - "› {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state) - Changes turning state." - "› {primaryColor}/npc attribute {secondaryColor}(npc) (attr) (value) - Sets entity attribute." - "› {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." - npc_attribute_syntax: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) (attribute) (value)" + + npc_attribute_set_syntax: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}set {secondaryColor}(attribute) (value)" npc_attribute_set: "Attribute {warningColor}{attribute} has been set to {warningColor}{value}." - npc_attribute_invalid_attribute: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid attribute." - npc_attribute_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." - npc_attribute_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." + npc_attribute_set_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." + npc_attribute_list_header: "-------------------- Attributes --------------------" + npc_attribute_list_entry: " › <#848484>{attribute}: {warningColor}{value}" + npc_attribute_list_footer: "---------------------------------------------------" + npc_attribute_list_failure_empty: "› {errorColor}There is no attributes set. Use {warningColor}/npc attribute (npc) set (attribute) (value){errorColor} to set an attribute." npc_collidable_syntax: "Syntax: {primaryColor}/npc collidable {secondaryColor}(npc) (state)" npc_collidable_set_true: "NPC {warningColor}{npc} is now collidable." @@ -100,10 +107,15 @@ messages: npc_displayname_set_name: "NPC {warningColor}{npc} is now using {name} as their display name." npc_displayname_set_empty: "NPC {warningColor}{npc} is no longer showing display name." - npc_equipment_syntax: "Syntax: {primaryColor}/npc equipment {secondaryColor}(npc) (slot)" - npc_equipment_success: "NPC named {warningColor}{npc} has had their equipment updated." - npc_equipment_failure_invalid_slot: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid equipment slot." - + npc_equipment_set_syntax: "Syntax: {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}set {secondaryColor}(slot) (@hand | @none | item)" + npc_equipment_set_item: "Equipment slot {warningColor}{slot} has been set to ." + npc_equipment_set_empty: "Equipment slot {warningColor}{slot} has been removed." + npc_equipment_set_failure_invalid_slot: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid equipment slot." + npc_equipment_clear_success: "Equipment has been cleared." + npc_equipment_list_header: "-------------------- Equipment --------------------" + npc_equipment_list_entry: " <#848484>{slot}: " + npc_equipment_list_footer: "---------------------------------------------------" + npc_equipment_list_failure_empty: "› {errorColor}There is no equipment slots set. Use {warningColor}/npc equipment (npc) set (slot) (@hand | @none | material){errorColor} to set an equipment slot." npc_fix_success: "Attempted to fix NPC {warningColor}{npc}... Still having issues? Please let us know." @@ -139,18 +151,6 @@ messages: - "Open the chat window to see all information." - "" - npc_info_playerCommands_header: "Player Commands:" - npc_info_playerCommands_entry: "{command}" - npc_info_playerCommands_footer: " " - - npc_info_serverCommands_header: "Server Commands:" - npc_info_serverCommands_entry: "{command}" - npc_info_serverCommands_footer: " " - - npc_info_attributes_header: "Attributes:" - npc_info_attributes_entry: "› <#848484>{attribute}: {warningColor}{value}" - npc_info_attributes_footer: " " - npc_interaction_cooldown_syntax: "Syntax: {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (seconds)" npc_interaction_cooldown_success: "NPC {warningColor}{npc} has had their interaction cooldown updated." @@ -200,22 +200,17 @@ messages: npc_message_add_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) add (@none | message)" npc_message_add_success: "Message has been added. There is {warningColor}{total} messages in total." - npc_message_set_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) set (number) (@none | message)" npc_message_set_success: "Message {warningColor}{number} has been updated. There is {warningColor}{total} messages in total." npc_message_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_message_set_failure_list_is_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." - npc_message_remove_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) remove (number)" npc_message_remove_success: "Message {warningColor}{number} has been removed. There is {warningColor}{total} messages in total." npc_message_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_message_remove_failure_list_is_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." - npc_message_clear_success: "Messages have been cleared. There was {warningColor}{total} messages in total." - npc_message_send_randomly_set_true: "NPC {warningColor}{npc} is now sending messages randomly." npc_message_send_randomly_set_false: "NPC {warningColor}{npc} is no longer sending messages randomly." - npc_message_list_header: "-------------------- Messages --------------------" npc_message_list_entry: " <#848484>{number}. {message}" npc_message_list_footer: "---------------------------------------------------" @@ -223,19 +218,15 @@ messages: npc_player_command_add_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) add (command)" npc_player_command_add_success: "Command has been added. There is {warningColor}{total} commands in total." - npc_player_command_set_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) set (number) (command)" npc_player_command_set_success: "Command {warningColor}{number} has been updated. There is {warningColor}{total} commands in total." npc_player_command_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_player_command_set_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." - npc_player_command_remove_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) remove (number)" npc_player_command_remove_success: "Command {warningColor}{number} has been removed. There is {warningColor}{total} commands in total." npc_player_command_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_player_command_remove_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." - npc_player_command_clear_success: "Commands have been cleared. There was {warningColor}{total} commands in total." - npc_player_command_list_header: "----------------- Player Commands -----------------" npc_player_command_list_entry: " <#848484>{number}. {command}" npc_player_command_list_footer: "---------------------------------------------------" From fe08e4a9ac3bb004f77d5e2a6f32c6fb937948b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 14 May 2024 22:59:10 +0200 Subject: [PATCH 63/94] cloud 2.0.0-rc.1 This version of Cloud, most notably, fixes Location argument suggestions and adds (optional) integration with Paper's new Brigadier API which we cannot currently use because there is no (and likely won't be) a legacy fallback. --- build.gradle.kts | 8 ++++---- gradle.properties | 4 +++- .../oliver/fancynpcs/commands/CloudCommandManager.java | 10 +++++----- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8183139f..d2c507a5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,7 @@ allprojects { maven(url = "https://repo.papermc.io/repository/maven-public/") maven(url = "https://repo.fancyplugins.de/releases") maven(url = "https://repo.smrt-1.com/releases") - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") + maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") } } @@ -42,9 +42,9 @@ dependencies { implementation("de.oliver:FancyLib:${findProperty("fancyLibVersion")}") compileOnly("me.dave:ChatColorHandler:${findProperty("chatcolorhandlerVersion")}") - implementation("org.incendo:cloud-core:${findProperty("cloudVersion")}") - implementation("org.incendo:cloud-paper:${findProperty("cloudVersion")}") - implementation("org.incendo:cloud-annotations:${findProperty("cloudVersion")}") + implementation("org.incendo:cloud-core:${findProperty("cloudCoreVersion")}") + implementation("org.incendo:cloud-paper:${findProperty("cloudPaperVersion")}") + implementation("org.incendo:cloud-annotations:${findProperty("cloudAnnotationsVersion")}") compileOnly("com.intellectualsites.plotsquared:plotsquared-core:${findProperty("plotsquaredVersion")}") } diff --git a/gradle.properties b/gradle.properties index 2b0af1cd..4388e5c5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,6 @@ minecraftVersion=1.20.6 fancyLibVersion=1.0.21 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 -cloudVersion=2.0.0-SNAPSHOT \ No newline at end of file +cloudCoreVersion=2.0.0-rc.1 +cloudPaperVersion=2.0.0-SNAPSHOT +cloudAnnotationsVersion=2.0.0-SNAPSHOT \ No newline at end of file diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 68b9f7c3..e5715258 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -30,7 +30,7 @@ import org.incendo.cloud.bukkit.CloudBukkitCapabilities; import org.incendo.cloud.exception.ArgumentParseException; import org.incendo.cloud.execution.ExecutionCoordinator; -import org.incendo.cloud.paper.PaperCommandManager; +import org.incendo.cloud.paper.LegacyPaperCommandManager; import org.jetbrains.annotations.NotNull; @@ -47,13 +47,13 @@ public final class CloudCommandManager { private final @NotNull FancyNpcs plugin; - private final @NotNull PaperCommandManager commandManager; + private final @NotNull LegacyPaperCommandManager commandManager; private final @NotNull AnnotationParser annotationParser; public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrigadier) { this.plugin = plugin; - // Creating instance of Cloud's PaperCommandManager, which is used for anything command-related. - this.commandManager = PaperCommandManager.createNative(plugin, ExecutionCoordinator.simpleCoordinator()); + // Creating instance of Cloud's LegacyPaperCommandManager, which is used for anything command-related. + this.commandManager = LegacyPaperCommandManager.createNative(plugin, ExecutionCoordinator.simpleCoordinator()); // Registering Brigadier, if available. if (isBrigadier && commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { commandManager.registerBrigadier(); @@ -110,7 +110,7 @@ public void unregisterCommands() { /** * Returns the internal {@link PaperCommandManager} associated with this instance of {@link CloudCommandManager}. */ - public @NotNull PaperCommandManager getCommandManager() { + public @NotNull LegacyPaperCommandManager getCommandManager() { return commandManager; } From d1a5497a206867f963414d472ff5d22f5fc5baa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Tue, 14 May 2024 22:59:55 +0200 Subject: [PATCH 64/94] FancyLib 1.0.22 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4388e5c5..8c71dead 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ minecraftVersion=1.20.6 -fancyLibVersion=1.0.21 +fancyLibVersion=1.0.22 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 cloudCoreVersion=2.0.0-rc.1 From e7b6f2e51a6e01e87e005ee94560ef038a1e9724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 15:04:49 +0200 Subject: [PATCH 65/94] suggest relative coords and target location for `Location` argument --- .../commands/CloudCommandManager.java | 14 ++--- .../oliver/fancynpcs/commands/Subcommand.java | 17 ------ .../commands/arguments/LocationArgument.java | 37 ++++++++++++ .../fancynpcs/commands/npc/CreateCMD.java | 60 ++++++++++++------- .../fancynpcs/commands/npc/MoveToCMD.java | 16 ++++- src/main/resources/languages/en.yml | 2 + 6 files changed, 96 insertions(+), 50 deletions(-) delete mode 100644 src/main/java/de/oliver/fancynpcs/commands/Subcommand.java create mode 100644 src/main/java/de/oliver/fancynpcs/commands/arguments/LocationArgument.java diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index e5715258..34f4d65c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -1,6 +1,7 @@ package de.oliver.fancynpcs.commands; import de.oliver.fancynpcs.FancyNpcs; +import de.oliver.fancynpcs.commands.arguments.LocationArgument; import de.oliver.fancynpcs.commands.arguments.NpcArgument; import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; import de.oliver.fancynpcs.commands.npc.AttributeCMD; @@ -62,13 +63,14 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig this.annotationParser = new AnnotationParser<>(commandManager, CommandSender.class); // Registering parsers and suggestion providers. annotationParser.parse(NpcArgument.INSTANCE); + annotationParser.parse(LocationArgument.INSTANCE); // Registering exception handlers. commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(ReplyingParseException.class)); commandManager.exceptionController().registerHandler(ReplyingParseException.class, context -> context.exception().runnable().run()); } /** - * Registers plugin commands to the {@link PaperCommandManager}. + * Registers plugin commands to the {@link LegacyPaperCommandManager}. */ public @NotNull CloudCommandManager registerCommands() { annotationParser.parse(FancyNpcsCMD.INSTANCE); @@ -100,15 +102,7 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig } /** - * Unregisters plugin commands from the {@link PaperCommandManager}. - */ - public void unregisterCommands() { - commandManager.deleteRootCommand("fancynpcs"); - commandManager.deleteRootCommand("npc"); - } - - /** - * Returns the internal {@link PaperCommandManager} associated with this instance of {@link CloudCommandManager}. + * Returns the internal {@link LegacyPaperCommandManager} associated with this instance of {@link CloudCommandManager}. */ public @NotNull LegacyPaperCommandManager getCommandManager() { return commandManager; diff --git a/src/main/java/de/oliver/fancynpcs/commands/Subcommand.java b/src/main/java/de/oliver/fancynpcs/commands/Subcommand.java deleted file mode 100644 index f9764f71..00000000 --- a/src/main/java/de/oliver/fancynpcs/commands/Subcommand.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.oliver.fancynpcs.commands; - -import de.oliver.fancynpcs.api.Npc; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public interface Subcommand { - - List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args); - - boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args); - -} diff --git a/src/main/java/de/oliver/fancynpcs/commands/arguments/LocationArgument.java b/src/main/java/de/oliver/fancynpcs/commands/arguments/LocationArgument.java new file mode 100644 index 00000000..01dec3fd --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/commands/arguments/LocationArgument.java @@ -0,0 +1,37 @@ +package de.oliver.fancynpcs.commands.arguments; + +import org.bukkit.FluidCollisionMode; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.util.RayTraceResult; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; + +import java.text.DecimalFormat; +import java.util.Collections; +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +public enum LocationArgument { + INSTANCE; // SINGLETON + + private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); + + @Suggestions("relative_location") + public List suggestLocation(final CommandContext context, final CommandInput input) { + if (context.sender() instanceof Player player) { + final @Nullable RayTraceResult raytrace = player.rayTraceBlocks(32.0, FluidCollisionMode.ALWAYS); + if (raytrace != null) + return List.of( + COORDS_FORMAT.format(raytrace.getHitPosition().getX()) + " " + + COORDS_FORMAT.format(raytrace.getHitPosition().getY()) + " " + + COORDS_FORMAT.format(raytrace.getHitPosition().getZ()), + "~ ~ ~" + ); + return List.of("~ ~ ~"); + } + return Collections.emptyList(); + } +} diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index 5f093ee0..11e0a9aa 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -8,14 +8,15 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Flag; import org.incendo.cloud.annotations.Permission; -import org.incendo.cloud.annotations.Regex; import java.util.UUID; +import java.util.regex.Pattern; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,33 +26,50 @@ public enum CreateCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); + private static final Pattern NPC_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9/_-]*$"); + private static final UUID EMPTY_UUID = new UUID(0,0); + @Command("npc create ") @Permission("fancynpcs.command.npc.create") - public void onCreateCommand(final @NotNull CommandSender sender, - final @NotNull @Regex("^[A-Za-z0-9_-]*$") String name, - final @Nullable @Flag("type") EntityType type, - final @Nullable @Flag("position") Location position, - final @Nullable @Flag("world") World world + public void onCreate( + final @NotNull CommandSender sender, + final @NotNull String name, + final @Nullable @Flag("type") EntityType type, + final @Nullable @Flag(value = "location", suggestions = "relative_location") Location location, + final @Nullable @Flag("world") World world ) { - if (FancyNpcs.getInstance().getNpcManager().getNpc(name) != null) { + // Sending error message if name does not match configured pattern. + if (!NPC_NAME_PATTERN.matcher(name).find()) { + translator.translate("npc_create_failure_invalid_name").replaceStripped("name", name).send(sender); + return; + } + // Getting the NPC creator unique identifier. The UUID is always empty (all zeroes) for non-player senders. + final UUID creator = (sender instanceof Player player) ? player.getUniqueId() : EMPTY_UUID; + // Sending error message if NPC with such name already exist. + if ((FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && FancyNpcs.getInstance().getNpcManager().getNpc(name, creator) != null) || FancyNpcs.getInstance().getNpcManager().getNpc(name) != null) { translator.translate("npc_create_failure_already_exists").replace("npc", FancyNpcs.getInstance().getNpcManager().getNpc(name).getData().getName()).send(sender); return; } - final EntityType finalType = (type != null) ? type : EntityType.PLAYER; - // Getting the Location where NPC will be created at. - final Location location = (position == null && sender instanceof Player player) ? player.getLocation() : position; - // Setting the world of specified location. - if (location.getWorld() == null) { - if (world == null) { - translator.translate("npc_create_failure_must_specify_world").send(sender); - return; - } - location.setWorld(world); + // Sending error message if sender is console and location has not been specified. + if (sender instanceof ConsoleCommandSender && location == null) { + translator.translate("npc_create_failure_must_specify_location").send(sender); + return; + } + // Sending error message if sender is console and world has not been specified. + if (sender instanceof ConsoleCommandSender && world == null) { + translator.translate("npc_create_failure_must_specify_world").send(sender); + return; } - final Npc npc = FancyNpcs.getInstance().getNpcAdapter().apply(new NpcData(name, (sender instanceof Player player) ? player.getUniqueId() : UUID.nameUUIDFromBytes(new byte[0]), location)); - // Setting the type of NPC. Default type is EntityType.PLAYER. - npc.getData().setType(finalType); - // Calling event and creating NPC if not cancelled, sending error message otherwise. + // Finalizing Location argument. This argument is optional and defaults to player's current location. + final Location finalLocation = (location == null && sender instanceof Player player) ? player.getLocation() : location; + // Updating World of the Location argument if '--world' flag has been specified. + if (world != null) + finalLocation.setWorld(world); + // Creating new NPC + final Npc npc = FancyNpcs.getInstance().getNpcAdapter().apply(new NpcData(name, creator, finalLocation)); + // Setting the type of NPC. Flag '--type' is optional and defaults to EntityType.PLAYER. + npc.getData().setType(type != null ? type : EntityType.PLAYER); + // Calling the event and creating NPC if not cancelled. if (new NpcCreateEvent(npc, sender).callEvent()) { npc.create(); FancyNpcs.getInstance().getNpcManagerImpl().registerNpc(npc); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java index cc1b9212..dbb5475e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java @@ -7,6 +7,8 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; @@ -32,9 +34,19 @@ public void onDefault(final CommandSender sender) { public void onCommand( final CommandSender sender, final Npc npc, - final Location location, + final @Argument(suggestions = "relative_location") Location location, final @Nullable World world ) { + // Finalizing World argument. Player-like senders don't have to specify the 'world' argument which then defaults to the World sender is currently in. + final World finalWorld = (world == null && sender instanceof Player player) ? player.getWorld() : world; + // Sending error message if finalized World argument ended up being null. This can happen when command is executed by console and 'world' argument was not specified. + if (finalWorld == null) { + translator.translate("npc_move_to_failure_must_specify_world").send(sender); + return; + } + // Updating World of the finalized Location. This should never pass a null value. + location.setWorld(finalWorld); + // Calling the event and re-locating NPC if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender).callEvent()) { npc.getData().setLocation(location); npc.updateForAll(); @@ -43,7 +55,7 @@ public void onCommand( .replace("x", COORDS_FORMAT.format(location.x())) .replace("y", COORDS_FORMAT.format(location.y())) .replace("z", COORDS_FORMAT.format(location.z())) - .replace("world", world.getName()) + .replace("world", finalWorld.getName()) .send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 49c696b7..19659345 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -100,6 +100,7 @@ messages: npc_create_syntax: "Syntax: {primaryColor}/npc create {secondaryColor}(npc)" npc_create_success: "NPC {warningColor}{npc} has been created." + npc_create_failure_invalid_name: "› {errorColor}Name contains illegal characters. Only [{warningColor}A-Z{errorColor}, {warningColor}a-z{errorColor}, {warningColor}0-9{errorColor}, {warningColor}_{errorColor}, {warningColor}-{errorColor}, {warningColor}/{errorColor}] characters are allowed." npc_create_failure_already_exists: "› {errorColor}NPC {warningColor}{npc}{errorColor} already exists." npc_create_failure_must_specify_world: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." @@ -184,6 +185,7 @@ messages: npc_move_to_syntax: "Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" npc_move_to_success: "NPC {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." + npc_move_to_failure_must_specify_world: "› {errorColor}You must specify world when running this command from the console." npc_teleport_syntax: "Syntax: {primaryColor}/npc teleport {secondaryColor}(npc)" npc_teleport_success: "You have been teleported to NPC {warningColor}{npc}." From 6f87ca212a59d16aff16e60b86c497cd71a5705a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 15:05:31 +0200 Subject: [PATCH 66/94] add `cloud-annotations` annotation processor --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index d2c507a5..1fe7eec0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -45,6 +45,7 @@ dependencies { implementation("org.incendo:cloud-core:${findProperty("cloudCoreVersion")}") implementation("org.incendo:cloud-paper:${findProperty("cloudPaperVersion")}") implementation("org.incendo:cloud-annotations:${findProperty("cloudAnnotationsVersion")}") + annotationProcessor("org.incendo:cloud-annotations:${findProperty("cloudAnnotationsVersion")}") compileOnly("com.intellectualsites.plotsquared:plotsquared-core:${findProperty("plotsquaredVersion")}") } From f7efd5ab70c7f3449106700523c4d259ccd8d339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 15:06:37 +0200 Subject: [PATCH 67/94] small clean-up for `/npc collidable` and `/npc glowing` --- .../de/oliver/fancynpcs/commands/npc/CollidableCMD.java | 4 +--- .../java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java index 817bcf74..b5e23690 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java @@ -24,14 +24,12 @@ public void onDefault(final CommandSender sender) { @Command("npc collidable [state]") @Permission("fancynpcs.command.npc.collidable") public void onCommand(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + // Finalizing the state. If no state has been specified, the current one is inverted. final boolean finalState = (state == null) ? !npc.getData().isCollidable() : state; // Calling the event and updating the state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.COLLIDABLE, finalState, sender).callEvent()) { - // Updating the state. npc.getData().setCollidable(finalState); - // Sending message to the sender. translator.translate(finalState ? "npc_collidable_set_true" : "npc_collidable_set_false").replace("npc", npc.getData().getName()).send(sender); - // Returning from the command block. return; } // Otherwise, sending error message to the sender. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java index 73e993a9..e7bc6a93 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java @@ -26,9 +26,9 @@ public void onDefault(final CommandSender sender) { @Command("npc glowing [color]") @Permission("fancynpcs.command.npc.glowing") public void onCommand(final CommandSender sender, final Npc npc, final @Nullable GlowingColor color) { - // Handling 'toggle' state. + // Handling 'toggle' state, which means inverting the current state. if (color == null) { - // Inverting the current glowing state, so it works like a toggle. + // Inverting the current glowing state, so the command works like a toggle. final boolean isGlowingToggled = !npc.getData().isGlowing(); // Calling the event and updating the state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, isGlowingToggled, sender).callEvent()) { @@ -39,7 +39,7 @@ public void onCommand(final CommandSender sender, final Npc npc, final @Nullable translator.translate("command_npc_modification_cancelled").send(sender); } } - // Handling 'disabled' state. + // Handling 'disabled' state, which means disabling glowing state. else if (color == GlowingColor.DISABLED) { // Calling the event and updating the state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, false, sender).callEvent()) { From e361224c198f48d4129e501f311f4f008ab1fc2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 16:47:29 +0200 Subject: [PATCH 68/94] clean-up all commands (once more) and add context-aware syntax exception handler --- .../commands/CloudCommandManager.java | 51 ++++++--- .../fancynpcs/commands/npc/AttributeCMD.java | 19 ++-- .../fancynpcs/commands/npc/CollidableCMD.java | 13 +-- .../fancynpcs/commands/npc/CopyCMD.java | 22 ++-- .../commands/npc/DisplayNameCMD.java | 51 +++++++-- .../fancynpcs/commands/npc/EquipmentCMD.java | 30 +++-- .../oliver/fancynpcs/commands/npc/FixCMD.java | 13 +-- .../fancynpcs/commands/npc/GlowingCMD.java | 13 +-- .../fancynpcs/commands/npc/InfoCMD.java | 51 +-------- .../commands/npc/InteractionCooldownCMD.java | 14 +-- .../fancynpcs/commands/npc/ListCMD.java | 3 +- .../fancynpcs/commands/npc/MessageCMD.java | 69 ++++++------ .../fancynpcs/commands/npc/MoveHereCMD.java | 14 +-- .../fancynpcs/commands/npc/MoveToCMD.java | 13 +-- .../fancynpcs/commands/npc/NearbyCMD.java | 3 +- .../npc/{NpcCMD.java => NpcHelpCMD.java} | 42 ++++--- .../commands/npc/PlayerCommandCMD.java | 57 ++++------ .../fancynpcs/commands/npc/RemoveCMD.java | 15 +-- .../commands/npc/ServerCommandCMD.java | 74 ------------ .../fancynpcs/commands/npc/ShowInTabCMD.java | 13 +-- .../fancynpcs/commands/npc/SkinCMD.java | 30 +++-- .../fancynpcs/commands/npc/TeleportCMD.java | 13 +-- .../commands/npc/TurnToPlayerCMD.java | 17 +-- .../fancynpcs/commands/npc/TypeCMD.java | 32 +++--- src/main/resources/languages/en.yml | 106 +++++++++++------- 25 files changed, 359 insertions(+), 419 deletions(-) rename src/main/java/de/oliver/fancynpcs/commands/npc/{NpcCMD.java => NpcHelpCMD.java} (87%) delete mode 100644 src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 34f4d65c..12345a4c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -1,11 +1,13 @@ package de.oliver.fancynpcs.commands; +import de.oliver.fancylib.translations.message.Message; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.commands.arguments.LocationArgument; import de.oliver.fancynpcs.commands.arguments.NpcArgument; import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; import de.oliver.fancynpcs.commands.npc.AttributeCMD; import de.oliver.fancynpcs.commands.npc.CollidableCMD; +import de.oliver.fancynpcs.commands.npc.CopyCMD; import de.oliver.fancynpcs.commands.npc.CreateCMD; import de.oliver.fancynpcs.commands.npc.DisplayNameCMD; import de.oliver.fancynpcs.commands.npc.EquipmentCMD; @@ -18,7 +20,7 @@ import de.oliver.fancynpcs.commands.npc.MoveHereCMD; import de.oliver.fancynpcs.commands.npc.MoveToCMD; import de.oliver.fancynpcs.commands.npc.NearbyCMD; -import de.oliver.fancynpcs.commands.npc.NpcCMD; +import de.oliver.fancynpcs.commands.npc.NpcHelpCMD; import de.oliver.fancynpcs.commands.npc.PlayerCommandCMD; import de.oliver.fancynpcs.commands.npc.RemoveCMD; import de.oliver.fancynpcs.commands.npc.ShowInTabCMD; @@ -29,21 +31,21 @@ import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.AnnotationParser; import org.incendo.cloud.bukkit.CloudBukkitCapabilities; +import org.incendo.cloud.component.CommandComponent; import org.incendo.cloud.exception.ArgumentParseException; +import org.incendo.cloud.exception.InvalidSyntaxException; import org.incendo.cloud.execution.ExecutionCoordinator; import org.incendo.cloud.paper.LegacyPaperCommandManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import static org.incendo.cloud.exception.handling.ExceptionHandler.unwrappingHandler; // DEV NOTES: -// - Location suggestions might behave a bit weird, writing custom provider doesn't work either. -// I'm fairly sure Cloud developers are aware of that issue and they'll fix it soon. // - For the time being, due to the reasons below, Brigadier integration should be OFF by default: // a) Argument pop-ups don't work properly, they don't appear most of the time. // b) Suggestions are supplied per-whitespace, and not per-argument. -// c) Location suggestions might also behave a bit weird, similarly as with Brigadier disabled. public final class CloudCommandManager { private final @NotNull FancyNpcs plugin; @@ -56,9 +58,8 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig // Creating instance of Cloud's LegacyPaperCommandManager, which is used for anything command-related. this.commandManager = LegacyPaperCommandManager.createNative(plugin, ExecutionCoordinator.simpleCoordinator()); // Registering Brigadier, if available. - if (isBrigadier && commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { + if (isBrigadier && commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) commandManager.registerBrigadier(); - } // Creating instance of AnnotationParser, which is used for parsing and registering commands. this.annotationParser = new AnnotationParser<>(commandManager, CommandSender.class); // Registering parsers and suggestion providers. @@ -67,36 +68,58 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig // Registering exception handlers. commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(ReplyingParseException.class)); commandManager.exceptionController().registerHandler(ReplyingParseException.class, context -> context.exception().runnable().run()); + commandManager.exceptionController().registerHandler(InvalidSyntaxException.class, (exceptionContext) -> { + // Creating a StringBuilder which is then appended with (known/existing) command literals. + final StringBuilder translationKeyBuilder = new StringBuilder("command_syntax."); + // Iterating over current command chain and appending literals, as described above. + exceptionContext.exception().currentChain().stream() + .filter(c -> c.type() == CommandComponent.ComponentType.LITERAL) + .forEach(literal -> translationKeyBuilder.append(literal.name()).append(' ')); + // Trimming input (last character ends up being blank) and replacing whitespaces with underscores, as that's how translations are defined inside the language file. + final String translationKey = translationKeyBuilder.toString().trim().replace(' ', '_'); + // Getting the message, it's not finished as there we need to handle fallback language etc. + // Currently, Translator#translate(String) throws NPE on invalid message and that's why we're not using it here. + final @Nullable Message message = plugin.getTranslator().getSelectedLanguage().getMessage(translationKey); + // "Fall-backing" to generic syntax error, if no specialized syntax message has been defined in the language file. + if (message == null) { + plugin.getTranslator().translate("command_invalid_syntax_generic") + .replace("syntax", exceptionContext.exception().correctSyntax()) + .send(exceptionContext.context().sender()); + return; + } + message.send(exceptionContext.context().sender()); + }); } /** * Registers plugin commands to the {@link LegacyPaperCommandManager}. */ public @NotNull CloudCommandManager registerCommands() { - annotationParser.parse(FancyNpcsCMD.INSTANCE); annotationParser.parse(AttributeCMD.INSTANCE); annotationParser.parse(CollidableCMD.INSTANCE); + annotationParser.parse(CopyCMD.INSTANCE); annotationParser.parse(CreateCMD.INSTANCE); annotationParser.parse(DisplayNameCMD.INSTANCE); annotationParser.parse(EquipmentCMD.INSTANCE); + annotationParser.parse(FancyNpcsCMD.INSTANCE); annotationParser.parse(FixCMD.INSTANCE); annotationParser.parse(GlowingCMD.INSTANCE); annotationParser.parse(InfoCMD.INSTANCE); annotationParser.parse(InteractionCooldownCMD.INSTANCE); annotationParser.parse(ListCMD.INSTANCE); annotationParser.parse(MessageCMD.INSTANCE); - // annotationParser.parse(ServerCommandCMD.INSTANCE); - annotationParser.parse(PlayerCommandCMD.INSTANCE); annotationParser.parse(MoveHereCMD.INSTANCE); + annotationParser.parse(MoveToCMD.INSTANCE); annotationParser.parse(NearbyCMD.INSTANCE); - annotationParser.parse(NpcCMD.INSTANCE); - annotationParser.parse(TurnToPlayerCMD.INSTANCE); + annotationParser.parse(NpcHelpCMD.INSTANCE); + annotationParser.parse(PlayerCommandCMD.INSTANCE); + annotationParser.parse(RemoveCMD.INSTANCE); + // annotationParser.parse(ServerCommandCMD.INSTANCE); annotationParser.parse(ShowInTabCMD.INSTANCE); + annotationParser.parse(SkinCMD.INSTANCE); annotationParser.parse(TeleportCMD.INSTANCE); + annotationParser.parse(TurnToPlayerCMD.INSTANCE); annotationParser.parse(TypeCMD.INSTANCE); - annotationParser.parse(RemoveCMD.INSTANCE); - annotationParser.parse(SkinCMD.INSTANCE); - annotationParser.parse(MoveToCMD.INSTANCE); // Returning this instance of CloudCommandManager to keep "builder-like" flow. return this; } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java index b453cba2..d5e12912 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java @@ -18,6 +18,8 @@ import java.util.List; +import org.jetbrains.annotations.NotNull; + public enum AttributeCMD { INSTANCE; // SINGLETON @@ -27,15 +29,15 @@ public enum AttributeCMD { @Command("npc attribute set ") @Permission("fancynpcs.command.npc.attribute.set") public void onAttributeSet( - final CommandSender sender, - final Npc npc, - final NpcAttribute attribute, - final @Argument(parserName = "AttributeCMD/attribute_value") String attributeValue + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull NpcAttribute attribute, + final @NotNull @Argument(parserName = "AttributeCMD/attribute_value") String attributeValue ) { if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.ATTRIBUTE, new Object[]{attribute, attributeValue}, sender).callEvent()) { npc.getData().addAttribute(attribute, attributeValue); npc.updateForAll(); - translator.translate("npc_attribute_set").replace("attribute", attribute.getName()).replace("value", attributeValue.toLowerCase()).send(sender); + translator.translate("npc_attribute_set").replace("attribute", attribute.getName()).replaceStripped("value", attributeValue.toLowerCase()).send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } @@ -43,7 +45,10 @@ public void onAttributeSet( @Command("npc attribute list") @Permission("fancynpcs.command.npc.attribute.list") - public void onAttributeList(final CommandSender sender, final Npc npc) { + public void onAttributeList( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { // Sending error message if the list is empty. if (npc.getData().getAttributes().isEmpty()) { translator.translate("npc_attribute_list_failure_empty").send(sender); @@ -101,7 +106,7 @@ public List suggestAttribute(final CommandContext context public List suggestAttributeValue(final CommandContext context, final CommandInput input) { final Npc npc = context.get("npc"); final NpcAttribute attribute = context.get("attribute"); - return FancyNpcs.getInstance().getAttributeManager().getAttributeByName(npc.getData().getType(), attribute.getName()).getPossibleValues(); + return attributeManager.getAttributeByName(npc.getData().getType(), attribute.getName()).getPossibleValues(); } } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java index b5e23690..4dffd8e8 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CollidableCMD.java @@ -8,6 +8,7 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum CollidableCMD { @@ -15,15 +16,13 @@ public enum CollidableCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("npc collidable") - @Permission("fancynpcs.command.npc.collidable") - public void onDefault(final CommandSender sender) { - translator.translate("npc_collidable_syntax").send(sender); - } - @Command("npc collidable [state]") @Permission("fancynpcs.command.npc.collidable") - public void onCommand(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + public void onCollidable( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Nullable Boolean state + ) { // Finalizing the state. If no state has been specified, the current one is inverted. final boolean finalState = (state == null) ? !npc.getData().isCollidable() : state; // Calling the event and updating the state if not cancelled. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java index cf45c8cf..39c9b37e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java @@ -8,9 +8,11 @@ import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; -import org.incendo.cloud.annotations.Regex; import java.util.UUID; +import java.util.regex.Pattern; + +import org.jetbrains.annotations.NotNull; // TO-DO: Console support with --position and --world parameter flags. public enum CopyCMD { @@ -18,15 +20,21 @@ public enum CopyCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command(value = "npc copy", requiredSender = Player.class) - @Permission("fancynpcs.command.npc.copy") - public void onDefault(final Player sender) { - translator.translate("npc_copy_syntax").send(sender); - } + private static final Pattern NPC_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9/_-]*$"); + @Command(value = "npc copy ", requiredSender = Player.class) @Permission("fancynpcs.command.npc.copy") - public void onCommand(final Player sender, final Npc npc, final @Regex("^[A-Za-z0-9_-]*$") String name) { + public void onCopy( + final @NotNull Player sender, + final @NotNull Npc npc, + final @NotNull String name + ) { + // Sending error message if name does not match configured pattern. + if (!NPC_NAME_PATTERN.matcher(name).find()) { + translator.translate("npc_create_failure_invalid_name").replaceStripped("name", name).send(sender); + return; + } // Creating a copy of an NPC and all it's data. The only different thing is it's UUID. final Npc copied = FancyNpcs.getInstance().getNpcAdapter().apply( new NpcData( diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java index 96268d6d..f13d1169 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java @@ -4,6 +4,10 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; +import me.dave.chatcolorhandler.ModernChatColorHandler; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentIteratorType; +import net.kyori.adventure.text.event.ClickEvent; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotation.specifier.Greedy; import org.incendo.cloud.annotations.Argument; @@ -14,6 +18,9 @@ import org.incendo.cloud.context.CommandInput; import java.util.List; +import java.util.stream.StreamSupport; + +import org.jetbrains.annotations.NotNull; public enum DisplayNameCMD { INSTANCE; // SINGLETON @@ -23,17 +30,20 @@ public enum DisplayNameCMD { // Storing in a static variable to avoid re-creating the array each time suggestion is requested. private static final List NONE_SUGGESTIONS = List.of("@none"); - @Command("npc displayname") - @Permission("fancynpcs.command.npc.displayname") - public void onDefault(final CommandSender sender) { - translator.translate("npc_displayname_syntax").send(sender); - } - @Command("npc displayname ") @Permission("fancynpcs.command.npc.displayname") - public void onCommand(final CommandSender sender, final Npc npc, final @Argument(suggestions = "DisplayNameCMD/none") @Greedy String name) { + public void onDisplayName( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull @Argument(suggestions = "DisplayNameCMD/none") @Greedy String name + ) { // Finalizing the name. In case input is '@none', it gets replaced with '' for backwards compatibility. final String finalName = name.equalsIgnoreCase("@none") ? "" : name; + // Sending error message in case banned command has been found in the input. + if (hasBlockedCommands(finalName)) { + translator.translate("command_input_contains_blocked_command").send(sender); + return; + } // Calling the event and updating the state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.DISPLAY_NAME, finalName, sender).callEvent()) { npc.getData().setDisplayName(finalName); @@ -48,8 +58,33 @@ public void onCommand(final CommandSender sender, final Npc npc, final @Argument } @Suggestions("DisplayNameCMD/none") - public List suggestions(final CommandContext sender, CommandInput input) { + public List suggestNone(final CommandContext sender, CommandInput input) { return NONE_SUGGESTIONS; } + /** Returns {@code true} if specified component contains blocked command, {@code false} otherwise. */ + private boolean hasBlockedCommands(final @NotNull String message) { + // Converting message to a Component. + final Component component = ModernChatColorHandler.translate(message); + // Getting the list of all blocked commands. + final List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); + // Iterating over all children of the component... + return StreamSupport.stream(component.iterable(ComponentIteratorType.DEPTH_FIRST).spliterator(), false).anyMatch(it -> { + final ClickEvent event = it.clickEvent(); + // We only care about click events with run_command as an action. Continuing if not found. + if (event == null || event.action() != ClickEvent.Action.RUN_COMMAND) + return false; + // Iterating over list of blocked commands... + for (final String blockedCommand : blockedCommands) { + // Transforming the command to a base command with trailed whitespaces and slashes. This also removes namespaced part from the beginning of the command. + final String transformedBaseCommand = blockedCommand.replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", ""); + // Comparing click event value with the transformed base command. Returning the result. + if (event.value().replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", "").equalsIgnoreCase(transformedBaseCommand)) + return true; + } + // Returning false as no blocked commands has been found. + return false; + }); + } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java index 2cd7a4e6..9cdc5c20 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java @@ -39,30 +39,22 @@ public enum EquipmentCMD { private static final List SLOT_SUGGESTIONS = Arrays.stream(NpcEquipmentSlot.values()).map(slot -> slot.name().toLowerCase()).toList(); private static final List MATERIAL_SUGGESTIONS = Registry.MATERIAL.stream().map(material -> material.key().asString()).toList(); - @Command("npc equipment set") - @Permission("fancynpcs.command.npc.equipment.set") - public void onEquipmentSet(final CommandSender sender, final Npc npc) { - translator.translate("npc_equipment_set_syntax").send(sender); - } - @Command("npc equipment set ") @Permission("fancynpcs.command.npc.equipment.set") public void onEquipmentSet( - final CommandSender sender, - final Npc npc, - final NpcEquipmentSlot slot, - final @Argument(parserName = "EquipmentCMD/item") ItemStack item + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull NpcEquipmentSlot slot, + final @NotNull @Argument(parserName = "EquipmentCMD/item") ItemStack item ) { - if (!(sender instanceof Player) && item == null) - translator.translate("command_player_only").send(sender); // Calling the event and updating equipment if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.EQUIPMENT, new Object[]{slot, item}, sender).callEvent()) { npc.getData().addEquipment(slot, item); npc.updateForAll(); - translator.translate(item != null && item.getType() != Material.AIR ? "npc_equipment_set_item" : "npc_equipment_set_empty") + translator.translate(item.getType() != Material.AIR ? "npc_equipment_set_item" : "npc_equipment_set_empty") .replace("npc", npc.getData().getName()) .replace("slot", getTranslatedSlot(slot)) - .addTagResolver(Placeholder.component("item", (item != null && item.getType() != Material.AIR) ? item.displayName().hoverEvent(item.asHoverEvent()) : Component.empty())) + .addTagResolver(Placeholder.component("item", (item.getType() != Material.AIR) ? item.displayName().hoverEvent(item.asHoverEvent()) : Component.empty())) .send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); @@ -71,7 +63,10 @@ public void onEquipmentSet( @Command("npc equipment clear") @Permission("fancynpcs.command.npc.equipment.clear") - public void onEquipmentClear(final CommandSender sender, final Npc npc) { + public void onEquipmentClear( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { // Calling the event and clearing equipment if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.EQUIPMENT, null, sender).callEvent()) { // Entries must be set to null manually because clearing the map would prevent equipment from being updated. (Npc#update checks if map is empty) @@ -86,7 +81,10 @@ public void onEquipmentClear(final CommandSender sender, final Npc npc) { @Command("npc equipment list") @Permission("fancynpcs.command.npc.equipment.list") - public void onEquipmentList(final CommandSender sender, final Npc npc) { + public void onEquipmentList( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { // Sending error message if the list is empty or all items are Material.AIR. if (npc.getData().getEquipment().isEmpty() || npc.getData().getEquipment().values().stream().allMatch(item -> item == null || item.getType() == Material.AIR)) { translator.translate("npc_equipment_list_failure_empty").send(sender); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java index 42387a7a..940b98f5 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/FixCMD.java @@ -8,20 +8,19 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; + public enum FixCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("npc fix") - @Permission("fancynpcs.command.npc.fix") - public void onDefault(final CommandSender sender) { - translator.translate("npc_fix_syntax").send(sender); - } - @Command("npc fix ") @Permission("fancynpcs.command.npc.fix") - public void onCommand(final CommandSender sender, final Npc npc) { + public void onFix( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { npc.removeForAll(); npc.create(); Bukkit.getOnlinePlayers().forEach(npc::checkAndUpdateVisibility); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java index e7bc6a93..c4eeff47 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java @@ -10,6 +10,7 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum GlowingCMD { @@ -17,15 +18,13 @@ public enum GlowingCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("npc glowing") - @Permission("fancynpcs.command.npc.glowing") - public void onDefault(final CommandSender sender) { - translator.translate("npc_glowing_syntax").send(sender); - } - @Command("npc glowing [color]") @Permission("fancynpcs.command.npc.glowing") - public void onCommand(final CommandSender sender, final Npc npc, final @Nullable GlowingColor color) { + public void onGlowing( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Nullable GlowingColor color + ) { // Handling 'toggle' state, which means inverting the current state. if (color == null) { // Inverting the current glowing state, so the command works like a toggle. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index 733f7659..860badf7 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -6,9 +6,7 @@ import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; import de.oliver.fancynpcs.util.GlowingColor; -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; @@ -25,21 +23,17 @@ public enum InfoCMD { private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); private static final DecimalFormat SECONDS_FORMAT = new DecimalFormat("#,###.#"); - @Command("npc info") - @Permission("fancynpcs.command.npc.info") - public void onDefault(final CommandSender sender) { - translator.translate("npc_info_syntax").send(sender); - } - @Command("npc info ") @Permission("fancynpcs.command.npc.info") - public void onCommand(final CommandSender sender, final Npc npc) { + public void onInfo( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { final Location loc = npc.getData().getLocation(); // Getting the translated glowing state. This should never throw because all supported NamedTextColor objects has their mapping in GlowingColor enum. final String glowingStateTranslated = (!npc.getData().isGlowing() || npc.getData().getGlowingColor() != null) ? ((SimpleMessage) translator.translate(GlowingColor.fromAdventure(npc.getData().getGlowingColor()).getTranslationKey())).getMessage() : ((SimpleMessage) translator.translate("disabled")).getMessage(); - // Sending general info to the sender. translator.translate("npc_info_general") .replace("name", npc.getData().getName()) .replace("id", npc.getData().getId()) @@ -60,43 +54,8 @@ public void onCommand(final CommandSender sender, final Npc npc) { .replace("interaction_cooldown", SECONDS_FORMAT.format(npc.getData().getInteractionCooldown()) + "s") .replace("messages_total", String.valueOf(npc.getData().getMessages().size())) .replace("player_commands_total", String.valueOf(npc.getData().getPlayerCommands().size())) - .replace("server_commands_total", String.valueOf(0)) // TODO + .replace("server_commands_total", String.valueOf(npc.getData().getServerCommand() == null ? 0 : 1)) // NOTE: PLACEHOLDER; MULTI COMMAND SUPPORT NOT IMPLEMENTED YET .send(sender); - - if (npc.getData().getServerCommand() != null) { - translator.translate("npc_info_serverCommands_header").send(sender); - translator.translate("npc_info_serverCommands_entry").replace("command", npc.getData().getServerCommand()).send(sender); - translator.translate("npc_info_serverCommands_footer").send(sender); - } - - if (!npc.getData().getPlayerCommands().isEmpty()) { - translator.translate("npc_info_playerCommands_header").send(sender); - npc.getData().getPlayerCommands().forEach(command -> { - translator.translate("npc_info_playerCommands_entry").replace("command", command).send(sender); - }); - translator.translate("npc_info_playerCommands_footer").send(sender); - } - - if (!npc.getData().getEquipment().isEmpty()) { - translator.translate("npc_info_equipment_header").send(sender); - npc.getData().getEquipment().forEach((slot, item) -> { - if (item.getType() == Material.AIR) - return; - translator.translate("npc_info_equipment_entry") - .replace("slot", getTranslatedSlot(slot)) - .addTagResolver(Placeholder.component("item", item.displayName().hoverEvent(item.asHoverEvent()))) - .send(sender); - }); - translator.translate("npc_info_equipment_footer").send(sender); - } - - if (!npc.getData().getAttributes().isEmpty()) { - translator.translate("npc_info_attributes_header").send(sender); - npc.getData().getAttributes().forEach((attribute, value) -> - translator.translate("npc_info_attributes_entry").replace("attribute", attribute.getName()).replace("value", value).send(sender) - ); - translator.translate("npc_info_attributes_footer").send(sender); - } } // NOTE: Might need to be improved later down the line, should get work done for now. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java index b0a8cf82..f9851894 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java @@ -8,20 +8,20 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; + public enum InteractionCooldownCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("npc interaction_cooldown") - @Permission("fancynpcs.command.npc.interaction_cooldown") - public void onDefault(final CommandSender sender) { - translator.translate("npc_interaction_cooldown_syntax").send(sender); - } - @Command("npc interaction_cooldown ") @Permission("fancynpcs.command.npc.interaction_cooldown") - public void onCommand(final CommandSender sender, final Npc npc, final float cooldown) { + public void onInteractionCooldown( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final float cooldown + ) { // Calling the event and updating the cooldown if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.INTERACTION_COOLDOWN, cooldown, sender).callEvent()) { npc.getData().setInteractionCooldown(cooldown); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java index 92d5b453..d1e7b0ca 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ListCMD.java @@ -15,6 +15,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum ListCMD { @@ -31,7 +32,7 @@ public enum ListCMD { @Command("npc list") @Permission("fancynpcs.command.npc.list") public void onCommand( - final CommandSender sender, + final @NotNull CommandSender sender, final @Nullable @Flag("type") EntityType type, final @Nullable @Flag("sort") SortType sort ) { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index 8ba90199..b00533ae 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -34,17 +34,13 @@ public enum MessageCMD { // Storing in a static variable to avoid re-creating the array each time suggestion is requested. private static final List NONE_SUGGESTIONS = List.of("@none"); - /* MESSAGE ADD */ - - @Command("npc message add") - @Permission("fancynpcs.command.npc.message.add") - public void onMessageAdd(final CommandSender sender, final Npc npc) { - translator.translate("npc_message_add_syntax").send(sender); - } - @Command("npc message add ") @Permission("fancynpcs.command.npc.message.add") - public void onMessageAdd(final CommandSender sender, final Npc npc, final @Argument(suggestions = "MessageCMD/none") @Greedy String message) { + public void onMessageAdd( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull @Argument(suggestions = "MessageCMD/none") @Greedy String message + ) { // Handling '@none' as an empty message. final String finalMessage = message.equalsIgnoreCase("@none") ? "" : message; // Sending error message in case banned command has been found in the input. @@ -61,17 +57,14 @@ public void onMessageAdd(final CommandSender sender, final Npc npc, final @Argum } } - /* MESSAGE SET */ - - @Command("npc message set") + @Command("npc message set [number] [message]") @Permission("fancynpcs.command.npc.message.set") - public void onMessageSet(final CommandSender sender, final Npc npc) { - translator.translate("npc_message_set_syntax").send(sender); - } - - @Command("npc message set ") - @Permission("fancynpcs.command.npc.message.set") - public void onMessageSet(final CommandSender sender, final Npc npc, final @Argument(suggestions = "MessageCMD/number_range") int number, final @Argument(suggestions = "MessageCMD/none") @Greedy String message) { + public void onMessageSet( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull @Argument(suggestions = "MessageCMD/number_range") Integer number, + final @NotNull @Argument(suggestions = "MessageCMD/none") @Greedy String message + ) { // Handling '@none' as an empty message. final String finalMessage = message.equalsIgnoreCase("@none") ? "" : message; // Sending error message in case banned command has been found in the input. @@ -105,17 +98,13 @@ public void onMessageSet(final CommandSender sender, final Npc npc, final @Argum } } - /* MESSAGE REMOVE */ - - @Command("npc message remove") - @Permission("fancynpcs.command.npc.message.remove") - public void onMessageRemove(final CommandSender sender, final Npc npc) { - translator.translate("npc_message_remove_syntax").send(sender); - } - @Command("npc message remove ") @Permission("fancynpcs.command.npc.message.remove") - public void onMessageRemove(final CommandSender sender, final Npc npc, final @Argument(suggestions = "MessageCMD/number_range") int number) { + public void onMessageRemove( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Argument(suggestions = "MessageCMD/number_range") int number + ) { // Getting the total count of messages that are currently in the list. final int totalCount = npc.getData().getMessages().size(); // Sending error message if the list is empty. @@ -144,11 +133,12 @@ public void onMessageRemove(final CommandSender sender, final Npc npc, final @Ar } } - /* MESSAGE CLEAR */ - @Command("npc message clear") @Permission("fancynpcs.command.npc.message.clear") - public void onMessageClear(final CommandSender sender, final Npc npc) { + public void onMessageClear( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { final int total = npc.getData().getMessages().size(); // Calling the event and clearing messages if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_CLEAR, null, sender).callEvent()) { @@ -159,11 +149,12 @@ public void onMessageClear(final CommandSender sender, final Npc npc) { } } - /* MESSAGE LIST */ - @Command("npc message list") @Permission("fancynpcs.command.npc.message.list") - public void onMessageList(final CommandSender sender, final Npc npc) { + public void onMessageList( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { // Sending error message if the list is empty. if (npc.getData().getMessages().isEmpty()) { translator.translate("npc_message_list_failure_empty").send(sender); @@ -181,11 +172,13 @@ public void onMessageList(final CommandSender sender, final Npc npc) { translator.translate("npc_message_list_footer").send(sender); } - /* MESSAGE SEND_RANDOMLY */ - @Command("npc message send_randomly [state]") @Permission("fancynpcs.command.npc.message.send_randomly") - public void onMessageSendRandomly(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + public void onMessageSendRandomly( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Nullable Boolean state + ) { final boolean finalState = state != null ? state : !npc.getData().isSendMessagesRandomly(); // Calling the event and setting send_randomly state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MESSAGE_SEND_RANDOMLY, finalState, sender).callEvent()) { @@ -197,6 +190,7 @@ public void onMessageSendRandomly(final CommandSender sender, final Npc npc, fin } } + /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ @Suggestions("MessageCMD/none") @@ -215,6 +209,7 @@ public List suggestNumber(final CommandContext context, f }}; } + /* UTILITY METHODS */ /** Returns {@code true} if specified component contains blocked command, {@code false} otherwise. */ diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java index 8633de90..67861c83 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveHereCMD.java @@ -9,21 +9,19 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; -// NOTE: Perhaps a better command could be added instead, which supports both - teleporting to the sender and setting coordinates. +import org.jetbrains.annotations.NotNull; + public enum MoveHereCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command(value = "npc move_here", requiredSender = Player.class) - @Permission("fancynpcs.command.npc.move_here") - public void onDefault(final Player sender) { - translator.translate("npc_move_here_syntax").send(sender); - } - @Command(value = "npc move_here ", requiredSender = Player.class) @Permission("fancynpcs.command.npc.move_here") - public void onCommand(final Player sender, final Npc npc) { + public void onCommand( + final @NotNull Player sender, + final @NotNull Npc npc + ) { final Location location = sender.getLocation(); final String oldWorld = npc.getData().getLocation().getWorld().getName(); // Calling the event and moving the NPc to location of the sender, if not cancelled. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java index dbb5475e..18ac80fe 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java @@ -14,6 +14,7 @@ import java.text.DecimalFormat; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum MoveToCMD { @@ -23,18 +24,12 @@ public enum MoveToCMD { private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); - @Command("npc move_to") - @Permission("fancynpcs.command.npc.move_to") - public void onDefault(final CommandSender sender) { - translator.translate("npc_move_to_syntax").send(sender); - } - @Command("npc move_to [world]") @Permission("fancynpcs.command.npc.move_to") public void onCommand( - final CommandSender sender, - final Npc npc, - final @Argument(suggestions = "relative_location") Location location, + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull @Argument(suggestions = "relative_location") Location location, final @Nullable World world ) { // Finalizing World argument. Player-like senders don't have to specify the 'world' argument which then defaults to the World sender is currently in. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java index 24454e7c..7a29eb12 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NearbyCMD.java @@ -15,6 +15,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum NearbyCMD { @@ -32,7 +33,7 @@ public enum NearbyCMD { @Command(value = "npc nearby", requiredSender = Player.class) @Permission("fancynpcs.command.npc.nearby") public void onCommand( - final Player sender, + final @NotNull Player sender, final @Nullable @Flag("radius") Long radius, final @Nullable @Flag("type") EntityType type, final @Nullable @Flag("sort") SortType sort diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java similarity index 87% rename from src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java rename to src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java index 3f673b85..e22a18fc 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java @@ -14,36 +14,20 @@ import java.util.ArrayList; import java.util.List; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public enum NpcCMD { +public enum NpcHelpCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Suggestions("page") - public List suggestions(final CommandContext context, final CommandInput input) { - // Getting the (full) help contents. - final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); - // Calculating max page number. - final int maxPage = contents.getRawMessages().size() / 6 + 1; - // Returning suggestions... - return new ArrayList<>() {{ - for (int i = 1; i <= maxPage; i++) { - add(String.valueOf(i)); - }} - }; - } - - @Command("npc") - @Permission("fancynpcs.command.npc") - public void onDefault(final CommandSender sender) { - translator.translate("command_incomplete_usage").send(sender); - } - @Command("npc help [page]") @Permission("fancynpcs.command.npc") - public void onHelp(final CommandSender sender, final @Argument(suggestions = "page") @Nullable Integer page) { + public void onHelp( + final @NotNull CommandSender sender, + final @Nullable @Argument(suggestions = "NpcHelpCMD/page") Integer page + ) { // Getting the (full) help contents. final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); // Calculating max page number. @@ -60,4 +44,18 @@ public void onHelp(final CommandSender sender, final @Argument(suggestions = "pa translator.translate("npc_help_page_footer").replace("page", String.valueOf(finalPage)).replace("max_page", String.valueOf(maxPage)).send(sender); } + @Suggestions("NpcHelpCMD/page") + public List suggestions(final CommandContext context, final CommandInput input) { + // Getting the (full) help contents. + final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); + // Calculating max page number. + final int maxPage = contents.getRawMessages().size() / 6 + 1; + // Returning suggestions... + return new ArrayList<>() {{ + for (int i = 1; i <= maxPage; i++) { + add(String.valueOf(i)); + }} + }; + } + } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java index fc968698..3850e3f5 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java @@ -24,17 +24,13 @@ public enum PlayerCommandCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); - /* PLAYER_COMMAND ADD */ - - @Command("npc player_command add") - @Permission("fancynpcs.command.npc.player_command.add") - public void onPlayerCommandAdd(final CommandSender sender, final Npc npc) { - translator.translate("npc_player_command_add_syntax").send(sender); - } - @Command("npc player_command add ") @Permission("fancynpcs.command.npc.player_command.add") - public void onPlayerCommandAdd(final CommandSender sender, final Npc npc, final @Greedy String command) { + public void onPlayerCommandAdd( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull @Greedy String command + ) { // Sending error message in case banned command has been found in the input. if (hasBlockedCommands(command)) { translator.translate("command_input_contains_blocked_command").send(sender); @@ -49,17 +45,14 @@ public void onPlayerCommandAdd(final CommandSender sender, final Npc npc, final } } - /* PLAYER_COMMAND SET */ - - @Command("npc player_command set") - @Permission("fancynpcs.command.npc.player_command.set") - public void onPlayerCommandSet(final CommandSender sender, final Npc npc) { - translator.translate("npc_player_command_set_syntax").send(sender); - } - @Command("npc player_command set ") @Permission("fancynpcs.command.npc.player_command.set") - public void onPlayerCommandSet(final CommandSender sender, final Npc npc, final @Argument(suggestions = "PlayerCommandCMD/number_range") int number, final @Greedy String command) { + public void onPlayerCommandSet( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Argument(suggestions = "PlayerCommandCMD/number_range") int number, + final @NotNull @Greedy String command + ) { // Sending error message in case banned command has been found in the input. if (hasBlockedCommands(command)) { translator.translate("command_input_contains_blocked_command").send(sender); @@ -91,17 +84,13 @@ public void onPlayerCommandSet(final CommandSender sender, final Npc npc, final } } - /* PLAYER_COMMAND REMOVE */ - - @Command("npc player_command remove") - @Permission("fancynpcs.command.npc.player_command.remove") - public void onPlayerCommandRemove(final CommandSender sender, final Npc npc) { - translator.translate("npc_player_command_remove_syntax").send(sender); - } - @Command("npc player_command remove ") @Permission("fancynpcs.command.npc.player_command.remove") - public void onPlayerCommandRemove(final CommandSender sender, final Npc npc, final @Argument(suggestions = "PlayerCommandCMD/number_range") int number) { + public void onPlayerCommandRemove( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Argument(suggestions = "PlayerCommandCMD/number_range") int number + ) { // Getting the total count of player commands that are currently in the list. final int totalCount = npc.getData().getPlayerCommands().size(); // Sending error message if the list is empty. @@ -131,11 +120,12 @@ public void onPlayerCommandRemove(final CommandSender sender, final Npc npc, fin } } - /* PLAYER_COMMAND CLEAR */ - @Command("npc player_command clear") @Permission("fancynpcs.command.npc.player_command.clear") - public void onPlayerCommandClear(final CommandSender sender, final Npc npc) { + public void onPlayerCommandClear( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { final int total = npc.getData().getPlayerCommands().size(); // Calling the event and clearing player commands if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.PLAYER_COMMAND_CLEAR, null, sender).callEvent()) { @@ -146,11 +136,12 @@ public void onPlayerCommandClear(final CommandSender sender, final Npc npc) { } } - /* PLAYER_COMMAND LIST */ - @Command("npc player_command list") @Permission("fancynpcs.command.npc.player_command.list") - public void onPlayerCommandList(final CommandSender sender, final Npc npc) { + public void onPlayerCommandList( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { // Sending error message if the list is empty. if (npc.getData().getPlayerCommands().isEmpty()) { translator.translate("npc_player_command_list_failure_empty").send(sender); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java index 7ad08f78..5fa009b2 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/RemoveCMD.java @@ -6,29 +6,24 @@ import de.oliver.fancynpcs.api.events.NpcRemoveEvent; import de.oliver.fancynpcs.api.events.NpcStopLookingEvent; import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; -import org.incendo.cloud.annotations.Flag; import org.incendo.cloud.annotations.Permission; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; public enum RemoveCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("npc remove") - @Permission("fancynpcs.command.npc.remove") - public void onDefault(final CommandSender sender) { - translator.translate("npc_remove_syntax").send(sender); - } - @Command("npc remove ") @Permission("fancynpcs.command.npc.remove") - public void onCommand(final CommandSender sender, final Npc npc, final @Nullable @Flag("creator") OfflinePlayer creator) { + public void onRemove( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { // Calling the event and removing the NPC if not cancelled. if (new NpcRemoveEvent(npc, sender).callEvent()) { npc.removeForAll(); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java deleted file mode 100644 index 5bccb9b1..00000000 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java +++ /dev/null @@ -1,74 +0,0 @@ -package de.oliver.fancynpcs.commands.npc; - -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; -import de.oliver.fancynpcs.FancyNpcs; -import de.oliver.fancynpcs.api.Npc; -import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.commands.Subcommand; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.stream.Stream; - -public class ServerCommandCMD implements Subcommand { - - private final LanguageConfig lang = FancyNpcs.getInstance().getLanguageConfig(); - - @Override - public List tabcompletion(@NotNull Player player, @Nullable Npc npc, @NotNull String[] args) { - if (args.length == 3) { - return Stream.of("none") - .filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase())) - .toList(); - } - - return null; - } - - @Override - public boolean run(@NotNull CommandSender receiver, @Nullable Npc npc, @NotNull String[] args) { - if (args.length < 3) { - MessageHelper.error(receiver, lang.get("wrong-usage")); - return false; - } - - - if (npc == null) { - MessageHelper.error(receiver, lang.get("npc-not-found")); - return false; - } - - String cmd = ""; - for (int i = 2; i < args.length; i++) { - cmd += args[i] + " "; - } - cmd = cmd.substring(0, cmd.length() - 1); - - if (cmd.equalsIgnoreCase("none")) { - cmd = ""; - } - - for (String blockedCommand : FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands()) { - if (cmd.equalsIgnoreCase(blockedCommand) || cmd.toLowerCase().startsWith(blockedCommand.toLowerCase() + " ")) { - MessageHelper.error(receiver, lang.get("illegal-command")); - return false; - } - } - - NpcModifyEvent npcModifyEvent = new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SERVER_COMMAND, cmd, receiver); - npcModifyEvent.callEvent(); - - if (!npcModifyEvent.isCancelled()) { - npc.getData().setServerCommand(cmd); - MessageHelper.success(receiver, lang.get("npc-command-serverCommand-updated", "npc", npc.getData().getName())); - } else { - MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); - } - - return true; - } -} diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java index 288df162..8fa9cd63 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java @@ -8,6 +8,7 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum ShowInTabCMD { @@ -15,15 +16,13 @@ public enum ShowInTabCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("npc show_in_tab") - @Permission("fancynpcs.command.npc.show_in_tab") - public void onDefault(final CommandSender sender) { - translator.translate("npc_show_in_tab_syntax").send(sender); - } - @Command("npc show_in_tab [state]") @Permission("fancynpcs.command.npc.show_in_tab") - public void onCommand(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + public void onCommand( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Nullable Boolean state + ) { final boolean finalState = (state == null) ? !npc.getData().isShowInTab() : state; // Calling the event and updating the state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SHOW_IN_TAB, finalState, sender).callEvent()) { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java index 5df90dda..8bd24f58 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java @@ -33,24 +33,13 @@ public enum SkinCMD { private static final Pattern USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{3,16}$"); - @Suggestions("skin") - public List suggestions(final CommandContext context, final CommandInput input) { - return new ArrayList<>() {{ - add("@none"); - add("@mirror"); - Bukkit.getOnlinePlayers().stream().map(Player::getName).forEach(this::add); - }}; - } - - @Command("npc skin") - @Permission("fancynpcs.command.npc.skin") - public void onDefault(final CommandSender sender) { - translator.translate("npc_skin_syntax").send(sender); - } - @Command("npc skin ") @Permission("fancynpcs.command.npc.skin") - public void onCommand(final CommandSender sender, final Npc npc, final @Argument(suggestions = "skin") String skin) { + public void onSkin( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull @Argument(suggestions = "SkinCMD/skin") String skin + ) { // Exiting command block if specified NPC is not of a PLAYER type. if (npc.getData().getType() != EntityType.PLAYER) { translator.translate("command_unsupported_npc_type").send(sender); @@ -139,6 +128,15 @@ public void onCommand(final CommandSender sender, final Npc npc, final @Argument } } + @Suggestions("SkinCMD/skin") + public List suggestSkin(final CommandContext context, final CommandInput input) { + return new ArrayList<>() {{ + add("@none"); + add("@mirror"); + Bukkit.getOnlinePlayers().stream().map(Player::getName).forEach(this::add); + }}; + } + // Returns 'true' if String can be parsed to an URL or 'false' otherwise. private static boolean isURL(final @NotNull String url) { try { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java index 8c821007..c229d4b2 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java @@ -8,20 +8,19 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; + public enum TeleportCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command(value = "npc teleport", requiredSender = Player.class) - @Permission("fancynpcs.command.npc.teleport") - public void onDefault(final Player sender) { - translator.translate("npc_teleport_syntax").send(sender); - } - @Command(value = "npc teleport ", requiredSender = Player.class) @Permission("fancynpcs.command.npc.teleport") - public void onCommand(final Player sender, final Npc npc) { + public void onTeleport( + final @NotNull Player sender, + final @NotNull Npc npc + ) { final Location location = npc.getData().getLocation(); // Checking if the world is still loaded. if (location.getWorld() == null) { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java index 4dbdcd49..4d939494 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TurnToPlayerCMD.java @@ -8,6 +8,7 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public enum TurnToPlayerCMD { @@ -15,26 +16,20 @@ public enum TurnToPlayerCMD { private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("npc turn_to_player") - @Permission("fancynpcs.command.npc.turn_to_player") - public void onDefault(final CommandSender sender) { - translator.translate("npc_turn_to_player_syntax").send(sender); - } - @Command("npc turn_to_player [state]") @Permission("fancynpcs.command.npc.turn_to_player") - public void onCommand(final CommandSender sender, final Npc npc, final @Nullable Boolean state) { + public void onTurnToPlayer( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Nullable Boolean state + ) { final boolean finalState = (state == null) ? !npc.getData().isTurnToPlayer() : state; // Calling the event and updating the state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.TURN_TO_PLAYER, finalState, sender).callEvent()) { - // Updating the state. npc.getData().setTurnToPlayer(finalState); - // Sending message to the sender. translator.translate(finalState ? "npc_turn_to_player_set_true" : "npc_turn_to_player_set_false").replace("npc", npc.getData().getName()).send(sender); - // Returning from the command block. return; } - // Otherwise, sending error message to the sender. translator.translate("command_npc_modification_cancelled").send(sender); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java index 5adf3551..5e184d15 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TypeCMD.java @@ -9,39 +9,35 @@ import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; + public enum TypeCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("npc type") - @Permission("fancynpcs.command.npc.type") - public void onDefault(final CommandSender sender) { - translator.translate("npc_type_syntax").send(sender); - } - @Command("npc type ") @Permission("fancynpcs.command.npc.type") - public boolean onCommand(final CommandSender sender, final Npc npc, final EntityType type) { + public void onType( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull EntityType type + ) { // Calling the event and updating the type if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.TYPE, type, sender).callEvent()) { npc.getData().setType(type); - if (type != EntityType.PLAYER) { - npc.getData().setGlowing(false); + // Removing NPC from the player-list if new type is not EntityType.PLAYER. + if (type != EntityType.PLAYER) npc.getData().setShowInTab(false); - if (npc.getData().getEquipment() != null) { - npc.getData().getEquipment().clear(); - } - } - + // Clearing equipment if new type is not a living entity or equipment list is empty. + if (!type.isAlive() && npc.getData().getEquipment() != null) + npc.getData().getEquipment().clear(); npc.removeForAll(); npc.create(); npc.spawnForAll(); - //MessageHelper.success(receiver, lang.get("npc-command-type-updated", "npc", npc.getData().getName(), "type", type.name().toLowerCase())); + translator.translate("npc_type_success").replace("npc", npc.getData().getName()).replace("type", type.name().toLowerCase()).send(sender); } else { - //MessageHelper.error(receiver, lang.get("npc-command-modification-cancelled")); + translator.translate("command_npc_modification_cancelled").send(sender); } - - return true; } } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 19659345..24cb0250 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -50,8 +50,42 @@ messages: command_unsupported_npc_type: "› This NPC type does not support this feature." command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." + # Generic Syntax Message (syntax is provided by Cloud and may not be human-friendly) + command_invalid_syntax_generic: "Syntax: {warningColor}{syntax}" + # Command Syntaxes + command_syntax: + fancynpcs: "Syntax: {primaryColor}/fancynpcs {secondaryColor}(version | reload | save | feature_flags)" + npc: "› {errorColor}Unknown command. Use {warningColor}/npc help{errorColor} to view available commands." + npc_attribute: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}(set | list)" + npc_attribute_set: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}set {secondaryColor}(attribute) (value)" + npc_collidable: "Syntax: {primaryColor}/npc collidable {secondaryColor}(npc) (state)" + npc_copy: "Syntax: {primaryColor}/npc copy {secondaryColor}(npc) (new_name)" + npc_create: "Syntax: {primaryColor}/npc create {secondaryColor}(npc) [--type] [--position] [--world]" + npc_displayname: "Syntax: {primaryColor}/npc displayname {secondaryColor}(npc) (name)" + npc_equipment: "Syntax: {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}(set | clear | list)" + npc_equipment_set: "Syntax: {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}set {secondaryColor}(slot) (@hand | @none | item)" + npc_glowing: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color)" + npc_info: "Syntax: {primaryColor}/npc info {secondaryColor}(npc)" + npc_interaction_cooldown: "Syntax: {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (seconds)" + npc_list: "Syntax: {primaryColor}/npc list {secondaryColor}[filters...]" + npc_message: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}(add | set | remove | clear | list | send_randomly)" + npc_message_add: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) add (@none | message)" + npc_message_remove: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) remove (number)" + npc_message_set: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) set (number) (@none | message)" + npc_move_here: "Syntax: {primaryColor}/npc move_here {secondaryColor}(npc)" + npc_move_to: "Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" + npc_nearby: "Syntax: {primaryColor}/npc nearby {secondaryColor}[filters...]" + npc_player_command: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}(add | set | remove | clear | list)" + npc_player_command_add: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) add (command)" + npc_player_command_remove: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) remove (number)" + npc_player_command_set: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) set (number) (command)" + npc_remove: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" + npc_show_in_tab: "Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" + npc_skin: "Syntax: {primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" + npc_teleport: "Syntax: {primaryColor}/npc teleport {secondaryColor}(npc)" + npc_turn_to_player: "Syntax: {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" + npc_type: "Syntax: {primaryColor}/npc type {secondaryColor}(npc) (type)" # Commands - fancynpcs_syntax: "Syntax: {primaryColor}/fancynpcs {secondaryColor}(version | reload | save | feature_flags)" fancynpcs_reload_success: "› {successColor}Plugin has been reloaded." fancynpcs_save_success: "› {successColor}NPCs have been saved." fancynpcs_version: "" # NOT CONFIGURABLE @@ -61,29 +95,45 @@ messages: npc_help_page_header: "------------- {primaryColor}FancyNpcs Commands ({primaryColor}{page}/{primaryColor}{max_page}) --------------" npc_help_page_footer: "----------- Click {primaryColor}here to open documentation -----------" npc_help_contents: - - "› {primaryColor}/npc create {secondaryColor}(npc) - Creates a new NPC at your location." - - "› {primaryColor}/npc remove {secondaryColor}(npc) - Removes specified NPC." - - "› {primaryColor}/npc copy {secondaryColor}(npc) (new_name) - Copies/clones specified NPC." - - "› {primaryColor}/npc list {secondaryColor}[flags...] - Lists all NPCs." - - "› {primaryColor}/npc nearby {secondaryColor}[flags...] - Lists nearby NPCs." - - "› {primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url) - Changes NPC's skin." + # - "› {primaryColor}/npc create {secondaryColor}(npc) - Creates a new NPC at your location." + # - "› {primaryColor}/npc remove {secondaryColor}(npc) - Removes specified NPC." + # - "› {primaryColor}/npc copy {secondaryColor}(npc) (new_name) - Copies/clones specified NPC." + # - "› {primaryColor}/npc list {secondaryColor}[flags...] - Lists all NPCs." + # - "› {primaryColor}/npc nearby {secondaryColor}[flags...] - Lists nearby NPCs." + # - "› {primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url) - Changes NPC's skin." + - "Creates a new NPC at your location.'>{primaryColor}/npc create {secondaryColor}(npc) <#6B1216>[--type] [--position] [--world]" + - "Removes specified NPC.'>{primaryColor}/npc remove {secondaryColor}(npc)" + - "Copies/clones specified NPC.'>{primaryColor}/npc copy {secondaryColor}(npc) (new_name)" + - "Lists all NPCs in all worlds. Filters can be applied.'>{primaryColor}/npc list <#6B1216>[--type] [--sort]" + - "Lists all NPCs in player''s world. Filters can be applied.'>{primaryColor}/npc nearby <#6B1216>[--radius] [--type] [--sort]" + - "Changes skin of the NPC.'>{primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url)" + - "› {primaryColor}/npc type {secondaryColor}(npc) (type) - Changes entity type of an NPC." - "› {primaryColor}/npc teleport {secondaryColor}(npc) - Teleports you to the NPC." - "› {primaryColor}/npc move_here {secondaryColor}(npc) - Moves NPC to your location." - "› {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world] - Moves NPC." - "› {primaryColor}/npc displayname {secondaryColor}(npc) (name) - Changes NPC's displayname." - - "› {primaryColor}/npc equipment {secondaryColor}(npc) (slot) - Changes equipment of an NPC." - - "› {primaryColor}/npc message {secondaryColor}(npc) (...) - Changes click message(s)." - - "› {primaryColor}/npc playerCommand {secondaryColor}(npc) (...) - Changes click command(s)." - - "› {primaryColor}/npc serverCommand {secondaryColor}(npc) (...) - Changes click command(s)." + - "› {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}set {secondaryColor}(slot) (item) - Changes equipment." + - "› {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}clear - Clears equipment." + - "› {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}list - Lists equipment." + - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}add {secondaryColor}(message) - Adds message." + - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}set {secondaryColor}(num) (message) - Sets message." + - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(num) - Removes message." + - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}clear - Clears message." + - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}list - Lists message." + - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}send_randomly {secondaryColor}[state] - " + - "› {primaryColor}/npc player_command {secondaryColor}(npc) (...) - Manages click commands." + - "› {primaryColor}/npc server_command {secondaryColor}(npc) (...) - Manages click commands." - "› {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state) - Changes tab-list visibility." - "› {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color) - Changes glowing state." - "› {primaryColor}/npc collidable {secondaryColor}(npc) (state) - Changes collidable state." - "› {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state) - Changes turning state." - - "› {primaryColor}/npc attribute {secondaryColor}(npc) (attr) (value) - Sets entity attribute." + - "› {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}set {secondaryColor}(attr) (value) - Sets attribute." + - "› {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}list - Lists attributes." + - "› {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}clear - Clears attributes." - "› {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." - npc_attribute_set_syntax: "Syntax: {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}set {secondaryColor}(attribute) (value)" + # FIX COLORS npc_attribute_set: "Attribute {warningColor}{attribute} has been set to {warningColor}{value}." npc_attribute_set_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." npc_attribute_list_header: "-------------------- Attributes --------------------" @@ -91,24 +141,19 @@ messages: npc_attribute_list_footer: "---------------------------------------------------" npc_attribute_list_failure_empty: "› {errorColor}There is no attributes set. Use {warningColor}/npc attribute (npc) set (attribute) (value){errorColor} to set an attribute." - npc_collidable_syntax: "Syntax: {primaryColor}/npc collidable {secondaryColor}(npc) (state)" npc_collidable_set_true: "NPC {warningColor}{npc} is now collidable." npc_collidable_set_false: "NPC {warningColor}{npc} is no longer collidable." - npc_copy_syntax: "Syntax: {primaryColor}/npc copy {secondaryColor}(npc) (new_name)" npc_copy_success: "NPC {warningColor}{npc} has been copied to {warningColor}{new_npc}." - npc_create_syntax: "Syntax: {primaryColor}/npc create {secondaryColor}(npc)" npc_create_success: "NPC {warningColor}{npc} has been created." npc_create_failure_invalid_name: "› {errorColor}Name contains illegal characters. Only [{warningColor}A-Z{errorColor}, {warningColor}a-z{errorColor}, {warningColor}0-9{errorColor}, {warningColor}_{errorColor}, {warningColor}-{errorColor}, {warningColor}/{errorColor}] characters are allowed." npc_create_failure_already_exists: "› {errorColor}NPC {warningColor}{npc}{errorColor} already exists." npc_create_failure_must_specify_world: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." - npc_displayname_syntax: "Syntax: {primaryColor}/npc displayname {secondaryColor}(npc) (name)" npc_displayname_set_name: "NPC {warningColor}{npc} is now using {name} as their display name." npc_displayname_set_empty: "NPC {warningColor}{npc} is no longer showing display name." - npc_equipment_set_syntax: "Syntax: {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}set {secondaryColor}(slot) (@hand | @none | item)" npc_equipment_set_item: "Equipment slot {warningColor}{slot} has been set to ." npc_equipment_set_empty: "Equipment slot {warningColor}{slot} has been removed." npc_equipment_set_failure_invalid_slot: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid equipment slot." @@ -120,13 +165,11 @@ messages: npc_fix_success: "Attempted to fix NPC {warningColor}{npc}... Still having issues? Please let us know." - npc_glowing_syntax: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color)" npc_glowing_set_true: "NPC {warningColor}{npc} is now glowing." npc_glowing_set_false: "NPC {warningColor}{npc} is no longer glowing." npc_glowing_set_color_success: "NPC {warningColor}{npc} is now glowing in {color}." npc_glowing_set_color_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." - npc_info_syntax: "Syntax: {primaryColor}/npc info {secondaryColor}(npc)" npc_info_general: - "" - "Unique, permanent identifier of the NPC.'><#848484>Identifier: Click to copy identifier to clipboard.'>{warningColor}{id_short}" @@ -152,10 +195,8 @@ messages: - "Open the chat window to see all information." - "" - npc_interaction_cooldown_syntax: "Syntax: {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (seconds)" npc_interaction_cooldown_success: "NPC {warningColor}{npc} has had their interaction cooldown updated." - npc_skin_syntax: "Syntax: {primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" npc_skin_set_name: "NPC {warningColor}{npc} is now using {warningColor}{name}'s skin." npc_skin_set_url: "NPC {warningColor}{npc} is now using skin from specified URL." npc_skin_set_mirror: "NPC {warningColor}{npc} is now mirroring player skin." @@ -164,49 +205,37 @@ messages: npc_skin_failure_invalid_name_or_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid player name or URL." npc_skin_failure_invalid_name_or_rate_limit: "› {errorColor}Could not find {warningColor}{input}'s{errorColor} skin. Either the account does not exist or you're being rate limited." - npc_move_here_syntax: "Syntax: {primaryColor}/npc move_here {secondaryColor}(npc)" npc_move_here_success: "NPC {warningColor}{npc} has been moved to your location." - npc_remove_syntax: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" npc_remove_success: "NPC {warningColor}{npc} has been removed." - npc_list_syntax: "Syntax: {primaryColor}/npc list {secondaryColor}[filters...]" npc_list_header: "------------------ List Query Result ------------------" npc_list_entry: " <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({location_x}, {location_y}, {location_z} in {world})" npc_list_footer: "---------- Showing {warningColor}{count_formatted} out of total {warningColor}{total_formatted} entries ----------" + npc_list_failure_sort_requires_player: "› {errorColor}This sort type cannot be used from the console." + npc_list_failure_requires_world_flag: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." - npc_nearby_syntax: "Syntax: {primaryColor}/npc nearby {secondaryColor}[filters...]" npc_nearby_header: "---------------- Nearby Query Result -----------------" npc_nearby_entry: " <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({distance} blocks away)" npc_nearby_footer: "---------- Showing {warningColor}{count_formatted} out of total {warningColor}{total_formatted} entries ----------" - npc_list_failure_sort_requires_player: "› {errorColor}This sort type cannot be used from the console." - npc_list_failure_requires_world_flag: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." - - npc_move_to_syntax: "Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" npc_move_to_success: "NPC {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." npc_move_to_failure_must_specify_world: "› {errorColor}You must specify world when running this command from the console." - npc_teleport_syntax: "Syntax: {primaryColor}/npc teleport {secondaryColor}(npc)" npc_teleport_success: "You have been teleported to NPC {warningColor}{npc}." npc_teleport_failure_exception: "› {errorColor}An error occurred while trying to teleport to NPC. Check console for errors." npc_teleport_failure_world_not_loaded: "› {errorColor}An error occurred while trying to teleport to NPC. Destination world is not loaded." - npc_turn_to_player_syntax: "Syntax: {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" npc_turn_to_player_set_true: "NPC {warningColor}{npc} is now turning to player." npc_turn_to_player_set_false: "NPC {warningColor}{npc} is no longer turning to player." - npc_show_in_tab_syntax: "Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" npc_show_in_tab_set_true: "NPC {warningColor}{npc} is now shown in player-list." npc_show_in_tab_set_false: "NPC {warningColor}{npc} is no longer shown in player-list." - npc_message_add_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) add (@none | message)" npc_message_add_success: "Message has been added. There is {warningColor}{total} messages in total." - npc_message_set_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) set (number) (@none | message)" npc_message_set_success: "Message {warningColor}{number} has been updated. There is {warningColor}{total} messages in total." npc_message_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_message_set_failure_list_is_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." - npc_message_remove_syntax: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) remove (number)" npc_message_remove_success: "Message {warningColor}{number} has been removed. There is {warningColor}{total} messages in total." npc_message_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_message_remove_failure_list_is_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." @@ -218,13 +247,10 @@ messages: npc_message_list_footer: "---------------------------------------------------" npc_message_list_failure_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." - npc_player_command_add_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) add (command)" npc_player_command_add_success: "Command has been added. There is {warningColor}{total} commands in total." - npc_player_command_set_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) set (number) (command)" npc_player_command_set_success: "Command {warningColor}{number} has been updated. There is {warningColor}{total} commands in total." npc_player_command_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_player_command_set_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." - npc_player_command_remove_syntax: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) remove (number)" npc_player_command_remove_success: "Command {warningColor}{number} has been removed. There is {warningColor}{total} commands in total." npc_player_command_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_player_command_remove_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." @@ -234,4 +260,6 @@ messages: npc_player_command_list_footer: "---------------------------------------------------" npc_player_command_list_failure_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." + npc_type_success: "NPC {warningColor}{npc} type has been changed to {warningColor}{type}." + From ffe4c33e0ea558acc0be828fb62f4132e61132c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 16:59:10 +0200 Subject: [PATCH 69/94] fix colors in some syntax messages --- src/main/resources/languages/en.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 24cb0250..8ab4f902 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -51,7 +51,7 @@ messages: command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." # Generic Syntax Message (syntax is provided by Cloud and may not be human-friendly) - command_invalid_syntax_generic: "Syntax: {warningColor}{syntax}" + command_invalid_syntax_generic: "Syntax: {warningColor}/{syntax}" # Command Syntaxes command_syntax: fancynpcs: "Syntax: {primaryColor}/fancynpcs {secondaryColor}(version | reload | save | feature_flags)" @@ -69,16 +69,16 @@ messages: npc_interaction_cooldown: "Syntax: {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (seconds)" npc_list: "Syntax: {primaryColor}/npc list {secondaryColor}[filters...]" npc_message: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}(add | set | remove | clear | list | send_randomly)" - npc_message_add: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) add (@none | message)" - npc_message_remove: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) remove (number)" - npc_message_set: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) set (number) (@none | message)" + npc_message_add: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}add {secondaryColor}(@none | message)" + npc_message_remove: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + npc_message_set: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (@none | message)" npc_move_here: "Syntax: {primaryColor}/npc move_here {secondaryColor}(npc)" npc_move_to: "Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" npc_nearby: "Syntax: {primaryColor}/npc nearby {secondaryColor}[filters...]" npc_player_command: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}(add | set | remove | clear | list)" - npc_player_command_add: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) add (command)" - npc_player_command_remove: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) remove (number)" - npc_player_command_set: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) set (number) (command)" + npc_player_command_add: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" + npc_player_command_remove: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + npc_player_command_set: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" npc_remove: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" npc_show_in_tab: "Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" npc_skin: "Syntax: {primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" From 43bdfa6596cca46579c2ae6d3723997d1cb162ee Mon Sep 17 00:00:00 2001 From: OliverSchlueter Date: Wed, 15 May 2024 19:34:25 +0200 Subject: [PATCH 70/94] Add multiple server commands --- .../java/de/oliver/fancynpcs/api/Npc.java | 5 +- .../java/de/oliver/fancynpcs/api/NpcData.java | 25 ++- .../api/events/NpcInteractEvent.java | 21 +- .../de/oliver/fancynpcs/NpcManagerImpl.java | 26 ++- .../commands/CloudCommandManager.java | 26 +-- .../fancynpcs/commands/npc/CopyCMD.java | 9 +- .../fancynpcs/commands/npc/InfoCMD.java | 8 +- .../commands/npc/ServerCommandCMD.java | 195 ++++++++++++++++++ src/main/resources/languages/en.yml | 17 ++ 9 files changed, 267 insertions(+), 65 deletions(-) create mode 100644 src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java diff --git a/api/src/main/java/de/oliver/fancynpcs/api/Npc.java b/api/src/main/java/de/oliver/fancynpcs/api/Npc.java index 92d80114..d07848bd 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/Npc.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/Npc.java @@ -165,7 +165,7 @@ public void interact(Player player, InteractionType interactionType) { lastPlayerInteraction.put(player.getUniqueId(), System.currentTimeMillis()); } - NpcInteractEvent npcInteractEvent = new NpcInteractEvent(this, data.getPlayerCommands(), data.getServerCommand(), data.getOnClick(), player, interactionType); + NpcInteractEvent npcInteractEvent = new NpcInteractEvent(this, data.getPlayerCommands(), data.getServerCommands(), data.getOnClick(), player, interactionType); npcInteractEvent.callEvent(); if (npcInteractEvent.isCancelled()) { @@ -190,8 +190,7 @@ public void interact(Player player, InteractionType interactionType) { } // serverCommand - if (data.getServerCommand() != null && data.getServerCommand().length() > 0) { - String command = data.getServerCommand(); + for (String command : data.getServerCommands()) { command = command.replace("{player}", player.getName()); String finalCommand = ChatColorHandler.translate(command, player, List.of(PlaceholderAPIParser.class)); diff --git a/api/src/main/java/de/oliver/fancynpcs/api/NpcData.java b/api/src/main/java/de/oliver/fancynpcs/api/NpcData.java index 668d2d74..b40717f9 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/NpcData.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/NpcData.java @@ -28,8 +28,8 @@ public class NpcData { private Map equipment; private Consumer onClick; private boolean turnToPlayer; - private String serverCommand; private List playerCommands; + private List serverCommands; private List messages; private boolean sendMessagesRandomly; private float interactionCooldown; @@ -55,7 +55,7 @@ public NpcData( Consumer onClick, List messages, boolean sendMessagesRandomly, - String serverCommand, + List serverCommands, List playerCommands, float interactionCooldown, Map attributes, @@ -76,7 +76,7 @@ public NpcData( this.equipment = equipment; this.onClick = onClick; this.turnToPlayer = turnToPlayer; - this.serverCommand = serverCommand; + this.serverCommands = serverCommands; this.playerCommands = playerCommands; this.messages = messages; this.sendMessagesRandomly = sendMessagesRandomly; @@ -105,6 +105,7 @@ public NpcData(String name, UUID creator, Location location) { }; this.turnToPlayer = false; this.messages = new ArrayList<>(); + this.serverCommands = new ArrayList<>(); this.playerCommands = new ArrayList<>(); this.sendMessagesRandomly = false; this.interactionCooldown = 0; @@ -253,16 +254,26 @@ public NpcData setTurnToPlayer(boolean turnToPlayer) { return this; } - public String getServerCommand() { - return serverCommand; + public List getServerCommands() { + return serverCommands; } - public NpcData setServerCommand(String serverCommand) { - this.serverCommand = serverCommand; + public NpcData setServerCommands(List serverCommands) { + this.serverCommands = serverCommands; isDirty = true; return this; } + public void addServerCommand(String command) { + serverCommands.add(command); + isDirty = true; + } + + public void removeServerCommand(int index) { + serverCommands.remove(index); + isDirty = true; + } + public List getPlayerCommands() { return playerCommands; } diff --git a/api/src/main/java/de/oliver/fancynpcs/api/events/NpcInteractEvent.java b/api/src/main/java/de/oliver/fancynpcs/api/events/NpcInteractEvent.java index 20c87795..17a04e64 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/events/NpcInteractEvent.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/events/NpcInteractEvent.java @@ -5,13 +5,12 @@ import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Consumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - /** * Is fired when a player interacts with a NPC */ @@ -23,7 +22,7 @@ public class NpcInteractEvent extends Event implements Cancellable { @Nullable private final List playerCommands; @Nullable - private final String serverCommand; + private final List serverCommands; @NotNull private final Consumer onClick; @NotNull @@ -31,10 +30,10 @@ public class NpcInteractEvent extends Event implements Cancellable { private final InteractionType interactionType; private boolean isCancelled; - public NpcInteractEvent(@NotNull Npc npc, @Nullable List playerCommands, @Nullable String serverCommand, @NotNull Consumer onClick, @NotNull Player player, @NotNull InteractionType interactionType) { + public NpcInteractEvent(@NotNull Npc npc, @Nullable List playerCommands, @Nullable List serverCommands, @NotNull Consumer onClick, @NotNull Player player, @NotNull InteractionType interactionType) { this.npc = npc; this.playerCommands = playerCommands; - this.serverCommand = serverCommand; + this.serverCommands = serverCommands; this.onClick = onClick; this.player = player; this.interactionType = interactionType; @@ -59,10 +58,10 @@ public static HandlerList getHandlerList() { } /** - * @return the command that the server will run + * @return the commands that the server will run */ - public @Nullable String getServerCommand() { - return serverCommand; + public @Nullable List getServerCommands() { + return serverCommands; } /** @@ -104,7 +103,9 @@ public void setCancelled(boolean cancel) { public enum InteractionType { LEFT_CLICK, RIGHT_CLICK, - /** {@link InteractionType#CUSTOM InteractionType#CUSTOM} represents interactions invoked by the API. */ + /** + * {@link InteractionType#CUSTOM InteractionType#CUSTOM} represents interactions invoked by the API. + */ CUSTOM } diff --git a/src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java b/src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java index 4a5eba6d..62a04287 100644 --- a/src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java +++ b/src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java @@ -153,9 +153,11 @@ public void saveNpcs(boolean force) { npcConfig.set("npcs." + data.getId() + ".glowingColor", data.getGlowingColor().toString()); npcConfig.set("npcs." + data.getId() + ".turnToPlayer", data.isTurnToPlayer()); npcConfig.set("npcs." + data.getId() + ".messages", data.getMessages()); - npcConfig.set("npcs." + data.getId() + ".message", null); //TODO: remove in 2.0.9 + npcConfig.set("npcs." + data.getId() + ".message", null); //TODO: remove in 2.1.1 npcConfig.set("npcs." + data.getId() + ".playerCommands", data.getPlayerCommands()); - npcConfig.set("npcs." + data.getId() + ".playerCommand", null); //TODO: remove in 2.0.9 + npcConfig.set("npcs." + data.getId() + ".playerCommand", null); //TODO: remove in 2.1.1 + npcConfig.set("npcs." + data.getId() + ".serverCommands", data.getServerCommands()); + npcConfig.set("npcs." + data.getId() + ".serverCommand", null); //TODO: remove in 2.1.1 npcConfig.set("npcs." + data.getId() + ".sendMessagesRandomly", data.isSendMessagesRandomly()); npcConfig.set("npcs." + data.getId() + ".interactionCooldown", data.getInteractionCooldown()); npcConfig.set("npcs." + data.getId() + ".mirrorSkin", data.isMirrorSkin()); @@ -172,10 +174,6 @@ public void saveNpcs(boolean force) { } } - if (data.getServerCommand() != null) { - npcConfig.set("npcs." + data.getId() + ".serverCommand", data.getServerCommand()); - } - for (NpcAttribute attribute : FancyNpcs.getInstance().getAttributeManager().getAllAttributesForEntityType(data.getType())) { String value = data.getAttributes().getOrDefault(attribute, null); npcConfig.set("npcs." + data.getId() + ".attributes." + attribute.getName(), value); @@ -255,14 +253,16 @@ public void loadNpcs() { NamedTextColor glowingColor = NamedTextColor.NAMES.value(npcConfig.getString("npcs." + id + ".glowingColor", "white")); boolean turnToPlayer = npcConfig.getBoolean("npcs." + id + ".turnToPlayer"); boolean sendMessagesRandomly = npcConfig.getBoolean("npcs." + id + ".sendMessagesRandomly", false); - String serverCommand = npcConfig.getString("npcs." + id + ".serverCommand"); - @Deprecated(since = "2.0.8") String playerCommand = npcConfig.getString("npcs." + id + ".playerCommand"); //TODO: remove in 2.0.9 + @Deprecated(since = "2.0.8") String playerCommand = npcConfig.getString("npcs." + id + ".playerCommand"); //TODO: remove in 2.1.1 List playerCommands = npcConfig.getStringList("npcs." + id + ".playerCommands"); - @Deprecated(since = "2.0.7") String message = npcConfig.getString("npcs." + id + ".message"); // TODO: remove in 2.0.9 + @Deprecated(since = "2.0.7") String message = npcConfig.getString("npcs." + id + ".message"); // TODO: remove in 2.1.1 List messages = npcConfig.getStringList("npcs." + id + ".messages"); + @Deprecated(since = "2.0.10") String serverCommand = npcConfig.getString("npcs." + id + ".serverCommand"); // TODO: remove in 2.1.1 + List serverCommands = npcConfig.getStringList("npcs." + id + ".serverCommands"); + float interactionCooldown = (float) npcConfig.getDouble("npcs." + id + ".interactionCooldown", 0); boolean mirrorSkin = npcConfig.getBoolean("npcs." + id + ".mirrorSkin"); @@ -295,7 +295,13 @@ public void loadNpcs() { playerCommands.add(playerCommand); } - NpcData data = new NpcData(id, name, creator, displayName, skin, location, showInTab, spawnEntity, collidable, glowing, glowingColor, type, new HashMap<>(), turnToPlayer, null, messages, sendMessagesRandomly, serverCommand, playerCommands, interactionCooldown, attributes, mirrorSkin); + // TODO: remove when the 'serverCommand' field is removed, and just pass in the 'serverCommands' + if (serverCommands.isEmpty() && serverCommand != null && !serverCommand.isEmpty()) { + serverCommands = new ArrayList<>(); + serverCommands.add(serverCommand); + } + + NpcData data = new NpcData(id, name, creator, displayName, skin, location, showInTab, spawnEntity, collidable, glowing, glowingColor, type, new HashMap<>(), turnToPlayer, null, messages, sendMessagesRandomly, serverCommands, playerCommands, interactionCooldown, attributes, mirrorSkin); Npc npc = npcAdapter.apply(data); if (npcConfig.isConfigurationSection("npcs." + id + ".equipment")) { diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 12345a4c..4775c5f4 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -5,29 +5,7 @@ import de.oliver.fancynpcs.commands.arguments.LocationArgument; import de.oliver.fancynpcs.commands.arguments.NpcArgument; import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; -import de.oliver.fancynpcs.commands.npc.AttributeCMD; -import de.oliver.fancynpcs.commands.npc.CollidableCMD; -import de.oliver.fancynpcs.commands.npc.CopyCMD; -import de.oliver.fancynpcs.commands.npc.CreateCMD; -import de.oliver.fancynpcs.commands.npc.DisplayNameCMD; -import de.oliver.fancynpcs.commands.npc.EquipmentCMD; -import de.oliver.fancynpcs.commands.npc.FixCMD; -import de.oliver.fancynpcs.commands.npc.GlowingCMD; -import de.oliver.fancynpcs.commands.npc.InfoCMD; -import de.oliver.fancynpcs.commands.npc.InteractionCooldownCMD; -import de.oliver.fancynpcs.commands.npc.ListCMD; -import de.oliver.fancynpcs.commands.npc.MessageCMD; -import de.oliver.fancynpcs.commands.npc.MoveHereCMD; -import de.oliver.fancynpcs.commands.npc.MoveToCMD; -import de.oliver.fancynpcs.commands.npc.NearbyCMD; -import de.oliver.fancynpcs.commands.npc.NpcHelpCMD; -import de.oliver.fancynpcs.commands.npc.PlayerCommandCMD; -import de.oliver.fancynpcs.commands.npc.RemoveCMD; -import de.oliver.fancynpcs.commands.npc.ShowInTabCMD; -import de.oliver.fancynpcs.commands.npc.SkinCMD; -import de.oliver.fancynpcs.commands.npc.TeleportCMD; -import de.oliver.fancynpcs.commands.npc.TurnToPlayerCMD; -import de.oliver.fancynpcs.commands.npc.TypeCMD; +import de.oliver.fancynpcs.commands.npc.*; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.AnnotationParser; import org.incendo.cloud.bukkit.CloudBukkitCapabilities; @@ -36,7 +14,6 @@ import org.incendo.cloud.exception.InvalidSyntaxException; import org.incendo.cloud.execution.ExecutionCoordinator; import org.incendo.cloud.paper.LegacyPaperCommandManager; - import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -113,6 +90,7 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig annotationParser.parse(NearbyCMD.INSTANCE); annotationParser.parse(NpcHelpCMD.INSTANCE); annotationParser.parse(PlayerCommandCMD.INSTANCE); + annotationParser.parse(ServerCommandCMD.INSTANCE); annotationParser.parse(RemoveCMD.INSTANCE); // annotationParser.parse(ServerCommandCMD.INSTANCE); annotationParser.parse(ShowInTabCMD.INSTANCE); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java index 39c9b37e..8729b355 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java @@ -8,20 +8,17 @@ import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; import java.util.UUID; import java.util.regex.Pattern; -import org.jetbrains.annotations.NotNull; - // TO-DO: Console support with --position and --world parameter flags. public enum CopyCMD { INSTANCE; // SINGLETON - private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private static final Pattern NPC_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9/_-]*$"); - + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Command(value = "npc copy ", requiredSender = Player.class) @Permission("fancynpcs.command.npc.copy") @@ -55,7 +52,7 @@ public void onCopy( npc.getData().getOnClick(), npc.getData().getMessages(), npc.getData().isSendMessagesRandomly(), - npc.getData().getServerCommand(), + npc.getData().getServerCommands(), npc.getData().getPlayerCommands(), npc.getData().getInteractionCooldown(), npc.getData().getAttributes(), diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index 860badf7..ebe764e4 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -10,18 +10,16 @@ import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.jetbrains.annotations.NotNull; import java.text.DecimalFormat; -import org.jetbrains.annotations.NotNull; - public enum InfoCMD { INSTANCE; // SINGLETON - private final Translator translator = FancyNpcs.getInstance().getTranslator(); - private static final DecimalFormat COORDS_FORMAT = new DecimalFormat("#.##"); private static final DecimalFormat SECONDS_FORMAT = new DecimalFormat("#,###.#"); + private final Translator translator = FancyNpcs.getInstance().getTranslator(); @Command("npc info ") @Permission("fancynpcs.command.npc.info") @@ -54,7 +52,7 @@ public void onInfo( .replace("interaction_cooldown", SECONDS_FORMAT.format(npc.getData().getInteractionCooldown()) + "s") .replace("messages_total", String.valueOf(npc.getData().getMessages().size())) .replace("player_commands_total", String.valueOf(npc.getData().getPlayerCommands().size())) - .replace("server_commands_total", String.valueOf(npc.getData().getServerCommand() == null ? 0 : 1)) // NOTE: PLACEHOLDER; MULTI COMMAND SUPPORT NOT IMPLEMENTED YET + .replace("server_commands_total", String.valueOf(npc.getData().getServerCommands().size())) .send(sender); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java new file mode 100644 index 00000000..ca1b1db4 --- /dev/null +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java @@ -0,0 +1,195 @@ +package de.oliver.fancynpcs.commands.npc; + +import de.oliver.fancylib.translations.Translator; +import de.oliver.fancynpcs.FancyNpcs; +import de.oliver.fancynpcs.api.Npc; +import de.oliver.fancynpcs.api.events.NpcModifyEvent; +import org.bukkit.command.CommandSender; +import org.incendo.cloud.annotation.specifier.Greedy; +import org.incendo.cloud.annotations.Argument; +import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public enum ServerCommandCMD { + INSTANCE; // SINGLETON + + private final Translator translator = FancyNpcs.getInstance().getTranslator(); + + @Command("npc server_command add ") + @Permission("fancynpcs.command.npc.server_command.add") + public void onServerCommandAdd( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @NotNull @Greedy String command + ) { + // Sending error message in case banned command has been found in the input. + if (hasBlockedCommands(command)) { + translator.translate("command_input_contains_blocked_command").send(sender); + return; + } + // Calling the event and adding server command if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SERVER_COMMAND_ADD, command, sender).callEvent()) { + npc.getData().getServerCommands().add(command); + translator.translate("npc_server_command_add_success").replace("total", String.valueOf(npc.getData().getServerCommands().size())).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + } + + @Command("npc server_command set ") + @Permission("fancynpcs.command.npc_server_command.set") + public void onServerCommandSet( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Argument(suggestions = "ServerCommandCMD/number_range") int number, + final @NotNull @Greedy String command + ) { + // Sending error message in case banned command has been found in the input. + if (hasBlockedCommands(command)) { + translator.translate("command_input_contains_blocked_command").send(sender); + return; + } + // Getting the total count of server commands that are currently in the list. + final int totalCount = npc.getData().getServerCommands().size(); + // Sending error message if the list is empty. + if (totalCount == 0) { + translator.translate("npc_server_command_set_failure_list_is_empty").send(sender); + return; + } + // Sending error message if provided number is lower than 0 or higher than the list size. + if (number < 1 || number > totalCount) { + translator.translate("npc_server_command_set_failure_not_in_range").replace("input", String.valueOf(number)).replace("max", String.valueOf(totalCount)).send(sender); + return; + } + // User-specified number starts from 1, while index starts from 0. Subtracting 1 from the provided number to get the list index. + final int index = number - 1; + // Calling the event and setting server command if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SERVER_COMMAND_SET, new Object[]{index, command}, sender).callEvent()) { + npc.getData().getServerCommands().set(index, command); + translator.translate("npc_server_command_set_success") + .replace("number", String.valueOf(number)) + .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. + .send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + } + + @Command("npc server_command remove ") + @Permission("fancynpcs.command.npc_server_command.remove") + public void onServerCommandRemove( + final @NotNull CommandSender sender, + final @NotNull Npc npc, + final @Argument(suggestions = "ServerCommandCMD/number_range") int number + ) { + // Getting the total count of server commands that are currently in the list. + final int totalCount = npc.getData().getServerCommands().size(); + // Sending error message if the list is empty. + if (totalCount == 0) { + translator.translate("npc_server_command_remove_failure_list_is_empty").send(sender); + return; + } + // Sending error message if provided number is lower than 0 or higher than the list size. + if (number < 1 || number > totalCount) { + translator.translate("npc_server_command_remove_failure_not_in_range").replace("input", String.valueOf(number)).replace("max", String.valueOf(totalCount)).send(sender); + return; + } + // User-specified number starts from 1, while index starts from 0. Subtracting 1 from the provided number to get the list index. + final int index = number - 1; + // Getting the message to pass to the NpcModifyEvent. + final String command = npc.getData().getServerCommands().get(index); + // Calling the event and removing server command if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SERVER_COMMAND_REMOVE, new Object[]{index, command}, sender).callEvent()) { + npc.getData().getServerCommands().remove(index); + // Sending success message to the sender. + translator.translate("npc_server_command_remove_success") + .replace("number", String.valueOf(number)) + .replace("total", String.valueOf(totalCount)) // Total count remains the same, no entry has been added/removed from the list. + .send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + } + + @Command("npc server_command clear") + @Permission("fancynpcs.command.npc_server_command.clear") + public void onServerCommandClear( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { + final int total = npc.getData().getServerCommands().size(); + // Calling the event and clearing server commands if not cancelled. + if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SERVER_COMMAND_CLEAR, null, sender).callEvent()) { + npc.getData().getServerCommands().clear(); + translator.translate("npc_server_command_clear_success").replace("total", String.valueOf(total)).send(sender); + } else { + translator.translate("command_npc_modification_cancelled").send(sender); + } + } + + @Command("npc server_command list") + @Permission("fancynpcs.command.npc_server_command.list") + public void onServerCommandList( + final @NotNull CommandSender sender, + final @NotNull Npc npc + ) { + // Sending error message if the list is empty. + if (npc.getData().getServerCommands().isEmpty()) { + translator.translate("npc_server_command_list_failure_empty").send(sender); + return; + } + translator.translate("npc_server_command_list_header").send(sender); + // Iterating over all server commands attached to this NPC and sending them to the sender. + for (int i = 0; i < npc.getData().getServerCommands().size(); i++) { + final String command = npc.getData().getServerCommands().get(i); + translator.translate("npc_server_command_list_entry") + .replace("number", String.valueOf(i + 1)) + .replace("command", command) + .send(sender); + } + translator.translate("npc_server_command_list_footer").send(sender); + } + + /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ + + @Suggestions("ServerCommandCMD/number_range") + // Generates number range suggestions based on the number of server commands. + public List suggestNumber(final CommandContext context, final CommandInput input) { + final Npc npc = context.getOrDefault("npc", null); + return npc == null || npc.getData().getServerCommands().isEmpty() + ? Collections.emptyList() + : new ArrayList<>() {{ + for (int i = 0; i < npc.getData().getServerCommands().size(); i++) + add(String.valueOf(i + 1)); + }}; + } + + /* UTILITY METHODS */ + + /** + * Returns {@code true} if specified string contains a blocked command, {@code false} otherwise. + */ + private boolean hasBlockedCommands(final @NotNull String string) { + // Getting the list of all blocked commands. + final List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); + // Iterating over list of blocked commands... + for (final String blockedCommand : blockedCommands) { + // Transforming the command to a base command with trailed whitespaces and slashes. This also removes namespaced part from the beginning of the command. + final String transformedBaseCommand = blockedCommand.replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", ""); + // Comparing click event value with the transformed base command. Returning the result. + if (string.replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", "").equalsIgnoreCase(transformedBaseCommand)) + return true; + } + // Returning false as no blocked commands has been found. + return false; + } + +} diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 8ab4f902..db686ad7 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -79,6 +79,10 @@ messages: npc_player_command_add: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" npc_player_command_remove: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" npc_player_command_set: "Syntax: {primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" + npc_server_command: "Syntax: {primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}(add | set | remove | clear | list)" + npc_server_command_add: "Syntax: {primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" + npc_server_command_remove: "Syntax: {primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + npc_server_command_set: "Syntax: {primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" npc_remove: "Syntax: {primaryColor}/npc remove {secondaryColor}(npc)" npc_show_in_tab: "Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" npc_skin: "Syntax: {primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" @@ -260,6 +264,19 @@ messages: npc_player_command_list_footer: "---------------------------------------------------" npc_player_command_list_failure_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." + npc_server_command_add_success: "Command has been added. There is {warningColor}{total} commands in total." + npc_server_command_set_success: "Command {warningColor}{number} has been updated. There is {warningColor}{total} commands in total." + npc_server_command_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." + npc_server_command_set_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc server_command (npc) add (command){errorColor} to add your first command." + npc_server_command_remove_success: "Command {warningColor}{number} has been removed. There is {warningColor}{total} commands in total." + npc_server_command_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." + npc_server_command_remove_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc server_command (npc) add (command){errorColor} to add your first command." + npc_server_command_clear_success: "Commands have been cleared. There was {warningColor}{total} commands in total." + npc_server_command_list_header: "----------------- Server Commands -----------------" + npc_server_command_list_entry: " <#848484>{number}. {command}" + npc_server_command_list_footer: "---------------------------------------------------" + npc_server_command_list_failure_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc server_command (npc) add (command){errorColor} to add your first command." + npc_type_success: "NPC {warningColor}{npc} type has been changed to {warningColor}{type}." From accc889f7b8726b97727aa588ee3d7eef6c7a88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 21:42:41 +0200 Subject: [PATCH 71/94] show total number of entries in list footers --- .../de/oliver/fancynpcs/commands/npc/MessageCMD.java | 6 +++++- .../fancynpcs/commands/npc/PlayerCommandCMD.java | 6 +++++- .../fancynpcs/commands/npc/ServerCommandCMD.java | 9 +++++++-- src/main/resources/languages/en.yml | 12 ++++++------ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index b00533ae..6ae923ce 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -169,7 +169,11 @@ public void onMessageList( .replace("message", message) .send(sender); } - translator.translate("npc_message_list_footer").send(sender); + final int totalCount = npc.getData().getMessages().size(); + translator.translate("npc_message_list_footer") + .replace("total", String.valueOf(totalCount)) + .replace("total_formatted", "· ".repeat(3 - String.valueOf(totalCount).length()) + totalCount) + .send(sender); } @Command("npc message send_randomly [state]") diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java index 3850e3f5..35ec2e4c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java @@ -156,7 +156,11 @@ public void onPlayerCommandList( .replace("command", command) .send(sender); } - translator.translate("npc_player_command_list_footer").send(sender); + final int totalCount = npc.getData().getPlayerCommands().size(); + translator.translate("npc_player_command_list_footer") + .replace("total", String.valueOf(totalCount)) + .replace("total_formatted", "· ".repeat(3 - String.valueOf(totalCount).length()) + totalCount) + .send(sender); } /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java index ca1b1db4..e2793686 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java @@ -12,12 +12,13 @@ import org.incendo.cloud.annotations.suggestion.Suggestions; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; -import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.jetbrains.annotations.NotNull; + public enum ServerCommandCMD { INSTANCE; // SINGLETON @@ -155,7 +156,11 @@ public void onServerCommandList( .replace("command", command) .send(sender); } - translator.translate("npc_server_command_list_footer").send(sender); + final int totalCount = npc.getData().getServerCommands().size(); + translator.translate("npc_server_command_list_footer") + .replace("total", String.valueOf(totalCount)) + .replace("total_formatted", "· ".repeat(3 - String.valueOf(totalCount).length()) + totalCount) + .send(sender); } /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index db686ad7..c6478aa0 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -246,9 +246,9 @@ messages: npc_message_clear_success: "Messages have been cleared. There was {warningColor}{total} messages in total." npc_message_send_randomly_set_true: "NPC {warningColor}{npc} is now sending messages randomly." npc_message_send_randomly_set_false: "NPC {warningColor}{npc} is no longer sending messages randomly." - npc_message_list_header: "-------------------- Messages --------------------" + npc_message_list_header: "--------------------- Messages --------------------" npc_message_list_entry: " <#848484>{number}. {message}" - npc_message_list_footer: "---------------------------------------------------" + npc_message_list_footer: "------------- Showing total of {warningColor}{total_formatted} entries -------------" npc_message_list_failure_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." npc_player_command_add_success: "Command has been added. There is {warningColor}{total} commands in total." @@ -259,9 +259,9 @@ messages: npc_player_command_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_player_command_remove_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." npc_player_command_clear_success: "Commands have been cleared. There was {warningColor}{total} commands in total." - npc_player_command_list_header: "----------------- Player Commands -----------------" + npc_player_command_list_header: "------------------ Player Commands -----------------" npc_player_command_list_entry: " <#848484>{number}. {command}" - npc_player_command_list_footer: "---------------------------------------------------" + npc_player_command_list_footer: "------------- Showing total of {warningColor}{total_formatted} entries -------------" npc_player_command_list_failure_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." npc_server_command_add_success: "Command has been added. There is {warningColor}{total} commands in total." @@ -272,9 +272,9 @@ messages: npc_server_command_remove_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." npc_server_command_remove_failure_list_is_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc server_command (npc) add (command){errorColor} to add your first command." npc_server_command_clear_success: "Commands have been cleared. There was {warningColor}{total} commands in total." - npc_server_command_list_header: "----------------- Server Commands -----------------" + npc_server_command_list_header: "------------------ Server Commands -----------------" npc_server_command_list_entry: " <#848484>{number}. {command}" - npc_server_command_list_footer: "---------------------------------------------------" + npc_server_command_list_footer: "------------- Showing total of {warningColor}{total_formatted} entries -------------" npc_server_command_list_failure_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc server_command (npc) add (command){errorColor} to add your first command." npc_type_success: "NPC {warningColor}{npc} type has been changed to {warningColor}{type}." From 2dda60a549c9bd41ca7ed32c410ef7f2a88319ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 23:13:21 +0200 Subject: [PATCH 72/94] add `--look-in-my-direction` presence flag to `/npc move_to` --- .../java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java index 18ac80fe..29d0a4ed 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MoveToCMD.java @@ -10,6 +10,7 @@ import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Flag; import org.incendo.cloud.annotations.Permission; import java.text.DecimalFormat; @@ -30,7 +31,8 @@ public void onCommand( final @NotNull CommandSender sender, final @NotNull Npc npc, final @NotNull @Argument(suggestions = "relative_location") Location location, - final @Nullable World world + final @Nullable World world, + final @Flag("look-in-my-direction") boolean shouldLookInSenderDirection ) { // Finalizing World argument. Player-like senders don't have to specify the 'world' argument which then defaults to the World sender is currently in. final World finalWorld = (world == null && sender instanceof Player player) ? player.getWorld() : world; @@ -41,6 +43,9 @@ public void onCommand( } // Updating World of the finalized Location. This should never pass a null value. location.setWorld(finalWorld); + // Updating direction NPC will be looking at. Only if '--look-in-my-direction' is present and sender is player. + if (shouldLookInSenderDirection && sender instanceof Player player) + location.setDirection(player.getLocation().subtract(location).toVector()); // Calling the event and re-locating NPC if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.LOCATION, location, sender).callEvent()) { npc.getData().setLocation(location); From 690304ae076dc6235c945b91513d6d50eb186fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 23:39:05 +0200 Subject: [PATCH 73/94] sort locale, add comments, add `FancyNpcsPlugin#getTranslator`, replace usage of `LanguageConfig` with `Translator` --- .../oliver/fancynpcs/api/FancyNpcsPlugin.java | 3 + .../java/de/oliver/fancynpcs/api/Npc.java | 8 +- .../java/de/oliver/fancynpcs/FancyNpcs.java | 1 + src/main/resources/languages/en.yml | 97 ++++++++++++------- 4 files changed, 71 insertions(+), 38 deletions(-) diff --git a/api/src/main/java/de/oliver/fancynpcs/api/FancyNpcsPlugin.java b/api/src/main/java/de/oliver/fancynpcs/api/FancyNpcsPlugin.java index 82faf21c..d9b5ec06 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/FancyNpcsPlugin.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/FancyNpcsPlugin.java @@ -2,6 +2,7 @@ import de.oliver.fancylib.LanguageConfig; import de.oliver.fancylib.serverSoftware.schedulers.FancyScheduler; +import de.oliver.fancylib.translations.Translator; import org.bukkit.Bukkit; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; @@ -33,4 +34,6 @@ static FancyNpcsPlugin get() { AttributeManager getAttributeManager(); LanguageConfig getLanguageConfig(); + + Translator getTranslator(); } diff --git a/api/src/main/java/de/oliver/fancynpcs/api/Npc.java b/api/src/main/java/de/oliver/fancynpcs/api/Npc.java index d07848bd..82967484 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/Npc.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/Npc.java @@ -2,9 +2,8 @@ import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; -import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; import de.oliver.fancylib.RandomUtils; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.api.events.NpcInteractEvent; import de.oliver.fancynpcs.api.events.NpcInteractEvent.InteractionType; import me.dave.chatcolorhandler.ChatColorHandler; @@ -32,7 +31,7 @@ public abstract class Npc { protected final Map isVisibleForPlayer = new ConcurrentHashMap<>(); protected final Map isLookingAtPlayer = new ConcurrentHashMap<>(); protected final Map lastPlayerInteraction = new ConcurrentHashMap<>(); - private final LanguageConfig lang = FancyNpcsPlugin.get().getLanguageConfig(); + private final Translator translator = FancyNpcsPlugin.get().getTranslator(); protected NpcData data; protected boolean saveToFile; @@ -155,8 +154,7 @@ public void interact(Player player, InteractionType interactionType) { if (nextAllowedInteraction > System.currentTimeMillis()) { if (!FancyNpcsPlugin.get().getFancyNpcConfig().isInteractionCooldownMessageDisabled()) { float timeLeft = (nextAllowedInteraction - System.currentTimeMillis()) / 1000F; - String cooldownMessage = lang.get("on-interaction-cooldown", "time", DECIMAL_FORMAT.format(timeLeft)); - MessageHelper.warning(player, cooldownMessage); + translator.translate("interaction_on_cooldown").replace("time", DECIMAL_FORMAT.format(timeLeft)).send(player); } return; } diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index 02833d77..b87a1e7c 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -275,6 +275,7 @@ public CloudCommandManager getCommandManager() { return commandManager; } + @Override public Translator getTranslator() { return translator; } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index c6478aa0..033da967 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -7,6 +7,7 @@ messages: enabled: "{successColor}Enabled" false: "{errorColor}False" disabled: "{errorColor}Disabled" + # Common (Equipment Slots) main_hand: "Main Hand" off_hand: "Off Hand" @@ -14,6 +15,7 @@ messages: chest: "Chest" legs: "Legs" feet: "Feet" + # Common (Colors) color_black: "Black" color_dark_blue: "Dark Blue" @@ -31,8 +33,10 @@ messages: color_light_purple: "Light Purple" color_yellow: "Yellow" color_white: "White" + # Common (Other) - interaction_on_cooldown: "" + interaction_on_cooldown: "› {errorColor}You're currently on cooldown. {time} seconds remaining." + # Commands (Common Replies) command_missing_permissions: "› {errorColor}Insufficient permissions. You cannot use this command." command_wrong_usage: "› {errorColor}This sub-command does not exist. Use {warningColor}/npc help{errorColor} to view available commands." @@ -50,8 +54,10 @@ messages: command_unsupported_npc_type: "› This NPC type does not support this feature." command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." + # Generic Syntax Message (syntax is provided by Cloud and may not be human-friendly) command_invalid_syntax_generic: "Syntax: {warningColor}/{syntax}" + # Command Syntaxes command_syntax: fancynpcs: "Syntax: {primaryColor}/fancynpcs {secondaryColor}(version | reload | save | feature_flags)" @@ -89,13 +95,16 @@ messages: npc_teleport: "Syntax: {primaryColor}/npc teleport {secondaryColor}(npc)" npc_turn_to_player: "Syntax: {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" npc_type: "Syntax: {primaryColor}/npc type {secondaryColor}(npc) (type)" - # Commands + + # Commands (fancynpcs) fancynpcs_reload_success: "› {successColor}Plugin has been reloaded." fancynpcs_save_success: "› {successColor}NPCs have been saved." fancynpcs_version: "" # NOT CONFIGURABLE fancynpcs_feature_flags_header: "Feature Flags:" fancynpcs_feature_flags_entry: "› <#848484>{number}. {warningColor}{name} <#848484>({id}): {state}" fancynpcs_feature_flags_footer: "" + + # Commands (npc help) npc_help_page_header: "------------- {primaryColor}FancyNpcs Commands ({primaryColor}{page}/{primaryColor}{max_page}) --------------" npc_help_page_footer: "----------- Click {primaryColor}here to open documentation -----------" npc_help_contents: @@ -136,8 +145,8 @@ messages: - "› {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}list - Lists attributes." - "› {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}clear - Clears attributes." - "› {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." - - # FIX COLORS + - + # Commands (npc attribute) npc_attribute_set: "Attribute {warningColor}{attribute} has been set to {warningColor}{value}." npc_attribute_set_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." npc_attribute_list_header: "-------------------- Attributes --------------------" @@ -145,19 +154,24 @@ messages: npc_attribute_list_footer: "---------------------------------------------------" npc_attribute_list_failure_empty: "› {errorColor}There is no attributes set. Use {warningColor}/npc attribute (npc) set (attribute) (value){errorColor} to set an attribute." + # Commands (npc collidable) npc_collidable_set_true: "NPC {warningColor}{npc} is now collidable." npc_collidable_set_false: "NPC {warningColor}{npc} is no longer collidable." + # Commands (npc copy) npc_copy_success: "NPC {warningColor}{npc} has been copied to {warningColor}{new_npc}." + # Commands (npc create) npc_create_success: "NPC {warningColor}{npc} has been created." npc_create_failure_invalid_name: "› {errorColor}Name contains illegal characters. Only [{warningColor}A-Z{errorColor}, {warningColor}a-z{errorColor}, {warningColor}0-9{errorColor}, {warningColor}_{errorColor}, {warningColor}-{errorColor}, {warningColor}/{errorColor}] characters are allowed." npc_create_failure_already_exists: "› {errorColor}NPC {warningColor}{npc}{errorColor} already exists." npc_create_failure_must_specify_world: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." + # Commands (npc displayname) npc_displayname_set_name: "NPC {warningColor}{npc} is now using {name} as their display name." npc_displayname_set_empty: "NPC {warningColor}{npc} is no longer showing display name." + # Commands (npc equipment) npc_equipment_set_item: "Equipment slot {warningColor}{slot} has been set to ." npc_equipment_set_empty: "Equipment slot {warningColor}{slot} has been removed." npc_equipment_set_failure_invalid_slot: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid equipment slot." @@ -167,13 +181,16 @@ messages: npc_equipment_list_footer: "---------------------------------------------------" npc_equipment_list_failure_empty: "› {errorColor}There is no equipment slots set. Use {warningColor}/npc equipment (npc) set (slot) (@hand | @none | material){errorColor} to set an equipment slot." + # Commands (npc fix) npc_fix_success: "Attempted to fix NPC {warningColor}{npc}... Still having issues? Please let us know." + # Commands (npc glowing) npc_glowing_set_true: "NPC {warningColor}{npc} is now glowing." npc_glowing_set_false: "NPC {warningColor}{npc} is no longer glowing." npc_glowing_set_color_success: "NPC {warningColor}{npc} is now glowing in {color}." npc_glowing_set_color_failure_invalid_color: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid color." + # Commands (npc info) npc_info_general: - "" - "Unique, permanent identifier of the NPC.'><#848484>Identifier: Click to copy identifier to clipboard.'>{warningColor}{id_short}" @@ -199,43 +216,17 @@ messages: - "Open the chat window to see all information." - "" + # Commands (npc interaction_cooldown) npc_interaction_cooldown_success: "NPC {warningColor}{npc} has had their interaction cooldown updated." - npc_skin_set_name: "NPC {warningColor}{npc} is now using {warningColor}{name}'s skin." - npc_skin_set_url: "NPC {warningColor}{npc} is now using skin from specified URL." - npc_skin_set_mirror: "NPC {warningColor}{npc} is now mirroring player skin." - npc_skin_set_none: "NPC {warningColor}{npc} is no longer using any skin." - npc_skin_failure_invalid_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is invalid or unsupported URL." - npc_skin_failure_invalid_name_or_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid player name or URL." - npc_skin_failure_invalid_name_or_rate_limit: "› {errorColor}Could not find {warningColor}{input}'s{errorColor} skin. Either the account does not exist or you're being rate limited." - - npc_move_here_success: "NPC {warningColor}{npc} has been moved to your location." - - npc_remove_success: "NPC {warningColor}{npc} has been removed." - + # Commands (npc list) npc_list_header: "------------------ List Query Result ------------------" npc_list_entry: " <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({location_x}, {location_y}, {location_z} in {world})" npc_list_footer: "---------- Showing {warningColor}{count_formatted} out of total {warningColor}{total_formatted} entries ----------" npc_list_failure_sort_requires_player: "› {errorColor}This sort type cannot be used from the console." npc_list_failure_requires_world_flag: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." - npc_nearby_header: "---------------- Nearby Query Result -----------------" - npc_nearby_entry: " <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({distance} blocks away)" - npc_nearby_footer: "---------- Showing {warningColor}{count_formatted} out of total {warningColor}{total_formatted} entries ----------" - - npc_move_to_success: "NPC {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." - npc_move_to_failure_must_specify_world: "› {errorColor}You must specify world when running this command from the console." - - npc_teleport_success: "You have been teleported to NPC {warningColor}{npc}." - npc_teleport_failure_exception: "› {errorColor}An error occurred while trying to teleport to NPC. Check console for errors." - npc_teleport_failure_world_not_loaded: "› {errorColor}An error occurred while trying to teleport to NPC. Destination world is not loaded." - - npc_turn_to_player_set_true: "NPC {warningColor}{npc} is now turning to player." - npc_turn_to_player_set_false: "NPC {warningColor}{npc} is no longer turning to player." - - npc_show_in_tab_set_true: "NPC {warningColor}{npc} is now shown in player-list." - npc_show_in_tab_set_false: "NPC {warningColor}{npc} is no longer shown in player-list." - + # Commands (npc message) npc_message_add_success: "Message has been added. There is {warningColor}{total} messages in total." npc_message_set_success: "Message {warningColor}{number} has been updated. There is {warningColor}{total} messages in total." npc_message_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." @@ -251,6 +242,19 @@ messages: npc_message_list_footer: "------------- Showing total of {warningColor}{total_formatted} entries -------------" npc_message_list_failure_empty: "› {errorColor}There are no messages in the list. Use {warningColor}/npc message (npc) add (none | message){errorColor} to add your first message." + # Commands (npc move_here) + npc_move_here_success: "NPC {warningColor}{npc} has been moved to your location." + + # Commands (npc move_to) + npc_move_to_success: "NPC {warningColor}{npc} has been moved to {warningColor}{x}, {warningColor}{y}, {warningColor}{z} in {warningColor}{world}." + npc_move_to_failure_must_specify_world: "› {errorColor}You must specify world when running this command from the console." + + # Commands (npc nearby) + npc_nearby_header: "---------------- Nearby Query Result -----------------" + npc_nearby_entry: " <#848484>{number}. Click to see more details.'>{warningColor}{npc} Click to teleport.'><#848484>({distance} blocks away)" + npc_nearby_footer: "---------- Showing {warningColor}{count_formatted} out of total {warningColor}{total_formatted} entries ----------" + + # Commands (npc player_command) npc_player_command_add_success: "Command has been added. There is {warningColor}{total} commands in total." npc_player_command_set_success: "Command {warningColor}{number} has been updated. There is {warningColor}{total} commands in total." npc_player_command_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." @@ -264,6 +268,10 @@ messages: npc_player_command_list_footer: "------------- Showing total of {warningColor}{total_formatted} entries -------------" npc_player_command_list_failure_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc player_command (npc) add (command){errorColor} to add your first command." + # Commands (npc remove) + npc_remove_success: "NPC {warningColor}{npc} has been removed." + + # Commands (npc server_command) npc_server_command_add_success: "Command has been added. There is {warningColor}{total} commands in total." npc_server_command_set_success: "Command {warningColor}{number} has been updated. There is {warningColor}{total} commands in total." npc_server_command_set_failure_not_in_range: "› {errorColor}Number {warningColor}{input}{errorColor} must be in range between {warningColor}1{errorColor} and {warningColor}{max}{errorColor}." @@ -277,6 +285,29 @@ messages: npc_server_command_list_footer: "------------- Showing total of {warningColor}{total_formatted} entries -------------" npc_server_command_list_failure_empty: "› {errorColor}There are no commands in the list. Use {warningColor}/npc server_command (npc) add (command){errorColor} to add your first command." + # Commands (npc show_in_tab) + npc_show_in_tab_set_true: "NPC {warningColor}{npc} is now shown in player-list." + npc_show_in_tab_set_false: "NPC {warningColor}{npc} is no longer shown in player-list." + + # Commands (npc skin) + npc_skin_set_name: "NPC {warningColor}{npc} is now using {warningColor}{name}'s skin." + npc_skin_set_url: "NPC {warningColor}{npc} is now using skin from specified URL." + npc_skin_set_mirror: "NPC {warningColor}{npc} is now mirroring player skin." + npc_skin_set_none: "NPC {warningColor}{npc} is no longer using any skin." + npc_skin_failure_invalid_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is invalid or unsupported URL." + npc_skin_failure_invalid_name_or_url: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid player name or URL." + npc_skin_failure_invalid_name_or_rate_limit: "› {errorColor}Could not find {warningColor}{input}'s{errorColor} skin. Either the account does not exist or you're being rate limited." + + # Commands (npc teleport) + npc_teleport_success: "You have been teleported to NPC {warningColor}{npc}." + npc_teleport_failure_exception: "› {errorColor}An error occurred while trying to teleport to NPC. Check console for errors." + npc_teleport_failure_world_not_loaded: "› {errorColor}An error occurred while trying to teleport to NPC. Destination world is not loaded." + + # Commands (npc turn_to_player) + npc_turn_to_player_set_true: "NPC {warningColor}{npc} is now turning to player." + npc_turn_to_player_set_false: "NPC {warningColor}{npc} is no longer turning to player." + + # Commands (npc type) npc_type_success: "NPC {warningColor}{npc} type has been changed to {warningColor}{type}." From 67b09ea1c68b60b8c03f6147e99a94c831ecc6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Wed, 15 May 2024 23:58:10 +0200 Subject: [PATCH 74/94] configurable language --- .../java/de/oliver/fancynpcs/FancyNpcs.java | 14 +++++++++++--- .../oliver/fancynpcs/FancyNpcsConfigImpl.java | 13 +++++++++++++ .../oliver/fancynpcs/commands/FancyNpcsCMD.java | 17 ++++++++--------- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index b87a1e7c..8ac99b42 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -12,6 +12,7 @@ import de.oliver.fancylib.serverSoftware.schedulers.BukkitScheduler; import de.oliver.fancylib.serverSoftware.schedulers.FancyScheduler; import de.oliver.fancylib.serverSoftware.schedulers.FoliaScheduler; +import de.oliver.fancylib.translations.Language; import de.oliver.fancylib.translations.TextConfig; import de.oliver.fancylib.translations.Translator; import de.oliver.fancylib.versionFetcher.MasterVersionFetcher; @@ -153,7 +154,10 @@ public void onEnable() { textConfig = new TextConfig("#E33239", "#AD1D23", "#81E366", "#E3CA66", "#E36666", ""); translator = new Translator(textConfig); translator.loadLanguages(getDataFolder().getAbsolutePath()); - translator.setSelectedLanguage(translator.getFallbackLanguage()); // WIP: Make it configurable. + final Language selectedLanguage = translator.getLanguages().stream() + .filter(language -> language.getLanguageName().equals(config.getLanguage())) + .findFirst().orElse(translator.getFallbackLanguage()); + translator.setSelectedLanguage(selectedLanguage); versionConfig.load(); @@ -222,8 +226,12 @@ public void onEnable() { if (config.isEnableAutoSave() && config.getAutoSaveInterval() > 0) { scheduler.runTaskTimerAsynchronously(60L * 20L, autosaveInterval * 60L * 20L, () -> npcManager.saveNpcs(false)); } - // Creating new instance of CloudCommandManager and registering commands. - commandManager = new CloudCommandManager(this, false).registerCommands(); + // Creating new instance of CloudCommandManager and registering all needed components. + // NOTE: Brigadier is disabled by default. More detailed information about that can be found in CloudCommandManager class. + commandManager = new CloudCommandManager(this, false) + .registerArguments() + .registerExceptionHandlers() + .registerCommands(); } @Override diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcsConfigImpl.java b/src/main/java/de/oliver/fancynpcs/FancyNpcsConfigImpl.java index 9d5baaf3..7b71b022 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcsConfigImpl.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcsConfigImpl.java @@ -8,6 +8,12 @@ import java.util.stream.Collectors; public class FancyNpcsConfigImpl implements FancyNpcsConfig { + + /** + * Currently active/selected language. + */ + private String language; + /** * Indicates whether interaction cooldown messages are disabled. */ @@ -59,6 +65,9 @@ public void reload() { FancyNpcs.getInstance().reloadConfig(); FileConfiguration config = FancyNpcs.getInstance().getConfig(); + language = (String) ConfigHelper.getOrDefault(config, "language", "english"); + config.setInlineComments("language", List.of("Language to use for translatable messages.")); + disabledInteractionCooldownMessage = (boolean) ConfigHelper.getOrDefault(config, "disable_interaction_cooldown_message", false); config.setInlineComments("disable_interaction_cooldown_message", List.of("Whether interaction cooldown messages are disabled.")); @@ -102,6 +111,10 @@ public void reload() { FancyNpcs.getInstance().saveConfig(); } + public String getLanguage() { + return language; + } + public boolean isInteractionCooldownMessageDisabled() { return disabledInteractionCooldownMessage; } diff --git a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java index 8ced1247..93d6d09e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java @@ -1,5 +1,6 @@ package de.oliver.fancynpcs.commands; +import de.oliver.fancylib.translations.Language; import de.oliver.fancylib.translations.Translator; import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; @@ -15,12 +16,6 @@ public enum FancyNpcsCMD { private final FancyNpcs plugin = FancyNpcs.getInstance(); private final Translator translator = FancyNpcs.getInstance().getTranslator(); - @Command("fancynpcs") - @Permission("fancynpcs.command.fancynpcs") - public void onDefault(final CommandSender sender) { - translator.translate("fancynpcs_syntax").send(sender); - } - @Command("fancynpcs version") @Permission("fancynpcs.command.fancynpcs.version") public void onVersion(final CommandSender sender) { @@ -32,11 +27,15 @@ public void onVersion(final CommandSender sender) { public void onReload(final CommandSender sender) { // Reloading all defined languages. translator.loadLanguages(plugin.getDataFolder().getAbsolutePath()); - // Reloading configuration + // Reloading plugin configuration. plugin.getFancyNpcConfig().reload(); - // Updating the selected language obtained from configuration. - translator.setSelectedLanguage(translator.getFallbackLanguage()); // WIP: Make it configurable. + // Getting the selected language from configuration. Defaults to fallback language. + final Language selectedLanguage = translator.getLanguages().stream() + .filter(language -> language.getLanguageName().equals(plugin.getFancyNpcConfig().getLanguage())) + .findFirst().orElse(translator.getFallbackLanguage()); + translator.setSelectedLanguage(selectedLanguage); // Reloading all NPCs. + // NOTE: This sometimes creates duplicated NPCs on the client-side. plugin.getNpcManagerImpl().reloadNpcs(); // Sending success message to the sender. translator.translate("fancynpcs_reload_success").send(sender); From aaad75c3038946d9cc7deba2aa14be0195a2b3b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Thu, 16 May 2024 11:29:28 +0200 Subject: [PATCH 75/94] suggest command names for `player_command` and `server_command` sub-commands --- .../fancynpcs/commands/npc/PlayerCommandCMD.java | 14 ++++++++++++-- .../fancynpcs/commands/npc/ServerCommandCMD.java | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java index 35ec2e4c..27233ce6 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java @@ -4,6 +4,7 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotation.specifier.Greedy; import org.incendo.cloud.annotations.Argument; @@ -14,6 +15,7 @@ import org.incendo.cloud.context.CommandInput; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -29,7 +31,7 @@ public enum PlayerCommandCMD { public void onPlayerCommandAdd( final @NotNull CommandSender sender, final @NotNull Npc npc, - final @NotNull @Greedy String command + final @NotNull @Argument(suggestions = "PlayerCommandCMD/commands") @Greedy String command ) { // Sending error message in case banned command has been found in the input. if (hasBlockedCommands(command)) { @@ -51,7 +53,7 @@ public void onPlayerCommandSet( final @NotNull CommandSender sender, final @NotNull Npc npc, final @Argument(suggestions = "PlayerCommandCMD/number_range") int number, - final @NotNull @Greedy String command + final @NotNull @Argument(suggestions = "PlayerCommandCMD/commands") @Greedy String command ) { // Sending error message in case banned command has been found in the input. if (hasBlockedCommands(command)) { @@ -176,6 +178,14 @@ public List suggestNumber(final CommandContext context, f }}; } + @Suggestions("PlayerCommandCMD/commands") // Suggests allowed (non-blocked) commands accessible by the command sender. + public Collection suggestCommand(final CommandContext context, final CommandInput input) { + return Bukkit.getServer().getCommandMap().getKnownCommands().values().stream() + .filter(command -> !command.getName().contains(":") && command.testPermission(context.sender()) && !hasBlockedCommands(command.getName())) + .map(org.bukkit.command.Command::getName) + .toList(); + } + /* UTILITY METHODS */ /** Returns {@code true} if specified string contains a blocked command, {@code false} otherwise. */ diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java index e2793686..37035d5c 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java @@ -4,6 +4,7 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotation.specifier.Greedy; import org.incendo.cloud.annotations.Argument; @@ -14,6 +15,7 @@ import org.incendo.cloud.context.CommandInput; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -29,7 +31,7 @@ public enum ServerCommandCMD { public void onServerCommandAdd( final @NotNull CommandSender sender, final @NotNull Npc npc, - final @NotNull @Greedy String command + final @NotNull @Argument(suggestions = "ServerCommandCMD/commands") @Greedy String command ) { // Sending error message in case banned command has been found in the input. if (hasBlockedCommands(command)) { @@ -51,7 +53,7 @@ public void onServerCommandSet( final @NotNull CommandSender sender, final @NotNull Npc npc, final @Argument(suggestions = "ServerCommandCMD/number_range") int number, - final @NotNull @Greedy String command + final @NotNull @Argument(suggestions = "ServerCommandCMD/commands") @Greedy String command ) { // Sending error message in case banned command has been found in the input. if (hasBlockedCommands(command)) { @@ -177,6 +179,14 @@ public List suggestNumber(final CommandContext context, f }}; } + @Suggestions("ServerCommandCMD/commands") // Suggests allowed (non-blocked) commands accessible by the command sender. + public Collection suggestCommand(final CommandContext context, final CommandInput input) { + return Bukkit.getServer().getCommandMap().getKnownCommands().values().stream() + .filter(command -> !command.getName().contains(":") && command.testPermission(context.sender()) && !hasBlockedCommands(command.getName())) + .map(org.bukkit.command.Command::getName) + .toList(); + } + /* UTILITY METHODS */ /** From de9c10e4235689bb65195654bb1666bce341a0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 00:31:06 +0200 Subject: [PATCH 76/94] improve `interaction_cooldown` sub-command --- .../java/de/oliver/fancynpcs/api/Npc.java | 20 +- .../oliver/fancynpcs/api/util/Interval.java | 217 ++++++++++++++++++ .../commands/CloudCommandManager.java | 25 +- .../commands/npc/InteractionCooldownCMD.java | 74 +++++- src/main/resources/languages/en.yml | 40 +--- 5 files changed, 326 insertions(+), 50 deletions(-) create mode 100644 api/src/main/java/de/oliver/fancynpcs/api/util/Interval.java diff --git a/api/src/main/java/de/oliver/fancynpcs/api/Npc.java b/api/src/main/java/de/oliver/fancynpcs/api/Npc.java index 82967484..1ab20eb0 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/Npc.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/Npc.java @@ -6,6 +6,8 @@ import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.api.events.NpcInteractEvent; import de.oliver.fancynpcs.api.events.NpcInteractEvent.InteractionType; +import de.oliver.fancynpcs.api.util.Interval; +import de.oliver.fancynpcs.api.util.Interval.Unit; import me.dave.chatcolorhandler.ChatColorHandler; import me.dave.chatcolorhandler.ModernChatColorHandler; import me.dave.chatcolorhandler.parsers.custom.PlaceholderAPIParser; @@ -15,7 +17,6 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import java.text.DecimalFormat; import java.util.List; import java.util.Map; import java.util.Random; @@ -25,7 +26,6 @@ public abstract class Npc { private static final NpcAttribute INVISIBLE_ATTRIBUTE = FancyNpcsPlugin.get().getAttributeManager().getAttributeByName(EntityType.PLAYER, "invisible"); - private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("##.##"); private static final char[] localNameChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'k', 'l', 'm', 'n', 'o', 'r'}; protected final Map isTeamCreated = new ConcurrentHashMap<>(); protected final Map isVisibleForPlayer = new ConcurrentHashMap<>(); @@ -149,17 +149,13 @@ public void interact(Player player) { public void interact(Player player, InteractionType interactionType) { if (data.getInteractionCooldown() > 0) { - if (lastPlayerInteraction.containsKey(player.getUniqueId())) { - long nextAllowedInteraction = lastPlayerInteraction.get(player.getUniqueId()) + Math.round(data.getInteractionCooldown() * 1000L); - if (nextAllowedInteraction > System.currentTimeMillis()) { - if (!FancyNpcsPlugin.get().getFancyNpcConfig().isInteractionCooldownMessageDisabled()) { - float timeLeft = (nextAllowedInteraction - System.currentTimeMillis()) / 1000F; - translator.translate("interaction_on_cooldown").replace("time", DECIMAL_FORMAT.format(timeLeft)).send(player); - } - return; - } + final long interactionCooldownMillis = (long) (data.getInteractionCooldown() * 1000); + final long lastInteractionMillis = lastPlayerInteraction.getOrDefault(player.getUniqueId(), 0L); + final Interval interactionCooldownLeft = Interval.between(lastInteractionMillis + interactionCooldownMillis, System.currentTimeMillis(), Unit.MILLISECONDS); + if (interactionCooldownLeft.as(Unit.MILLISECONDS) > 0 && !FancyNpcsPlugin.get().getFancyNpcConfig().isInteractionCooldownMessageDisabled()) { + translator.translate("interaction_on_cooldown").replace("time", interactionCooldownLeft.toString()).send(player); + return; } - lastPlayerInteraction.put(player.getUniqueId(), System.currentTimeMillis()); } diff --git a/api/src/main/java/de/oliver/fancynpcs/api/util/Interval.java b/api/src/main/java/de/oliver/fancynpcs/api/util/Interval.java new file mode 100644 index 00000000..0a82a5d0 --- /dev/null +++ b/api/src/main/java/de/oliver/fancynpcs/api/util/Interval.java @@ -0,0 +1,217 @@ +/* + * MIT License + * + * Copyright (c) 2023 Grabsky <44530932+Grabsky@users.noreply.github.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * HORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package de.oliver.fancynpcs.api.util; + +import java.time.Instant; +import java.util.Date; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static de.oliver.fancynpcs.api.util.Interval.Unit.DAYS; +import static de.oliver.fancynpcs.api.util.Interval.Unit.HOURS; +import static de.oliver.fancynpcs.api.util.Interval.Unit.MILLISECONDS; +import static de.oliver.fancynpcs.api.util.Interval.Unit.MINUTES; +import static de.oliver.fancynpcs.api.util.Interval.Unit.MONTHS; +import static de.oliver.fancynpcs.api.util.Interval.Unit.SECONDS; +import static de.oliver.fancynpcs.api.util.Interval.Unit.YEARS; + +/** + * {@link Interval} is simple (but not very extensible) object that provides methods for + * unit conversion and creation of human-readable 'elapsed time' strings. + */ +@ApiStatus.Internal +public final class Interval { + + private final long value; + + public Interval(final long value) { + this.value = value; + } + + /** + * Returns {@link Interval} object of current time. + */ + public static @NotNull Interval now() { + return new Interval(System.currentTimeMillis()); + } + + /** + * Returns {@link Interval} object constructed from provided {@link Long long} {@code (interval)}. + * It is expected that provided value is already a difference between two timestamps. + */ + public static @NotNull Interval of(final long interval, final @NotNull Unit unit) { + return new Interval(interval * unit.factor); + } + + /** + * Returns {@link Interval} object constructed from provided {@link Double double} {@code (interval)}. + * It is expected that provided value is already a difference between two timestamps. + */ + public static @NotNull Interval of(final double interval, final @NotNull Unit unit) { + return new Interval(Math.round(interval * unit.factor)); + } + + /** + * Returns {@link Interval} of time between {@code n} and {@code m}. + */ + public static @NotNull Interval between(final long n, final long m, final @NotNull Unit unit) { + return new Interval((n - m) * unit.factor); + } + + /** + * Returns {@link Interval} of time between {@code n} and {@code m}. + */ + public static @NotNull Interval between(final double n, final double m, final @NotNull Unit unit) { + return new Interval(Math.round((n - m) * unit.factor)); + } + + /** + * Returns interval converted to specified {@link Unit} {@code (unit)}.
+ *
+     * Interval.of(1500, Interval.Unit.MILLISECONDS).as(Interval.Unit.SECONDS) // 1.5F
+     * Interval.of(300, Interval.Unit.SECONDS).as(Interval.Unit.MINUTES) // 5F
+     * 
+ */ + public double as(final @NotNull Unit unit) { + return (double) (value / unit.factor); + } + + /** + * Returns a copy of (this) {@link Interval} with {@code n} of {@link Unit} added. + */ + public @NotNull Interval add(final @NotNull Interval other) { + return new Interval(this.value + other.value); + } + + /** + * Returns a copy of (this) {@link Interval} with {@code n} of {@link Unit} added. + */ + public @NotNull Interval add(final long n, final @NotNull Unit unit) { + return new Interval(this.value + (n * unit.factor)); + } + + /** + * Returns a copy of (this) {@link Interval} with {@code n} of {@link Unit} removed. + */ + public @NotNull Interval remove(final @NotNull Interval other) { + return new Interval(this.value - other.value); + } + + /** + * Returns a copy of (this) {@link Interval} with {@code n} of {@link Unit} removed. + */ + public @NotNull Interval remove(final long n, final @NotNull Unit unit) { + return new Interval(this.value - (n * unit.factor)); + } + + /** + * Returns new {@link Date} created from (this) {@link Interval}. + */ + public @NotNull Date toDate() { + return new Date(this.value); + } + + /** + * Returns new {@link Instant} created from (this) {@link Interval}. + */ + public @NotNull Instant toInstant() { + return Instant.ofEpochMilli(this.value); + } + + /** + * Returns formatted {@link String} expressing this {@link Interval}. + *
+     * final Interval i = Interval.between(lastJoinedMillis, currentTimeMillis, Interval.Unit.MILLISECONDS);
+     * System.out.println(i.toString()) + " ago"; // eg. '1d 7h 32min 10s ago'
+     * 
+ */ + @Override + public @NotNull String toString() { + // Returning milliseconds for values below 1000. (less than one second) + if (value < 1000) + return value % YEARS.getFactor() % MONTHS.getFactor() % DAYS.getFactor() % HOURS.getFactor() % MINUTES.getFactor() % SECONDS.getFactor() / MILLISECONDS.getFactor() + "ms";; + // Calculation values, the ugly way. + final long years = value / YEARS.getFactor(); + final long months = value % YEARS.getFactor() / MONTHS.getFactor(); + final long days = value % YEARS.getFactor() % MONTHS.getFactor() / DAYS.getFactor(); + final long hours = value % YEARS.getFactor() % MONTHS.getFactor() % DAYS.getFactor() / HOURS.getFactor(); + final long minutes = value % YEARS.getFactor() % MONTHS.getFactor() % DAYS.getFactor() % HOURS.getFactor() / MINUTES.getFactor(); + final long seconds = value % YEARS.getFactor() % MONTHS.getFactor() % DAYS.getFactor() % HOURS.getFactor() % MINUTES.getFactor() / SECONDS.getFactor(); + // Creating a new output StringBuilder object. + final StringBuilder builder = new StringBuilder(); + // Appending to the StringBuilder. + if (years > 0L) builder.append(years).append("y "); + if (months > 0L) builder.append(months).append("m "); + if (days > 0L) builder.append(days).append("d "); + if (hours > 0L) builder.append(hours).append("h "); + if (minutes > 0L) builder.append(minutes).append("min "); + if (seconds > 0L) builder.append(seconds).append("s"); + // Removing last character if a whitespace. + if (builder.charAt(builder.length() - 1) == ' ') + builder.deleteCharAt(builder.length() - 1); + // Building a String and returning. + return builder.toString(); + } + + public enum Unit { + MILLISECONDS(1L, "ms"), + TICKS(50L, "t"), + SECONDS(1_000L, "s"), + MINUTES(60_000L, "min"), + HOURS(3_600_000L, "h"), + DAYS(86_400_000L, "d"), + MONTHS(2_629_800_000L, "mo"), + YEARS(31_557_600_000L, "y"); + + private final long factor; + private final String shortCode; + + Unit(final long factor, final @NotNull String shortCode) { + this.factor = factor; + this.shortCode = shortCode; + } + + public long getFactor() { + return factor; + } + + public @NotNull String getShortCode() { + return shortCode; + } + + /** Returns {@link Unit} or {@code null} from provided short code. */ + public static @Nullable Unit fromShortCode(final @NotNull String shortCode) { + // Iterating over all units and finding one that matches provided short code. + for (final Unit unit : Unit.values()) + if (unit.shortCode.equalsIgnoreCase(shortCode) == true) + return unit; + // Unit has not been found. Returning null. + return null; + } + + } + +} \ No newline at end of file diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 4775c5f4..3c5b2cfd 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -6,6 +6,30 @@ import de.oliver.fancynpcs.commands.arguments.NpcArgument; import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; import de.oliver.fancynpcs.commands.npc.*; +import de.oliver.fancynpcs.commands.npc.AttributeCMD; +import de.oliver.fancynpcs.commands.npc.CollidableCMD; +import de.oliver.fancynpcs.commands.npc.CopyCMD; +import de.oliver.fancynpcs.commands.npc.CreateCMD; +import de.oliver.fancynpcs.commands.npc.DisplayNameCMD; +import de.oliver.fancynpcs.commands.npc.EquipmentCMD; +import de.oliver.fancynpcs.commands.npc.FixCMD; +import de.oliver.fancynpcs.commands.npc.GlowingCMD; +import de.oliver.fancynpcs.commands.npc.InfoCMD; +import de.oliver.fancynpcs.commands.npc.InteractionCooldownCMD; +import de.oliver.fancynpcs.commands.npc.ListCMD; +import de.oliver.fancynpcs.commands.npc.MessageCMD; +import de.oliver.fancynpcs.commands.npc.MoveHereCMD; +import de.oliver.fancynpcs.commands.npc.MoveToCMD; +import de.oliver.fancynpcs.commands.npc.NearbyCMD; +import de.oliver.fancynpcs.commands.npc.NpcHelpCMD; +import de.oliver.fancynpcs.commands.npc.PlayerCommandCMD; +import de.oliver.fancynpcs.commands.npc.RemoveCMD; +import de.oliver.fancynpcs.commands.npc.ServerCommandCMD; +import de.oliver.fancynpcs.commands.npc.ShowInTabCMD; +import de.oliver.fancynpcs.commands.npc.SkinCMD; +import de.oliver.fancynpcs.commands.npc.TeleportCMD; +import de.oliver.fancynpcs.commands.npc.TurnToPlayerCMD; +import de.oliver.fancynpcs.commands.npc.TypeCMD; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.AnnotationParser; import org.incendo.cloud.bukkit.CloudBukkitCapabilities; @@ -92,7 +116,6 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig annotationParser.parse(PlayerCommandCMD.INSTANCE); annotationParser.parse(ServerCommandCMD.INSTANCE); annotationParser.parse(RemoveCMD.INSTANCE); - // annotationParser.parse(ServerCommandCMD.INSTANCE); annotationParser.parse(ShowInTabCMD.INSTANCE); annotationParser.parse(SkinCMD.INSTANCE); annotationParser.parse(TeleportCMD.INSTANCE); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java index f9851894..fdeabb6a 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java @@ -4,31 +4,99 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; +import de.oliver.fancynpcs.api.util.Interval; +import de.oliver.fancynpcs.api.util.Interval.Unit; +import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; +import it.unimi.dsi.fastutil.Pair; import org.bukkit.command.CommandSender; +import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; +import org.incendo.cloud.annotations.parser.Parser; +import org.incendo.cloud.annotations.suggestion.Suggestions; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public enum InteractionCooldownCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); + private static final Pattern SPLIT_PATTERN = Pattern.compile("(?<=\\d)(?=\\D)"); + @Command("npc interaction_cooldown ") @Permission("fancynpcs.command.npc.interaction_cooldown") public void onInteractionCooldown( final @NotNull CommandSender sender, final @NotNull Npc npc, - final float cooldown + final @NotNull @Argument(parserName = "InteractionCooldownCMD/cooldown") Interval cooldown ) { // Calling the event and updating the cooldown if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.INTERACTION_COOLDOWN, cooldown, sender).callEvent()) { - npc.getData().setInteractionCooldown(cooldown); - translator.translate("npc_interaction_cooldown_success").replace("npc", npc.getData().getName()); + npc.getData().setInteractionCooldown((float) cooldown.as(Unit.MILLISECONDS) / 1000F); + translator.translate(cooldown.as(Unit.MILLISECONDS) != 0 ? "npc_interaction_cooldown_set" : "npc_interaction_cooldown_disabled") + .replace("npc", npc.getData().getName()) + .replace("time", cooldown.toString()) + .send(sender); } else { translator.translate("command_npc_modification_cancelled").send(sender); } } + @Parser(name = "InteractionCooldownCMD/cooldown", suggestions = "InteractionCooldownCMD/cooldown") + public @NotNull Interval parse(final CommandContext context, final CommandInput input) { + final String value = input.readString(); + // Handling 'disabled' as interval of 0 milliseconds. This is how plugin determines whether interaction cooldown is enabled or not. + if (value.equalsIgnoreCase("disabled")) + return Interval.of(0, Unit.MILLISECONDS); + // Splitting user input between a digit and a letter. + final String[] split = SPLIT_PATTERN.split(value); + final @Nullable Long num = (split.length == 2) ? parseLong(split[0]) : null; + final @Nullable Unit unit = (split.length == 2) ? Unit.fromShortCode(split[1].toLowerCase()) : null; + // Sending error message to the sender if input cannot be converted to a valid interval. + if (num == null || unit == null) + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_interval").replaceStripped("input", value).send(context.sender())); + return Interval.of(Math.max(0, num), unit); + } + + @Suggestions(value = "InteractionCooldownCMD/cooldown") + public @NotNull Collection suggest(final CommandContext context, final CommandInput input) { + final String value = input.readString(); + // Splitting user input between a digit and a letter. + final String[] split = SPLIT_PATTERN.split(value); + final @Nullable Long num = parseLong(split[0]); + // Checking that the number is not null. + return (num == null || num <= 0) + ? List.of("disabled") + : new ArrayList<>() {{ + add("disabled"); + addAll(Stream.of( + Pair.of(Interval.of(num, Unit.MILLISECONDS), Unit.MILLISECONDS), + Pair.of(Interval.of(num, Unit.SECONDS), Unit.SECONDS), + Pair.of(Interval.of(num, Unit.MINUTES), Unit.MINUTES), + Pair.of(Interval.of(num, Unit.HOURS), Unit.HOURS), + Pair.of(Interval.of(num, Unit.DAYS), Unit.DAYS), + Pair.of(Interval.of(num, Unit.MONTHS), Unit.MONTHS), + Pair.of(Interval.of(num, Unit.YEARS), Unit.YEARS) + ).map(pair -> num + pair.second().getShortCode()).toList()); + }}; + } + + private @Nullable Long parseLong(final @NotNull String value) { + try { + return Long.parseLong(value); + } catch (final NumberFormatException e) { + return null; + } + } + } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 033da967..36e8736f 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -35,7 +35,7 @@ messages: color_white: "White" # Common (Other) - interaction_on_cooldown: "› {errorColor}You're currently on cooldown. {time} seconds remaining." + interaction_on_cooldown: "› {errorColor}You're currently on cooldown. {warningColor}{time}{errorColor} remaining." # Commands (Common Replies) command_missing_permissions: "› {errorColor}Insufficient permissions. You cannot use this command." @@ -51,6 +51,7 @@ messages: command_invalid_attribute: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid attribute." command_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." command_invalid_equipment_slot: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid slot." + command_invalid_interval: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid duration of time." command_unsupported_npc_type: "› This NPC type does not support this feature." command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." @@ -72,7 +73,7 @@ messages: npc_equipment_set: "Syntax: {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}set {secondaryColor}(slot) (@hand | @none | item)" npc_glowing: "Syntax: {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color)" npc_info: "Syntax: {primaryColor}/npc info {secondaryColor}(npc)" - npc_interaction_cooldown: "Syntax: {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (seconds)" + npc_interaction_cooldown: "Syntax: {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (disabled | time)" npc_list: "Syntax: {primaryColor}/npc list {secondaryColor}[filters...]" npc_message: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}(add | set | remove | clear | list | send_randomly)" npc_message_add: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}add {secondaryColor}(@none | message)" @@ -108,44 +109,14 @@ messages: npc_help_page_header: "------------- {primaryColor}FancyNpcs Commands ({primaryColor}{page}/{primaryColor}{max_page}) --------------" npc_help_page_footer: "----------- Click {primaryColor}here to open documentation -----------" npc_help_contents: - # - "› {primaryColor}/npc create {secondaryColor}(npc) - Creates a new NPC at your location." - # - "› {primaryColor}/npc remove {secondaryColor}(npc) - Removes specified NPC." - # - "› {primaryColor}/npc copy {secondaryColor}(npc) (new_name) - Copies/clones specified NPC." - # - "› {primaryColor}/npc list {secondaryColor}[flags...] - Lists all NPCs." - # - "› {primaryColor}/npc nearby {secondaryColor}[flags...] - Lists nearby NPCs." - # - "› {primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url) - Changes NPC's skin." - "Creates a new NPC at your location.'>{primaryColor}/npc create {secondaryColor}(npc) <#6B1216>[--type] [--position] [--world]" - "Removes specified NPC.'>{primaryColor}/npc remove {secondaryColor}(npc)" - "Copies/clones specified NPC.'>{primaryColor}/npc copy {secondaryColor}(npc) (new_name)" - "Lists all NPCs in all worlds. Filters can be applied.'>{primaryColor}/npc list <#6B1216>[--type] [--sort]" - "Lists all NPCs in player''s world. Filters can be applied.'>{primaryColor}/npc nearby <#6B1216>[--radius] [--type] [--sort]" - "Changes skin of the NPC.'>{primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url)" + # TO-DO: ... - - "› {primaryColor}/npc type {secondaryColor}(npc) (type) - Changes entity type of an NPC." - - "› {primaryColor}/npc teleport {secondaryColor}(npc) - Teleports you to the NPC." - - "› {primaryColor}/npc move_here {secondaryColor}(npc) - Moves NPC to your location." - - "› {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world] - Moves NPC." - - "› {primaryColor}/npc displayname {secondaryColor}(npc) (name) - Changes NPC's displayname." - - "› {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}set {secondaryColor}(slot) (item) - Changes equipment." - - "› {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}clear - Clears equipment." - - "› {primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}list - Lists equipment." - - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}add {secondaryColor}(message) - Adds message." - - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}set {secondaryColor}(num) (message) - Sets message." - - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(num) - Removes message." - - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}clear - Clears message." - - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}list - Lists message." - - "› {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}send_randomly {secondaryColor}[state] - " - - "› {primaryColor}/npc player_command {secondaryColor}(npc) (...) - Manages click commands." - - "› {primaryColor}/npc server_command {secondaryColor}(npc) (...) - Manages click commands." - - "› {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state) - Changes tab-list visibility." - - "› {primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color) - Changes glowing state." - - "› {primaryColor}/npc collidable {secondaryColor}(npc) (state) - Changes collidable state." - - "› {primaryColor}/npc turn_to_player {secondaryColor}(npc) (state) - Changes turning state." - - "› {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}set {secondaryColor}(attr) (value) - Sets attribute." - - "› {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}list - Lists attributes." - - "› {primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}clear - Clears attributes." - - "› {primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (sec) - Sets inter. cooldown." - - # Commands (npc attribute) npc_attribute_set: "Attribute {warningColor}{attribute} has been set to {warningColor}{value}." npc_attribute_set_invalid_for_this_entity_type: "› {errorColor}Attribute {warningColor}{input}{errorColor} is not valid attribute for this entity type." @@ -217,7 +188,8 @@ messages: - "" # Commands (npc interaction_cooldown) - npc_interaction_cooldown_success: "NPC {warningColor}{npc} has had their interaction cooldown updated." + npc_interaction_cooldown_set: "Interaction cooldown has been set to {warningColor}{time}." + npc_interaction_cooldown_disabled: "Interaction cooldown has been disabled." # Commands (npc list) npc_list_header: "------------------ List Query Result ------------------" From cd174cb77f7767a3935228afe34b3d298d96952e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 00:32:26 +0200 Subject: [PATCH 77/94] fix import --- .../java/de/oliver/fancynpcs/commands/CloudCommandManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 3c5b2cfd..2c85bd17 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -5,7 +5,6 @@ import de.oliver.fancynpcs.commands.arguments.LocationArgument; import de.oliver.fancynpcs.commands.arguments.NpcArgument; import de.oliver.fancynpcs.commands.exceptions.ReplyingParseException; -import de.oliver.fancynpcs.commands.npc.*; import de.oliver.fancynpcs.commands.npc.AttributeCMD; import de.oliver.fancynpcs.commands.npc.CollidableCMD; import de.oliver.fancynpcs.commands.npc.CopyCMD; From cc148c942fcd9436a64ad5ebace98d657833ed7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 00:45:45 +0200 Subject: [PATCH 78/94] format interaction cooldown in `info` sub-command --- .../java/de/oliver/fancynpcs/api/util/Interval.java | 4 +++- .../de/oliver/fancynpcs/commands/npc/InfoCMD.java | 13 +++++++++++-- src/main/resources/languages/en.yml | 10 +++++----- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/de/oliver/fancynpcs/api/util/Interval.java b/api/src/main/java/de/oliver/fancynpcs/api/util/Interval.java index 0a82a5d0..04ef6610 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/util/Interval.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/util/Interval.java @@ -41,6 +41,8 @@ /** * {@link Interval} is simple (but not very extensible) object that provides methods for * unit conversion and creation of human-readable 'elapsed time' strings. + * + * @apiNote This API is for internal use only and can change at any time. */ @ApiStatus.Internal public final class Interval { @@ -164,7 +166,7 @@ public double as(final @NotNull Unit unit) { final StringBuilder builder = new StringBuilder(); // Appending to the StringBuilder. if (years > 0L) builder.append(years).append("y "); - if (months > 0L) builder.append(months).append("m "); + if (months > 0L) builder.append(months).append("mo "); if (days > 0L) builder.append(days).append("d "); if (hours > 0L) builder.append(hours).append("h "); if (minutes > 0L) builder.append(minutes).append("min "); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index ebe764e4..b2d85f0b 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -4,16 +4,19 @@ import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; +import de.oliver.fancynpcs.api.util.Interval; +import de.oliver.fancynpcs.api.util.Interval.Unit; import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; import de.oliver.fancynpcs.util.GlowingColor; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; -import org.jetbrains.annotations.NotNull; import java.text.DecimalFormat; +import org.jetbrains.annotations.NotNull; + public enum InfoCMD { INSTANCE; // SINGLETON @@ -28,6 +31,7 @@ public void onInfo( final @NotNull Npc npc ) { final Location loc = npc.getData().getLocation(); + final Interval interactionCooldown = Interval.of(npc.getData().getInteractionCooldown(), Unit.SECONDS); // Getting the translated glowing state. This should never throw because all supported NamedTextColor objects has their mapping in GlowingColor enum. final String glowingStateTranslated = (!npc.getData().isGlowing() || npc.getData().getGlowingColor() != null) ? ((SimpleMessage) translator.translate(GlowingColor.fromAdventure(npc.getData().getGlowingColor()).getTranslationKey())).getMessage() @@ -49,7 +53,7 @@ public void onInfo( .replace("is_turn_to_player", getTranslatedBoolean(npc.getData().isTurnToPlayer())) .replace("is_show_in_tab", getTranslatedBoolean(npc.getData().isShowInTab())) .replace("is_skin_mirror", getTranslatedBoolean(npc.getData().isMirrorSkin())) - .replace("interaction_cooldown", SECONDS_FORMAT.format(npc.getData().getInteractionCooldown()) + "s") + .replace("interaction_cooldown", npc.getData().getInteractionCooldown() <= 0 ? getTranslatedState(false) : interactionCooldown.toString()) .replace("messages_total", String.valueOf(npc.getData().getMessages().size())) .replace("player_commands_total", String.valueOf(npc.getData().getPlayerCommands().size())) .replace("server_commands_total", String.valueOf(npc.getData().getServerCommands().size())) @@ -61,6 +65,11 @@ public void onInfo( return (bool) ? ((SimpleMessage) translator.translate("true")).getMessage() : ((SimpleMessage) translator.translate("false")).getMessage(); } + // NOTE: Might need to be improved later down the line, should get work done for now. + private @NotNull String getTranslatedState(final boolean bool) { + return (bool) ? ((SimpleMessage) translator.translate("enabled")).getMessage() : ((SimpleMessage) translator.translate("disabled")).getMessage(); + } + // NOTE: Might need to be improved later down the line, should get work done for now. private @NotNull String getTranslatedSlot(final @NotNull NpcEquipmentSlot slot) { return ((SimpleMessage) translator.translate( diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 36e8736f..49c0349e 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -175,13 +175,13 @@ messages: - "Whether the NPC should be shown in player-list. Can be {successColor}true or {errorColor}false.'><#848484>Shown in TAB: {is_show_in_tab}" - "Collidable state of the NPC. Can be {successColor}true or {errorColor}false.'>Collidable: {is_collidable}" - "Skin mirroring state of the NPC.. Can be {successColor}true or {errorColor}false.'><#848484>Skin Mirroring: {warningColor}{is_skin_mirror}" - - "Interaction cooldown between interactions. In seconds.'>Interaction Cooldown: {warningColor}{interaction_cooldown}" + - "Cooldown between interactions.'>Interaction Cooldown: {warningColor}{interaction_cooldown}" - "" - "Click here to browse equipment.'><#848484>Equipment: {warningColor}[Click Here]" - - "Click here to browse attributes.'><#848484>Attributes: {warningColor}[Click Here]" - - "Click here to browse list of messages.'>Messages: {warningColor}[Click Here] ({messages_total} total)" - - "Click here to browse list of player commands.'><#848484>Player Commands: {warningColor}[Click Here] ({player_commands_total} total)" - - "Click here to browse list of server commands.'>Server Commands: {warningColor}[Click Here] ({server_commands_total} total)" + - "Click here to browse attributes.'>Attributes: {warningColor}[Click Here]" + - "Click here to browse list of messages.'><#848484>Messages: {warningColor}[Click Here] ({messages_total} total)" + - "Click here to browse list of player commands.'>Player Commands: {warningColor}[Click Here] ({player_commands_total} total)" + - "Click here to browse list of server commands.'><#848484>Server Commands: {warningColor}[Click Here] ({server_commands_total} total)" - "" - "› {primaryColor}Can't find what you're looking for?" - "Open the chat window to see all information." From 32d3bd528a3bd3c9b33c2f539cb8632c05dcc300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 19:35:06 +0200 Subject: [PATCH 79/94] add missing and improve existing exception handlers --- .../commands/CloudCommandManager.java | 93 ++++++++++++++++++- .../commands/arguments/NpcArgument.java | 4 +- .../fancynpcs/commands/npc/AttributeCMD.java | 4 +- .../fancynpcs/commands/npc/EquipmentCMD.java | 6 +- .../fancynpcs/commands/npc/SkinCMD.java | 4 +- src/main/resources/languages/en.yml | 9 +- 6 files changed, 107 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index 2c85bd17..dfc38ace 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -1,5 +1,6 @@ package de.oliver.fancynpcs.commands; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancylib.translations.message.Message; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.commands.arguments.LocationArgument; @@ -29,14 +30,27 @@ import de.oliver.fancynpcs.commands.npc.TeleportCMD; import de.oliver.fancynpcs.commands.npc.TurnToPlayerCMD; import de.oliver.fancynpcs.commands.npc.TypeCMD; +import de.oliver.fancynpcs.util.GlowingColor; +import io.leangen.geantyref.TypeToken; import org.bukkit.command.CommandSender; +import org.bukkit.entity.EntityType; import org.incendo.cloud.annotations.AnnotationParser; import org.incendo.cloud.bukkit.CloudBukkitCapabilities; +import org.incendo.cloud.bukkit.parser.WorldParser; +import org.incendo.cloud.bukkit.parser.location.LocationParser; import org.incendo.cloud.component.CommandComponent; import org.incendo.cloud.exception.ArgumentParseException; +import org.incendo.cloud.exception.InvalidCommandSenderException; import org.incendo.cloud.exception.InvalidSyntaxException; +import org.incendo.cloud.exception.NoPermissionException; +import org.incendo.cloud.exception.handling.ExceptionHandlerRegistration; +import org.incendo.cloud.exception.parsing.NumberParseException; +import org.incendo.cloud.exception.parsing.ParserException; import org.incendo.cloud.execution.ExecutionCoordinator; import org.incendo.cloud.paper.LegacyPaperCommandManager; +import org.incendo.cloud.parser.standard.BooleanParser; +import org.incendo.cloud.parser.standard.EnumParser; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -62,12 +76,85 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig commandManager.registerBrigadier(); // Creating instance of AnnotationParser, which is used for parsing and registering commands. this.annotationParser = new AnnotationParser<>(commandManager, CommandSender.class); - // Registering parsers and suggestion providers. + } + + /** + * Registers arguments (parsers and suggestion providers) to the {@link LegacyPaperCommandManager}. + */ + public @NotNull CloudCommandManager registerArguments() { annotationParser.parse(NpcArgument.INSTANCE); annotationParser.parse(LocationArgument.INSTANCE); - // Registering exception handlers. + // Returning this instance of CloudCommandManager to keep "builder-like" flow. + return this; + } + + /** + * Registers exception handlers to the {@link LegacyPaperCommandManager}. + */ + public @NotNull CloudCommandManager registerExceptionHandlers() { + final Translator translator = plugin.getTranslator(); + // Unwrapping some causes of ArgumentParseException to be handled in standalone exception handlers. + commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(NumberParseException.class)); + commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(BooleanParser.BooleanParseException.class)); + commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(EnumParser.EnumParseException.class)); + commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(WorldParser.WorldParseException.class)); commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(ReplyingParseException.class)); + // Overriding some default handlers to send specialized messages. + commandManager.exceptionController().registerHandler(NoPermissionException.class, (exceptionContext) -> { + translator.translate("command_missing_permissions").send(exceptionContext.context().sender()); + }); + // DEV NOTE: No need to compare sender types until we decide to make a console-only command. Should get the job done for the time being. + commandManager.exceptionController().registerHandler(InvalidCommandSenderException.class, (exceptionContext) -> { + translator.translate("command_player_only").send(exceptionContext.context().sender()); + }); + commandManager.exceptionController().registerHandler(NumberParseException.class, (exceptionContext) -> { + translator.translate("command_invalid_number") + .replaceStripped("input", exceptionContext.exception().input()) + .replace("min", exceptionContext.exception().range().min().toString()) + .replace("max", exceptionContext.exception().range().max().toString()) + .send(exceptionContext.context().sender()); + }); + commandManager.exceptionController().registerHandler(BooleanParser.BooleanParseException.class, (exceptionContext) -> { + translator.translate("command_invalid_boolean") + .replaceStripped("input", exceptionContext.exception().input()) + .send(exceptionContext.context().sender()); + }); + commandManager.exceptionController().registerHandler(WorldParser.WorldParseException.class, (exceptionContext) -> { + translator.translate("command_invalid_world") + .replaceStripped("input", exceptionContext.exception().input()) + .send(exceptionContext.context().sender()); + }); + // DEV NOTE: Temporary solution util https://github.com/Incendo/cloud-minecraft/pull/70 is merged. + commandManager.exceptionController().register(ExceptionHandlerRegistration.builder(TypeToken.get(ArgumentParseException.class)) + .exceptionFilter(exception -> exception.getCause() instanceof ParserException parserException && parserException.argumentParserClass() == LocationParser.class) + .exceptionHandler(exceptionContext -> { + final ParserException exception = (ParserException) exceptionContext.exception().getCause(); + final String input = exception.captionVariables()[0].value(); // Should never throw. + translator.translate("command_invalid_location") + .replaceStripped("input", !input.isBlank() ? input : "N/A") // Under certain conditions, input is not passed to the exception. + .send(exceptionContext.context().sender()); + }).build() + ); + commandManager.exceptionController().registerHandler(EnumParser.EnumParseException.class, (exceptionContext) -> { + String translationKey = "command_invalid_enum_generic"; + // Comparing exception enum class and choosing specialized messages. + if (exceptionContext.exception().enumClass() == ListCMD.SortType.class) + translationKey = "command_invalid_list_sort_type"; + else if (exceptionContext.exception().enumClass() == NearbyCMD.SortType.class) + translationKey = "command_invalid_nearby_sort_type"; + else if (exceptionContext.exception().enumClass() == EntityType.class) + translationKey = "command_invalid_entity_type"; + else if (exceptionContext.exception().enumClass() == GlowingColor.class) + translationKey = "command_invalid_glowing_color"; + // Sending error message to the sender. In case no specialized message has been found, a generic one is used instead. + translator.translate(translationKey) + .replaceStripped("input", exceptionContext.exception().input()) + .replace("enum", exceptionContext.exception().enumClass().getSimpleName().toLowerCase()) + .send(exceptionContext.context().sender()); + }); + // ReplyingParseException is thrown from custom argument types and is handled there. commandManager.exceptionController().registerHandler(ReplyingParseException.class, context -> context.exception().runnable().run()); + // InvalidSyntaxException is thrown when user specified syntax don't match any command. commandManager.exceptionController().registerHandler(InvalidSyntaxException.class, (exceptionContext) -> { // Creating a StringBuilder which is then appended with (known/existing) command literals. final StringBuilder translationKeyBuilder = new StringBuilder("command_syntax."); @@ -89,6 +176,8 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig } message.send(exceptionContext.context().sender()); }); + // Returning this instance of CloudCommandManager to keep "builder-like" flow. + return this; } /** diff --git a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java index 52c3a245..a1c0f24e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java +++ b/src/main/java/de/oliver/fancynpcs/commands/arguments/NpcArgument.java @@ -38,10 +38,10 @@ public enum NpcArgument { : null; // Throwing exception if no NPC with given name or UUID exist. if (npc == null) - throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replace("input", value).send(context.sender())); + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replaceStripped("input", value).send(context.sender())); // Throwing exception if PLAYER NPCS FLAG is enabled and sender is not creator of the specified NPC. if (FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled() && context.sender() instanceof Player sender && !npc.getData().getCreator().equals(sender.getUniqueId())) - throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replace("input", value).send(context.sender())); + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_npc").replaceStripped("input", value).send(context.sender())); return npc; } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java index d5e12912..f8c4fe33 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java @@ -78,7 +78,7 @@ public NpcAttribute parseAttribute(final CommandContext context, final NpcAttribute attribute = attributeManager.getAttributeByName(npc.getData().getType(), value); // Throwing exception when non-existent attribute has been provided. if (attribute == null) - throw ReplyingParseException.replying(() -> translator.translate("command_invalid_attribute").replace("input", value).send(context.sender())); + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_attribute").replaceStripped("input", value).send(context.sender())); // Otherwise, returning the attribute from the parser. return attribute; } @@ -91,7 +91,7 @@ public String parseAttributeValue(final CommandContext context, f final String value = input.readString(); // Sending error message if attribute is null or cannot accept provided value. if (!attribute.isValidValue(value)) - throw ReplyingParseException.replying(() -> translator.translate("command_invalid_attribute_value").replace("input", value).send(context.sender())); + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_attribute_value").replaceStripped("input", value).send(context.sender())); // Otherwise, returning the attribute from the parser. return value; } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java index 9cdc5c20..45407dca 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java @@ -113,7 +113,7 @@ public NpcEquipmentSlot parseSlot(final CommandContext context, f final @Nullable NpcEquipmentSlot slot = NpcEquipmentSlot.parse(value); // Sending error message if input is not a valid NpcEquipmentSlot. if (slot == null) - throw ReplyingParseException.replying(() -> translator.translate("command_invalid_equipment_slot").replace("input", value).send(context.sender())); + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_equipment_slot").replaceStripped("input", value).send(context.sender())); return slot; } @@ -132,12 +132,12 @@ else if (value.equals("@hand") && context.sender() instanceof Player player) final @Nullable NamespacedKey key = NamespacedKey.fromString(value); // Sending error message if input is not a valid NamespacedKey. if (key == null) - throw ReplyingParseException.replying(() -> translator.translate("command_invalid_material").replace("input", value).send(context.sender())); + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_material").replaceStripped("input", value).send(context.sender())); // Getting material from the registry. final @Nullable Material material = Registry.MATERIAL.get(key); // Sending error message if no material was found. if (material == null) - throw ReplyingParseException.replying(() -> translator.translate("command_invalid_material").replace("input", value).send(context.sender())); + throw ReplyingParseException.replying(() -> translator.translate("command_invalid_material").replaceStripped("input", value).send(context.sender())); // Returning new ItemStack object from the specified Material. return new ItemStack(material); } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java index 8bd24f58..80cad54a 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java @@ -80,7 +80,7 @@ public void onSkin( final SkinFetcher skinFetcher = new SkinFetcher(skin); // Sending error message if SkinFetcher has failed to load the skin. if (!skinFetcher.isLoaded()) { - translator.translate("npc_skin_failure_invalid_url").replace("input", skin).send(sender); + translator.translate("npc_skin_failure_invalid_url").replaceStripped("input", skin).send(sender); return; } // Calling events and updating the skin if not cancelled, sending error message otherwise. @@ -124,7 +124,7 @@ public void onSkin( translator.translate("command_npc_modification_cancelled").send(sender); } } else { - translator.translate("npc_skin_failure_invalid_name_or_url").replace("input", skin).send(sender); + translator.translate("npc_skin_failure_invalid_name_or_url").replaceStripped("input", skin).send(sender); } } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 49c0349e..5693e579 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -44,14 +44,19 @@ messages: command_player_only: "› {errorColor}This command can only be executed by in-game players." command_invalid_boolean: "› {errorColor}Argument {warningColor}{input}{errorColor} must be either {warningColor}true{errorColor} or {warningColor}false{errorColor}." command_invalid_number: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid number." - command_invalid_integer: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid integer." - command_invalid_world: "› {errorColor}World named {warningColor}{input}{errorColor} does not exist." + command_invalid_location: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid location." + command_invalid_world: "› {errorColor}World named {warningColor}{input}{errorColor} does not exist or is not loaded." + command_invalid_glowing_color: "› {errorColor}Argument named {warningColor}{input}{errorColor} is not a valid glowing color." + command_invalid_list_sort_type: "› {errorColor}Argument named {warningColor}{input}{errorColor} is not a valid sort type." + command_invalid_nearby_sort_type: "› {errorColor}Argument named {warningColor}{input}{errorColor} is not a valid sort type." + command_invalid_entity_type: "› {errorColor}Argument named {warningColor}{input}{errorColor} is not a valid entity type." command_invalid_npc: "› {errorColor}NPC {warningColor}{input}{errorColor} does not exist." command_invalid_material: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid material." command_invalid_attribute: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not a valid attribute." command_invalid_attribute_value: "› {errorColor}Specified value {warningColor}{input}{errorColor} is not valid for this attribute." command_invalid_equipment_slot: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid slot." command_invalid_interval: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid duration of time." + command_invalid_enum_generic: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid {enum}." command_unsupported_npc_type: "› This NPC type does not support this feature." command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." From 69ef3d45d565156c35536a247b00b333d6d6f75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 20:13:54 +0200 Subject: [PATCH 80/94] minor `skin` sub-command changes --- .../oliver/fancynpcs/commands/npc/SkinCMD.java | 18 ++++++++---------- src/main/resources/languages/en.yml | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java index 80cad54a..c7b49997 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java @@ -25,6 +25,7 @@ import java.util.regex.Pattern; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public enum SkinCMD { INSTANCE; // SINGLETON @@ -40,7 +41,7 @@ public void onSkin( final @NotNull Npc npc, final @NotNull @Argument(suggestions = "SkinCMD/skin") String skin ) { - // Exiting command block if specified NPC is not of a PLAYER type. + // Sending error message if NPC cannot have skin applied. Only players can have skins. if (npc.getData().getType() != EntityType.PLAYER) { translator.translate("command_unsupported_npc_type").send(sender); return; @@ -49,7 +50,6 @@ public void onSkin( final boolean isMirror = skin.equalsIgnoreCase("@mirror"); final boolean isNone = skin.equalsIgnoreCase("@none"); final boolean isURL = isURL(skin); - if (isMirror) { // Calling event and updating the skin if not cancelled, sending error message otherwise. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, true, sender).callEvent()) { @@ -61,7 +61,6 @@ public void onSkin( } else { translator.translate("command_npc_modification_cancelled").send(sender); } - } else if (isNone) { // Calling events and updating the skin if not cancelled, sending error message otherwise. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.MIRROR_SKIN, false, sender).callEvent() && new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SKIN, null, sender).callEvent()) { @@ -74,7 +73,6 @@ public void onSkin( } else { translator.translate("command_npc_modification_cancelled").send(sender); } - } else if (isURL) { // Creating SkinFetcher from the specified texture URL. final SkinFetcher skinFetcher = new SkinFetcher(skin); @@ -94,13 +92,11 @@ public void onSkin( } else { translator.translate("command_npc_modification_cancelled").send(sender); } - - // NOTE: Matching against valid username pattern to make it somewhat injection-proof. + // Handling as if user input is a player name. Because this may require sending a web request, we should (?) match against valid username pattern to make it somewhat injection-proof. } else if (USERNAME_PATTERN.matcher(skin).find()) { // Fetching UUID from the specified player name. - // NOTE: This can occasionally print stacktrace to the console and right now there is nothing that could be done to prevent that. - final UUID uuid = UUIDFetcher.getUUID(skin); - // Exiting the command block and sending error message if invalid/unsupported URL has been provided. + final @Nullable UUID uuid = UUIDFetcher.getUUID(skin); + // Sending error message if message if UUID fetch has (for whatever reason) failed. This can happen eg. when being rate limited. if (uuid == null) { translator.translate("npc_skin_failure_invalid_name_or_rate_limit").send(sender); return; @@ -137,7 +133,9 @@ public List suggestSkin(final CommandContext context, fin }}; } - // Returns 'true' if String can be parsed to an URL or 'false' otherwise. + /** + * Returns {@code true} if provided string can be parsed to an {@link URL} object. + */ private static boolean isURL(final @NotNull String url) { try { new URL(url); diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 5693e579..c4748f1b 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -57,7 +57,7 @@ messages: command_invalid_equipment_slot: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid slot." command_invalid_interval: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid duration of time." command_invalid_enum_generic: "› {errorColor}Argument {warningColor}{input}{errorColor} is not a valid {enum}." - command_unsupported_npc_type: "› This NPC type does not support this feature." + command_unsupported_npc_type: "› {errorColor}This NPC type does not support this feature." command_input_contains_blocked_command: "› {errorColor}This command is not allowed for use in interactions." command_npc_modification_cancelled: "› {errorColor}NPC modification has been cancelled by the API." From 96854b8adcf845db78377b91afc9dab2eab219cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 20:17:33 +0200 Subject: [PATCH 81/94] additional completions for `interaction_cooldown` sub-command --- .../oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java index fdeabb6a..71759e57 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java @@ -76,7 +76,7 @@ public void onInteractionCooldown( final @Nullable Long num = parseLong(split[0]); // Checking that the number is not null. return (num == null || num <= 0) - ? List.of("disabled") + ? List.of("30s", "5min", "8h", "disabled") : new ArrayList<>() {{ add("disabled"); addAll(Stream.of( From eb136ba57a174e636567a2e1b268ca607cd2d4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 21:56:49 +0200 Subject: [PATCH 82/94] remove days, months and years from suggestions for interval argument type These are not really that useful given that interactions are currently not stored and reset throughout server restarts. --- .../fancynpcs/commands/npc/InteractionCooldownCMD.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java index 71759e57..5e77e718 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java @@ -83,10 +83,7 @@ public void onInteractionCooldown( Pair.of(Interval.of(num, Unit.MILLISECONDS), Unit.MILLISECONDS), Pair.of(Interval.of(num, Unit.SECONDS), Unit.SECONDS), Pair.of(Interval.of(num, Unit.MINUTES), Unit.MINUTES), - Pair.of(Interval.of(num, Unit.HOURS), Unit.HOURS), - Pair.of(Interval.of(num, Unit.DAYS), Unit.DAYS), - Pair.of(Interval.of(num, Unit.MONTHS), Unit.MONTHS), - Pair.of(Interval.of(num, Unit.YEARS), Unit.YEARS) + Pair.of(Interval.of(num, Unit.HOURS), Unit.HOURS) ).map(pair -> num + pair.second().getShortCode()).toList()); }}; } From 772d851ccc811cb09781fbbc7b7b17955b965fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 21:57:24 +0200 Subject: [PATCH 83/94] migrate all remaining usages of MessageHelper to Translator --- src/main/java/de/oliver/fancynpcs/FancyNpcs.java | 3 --- .../fancynpcs/listeners/PlayerNpcsListener.java | 14 ++++++++------ src/main/resources/languages/en.yml | 4 ++++ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index 8ac99b42..46e104b2 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -3,7 +3,6 @@ import de.oliver.fancylib.FancyLib; import de.oliver.fancylib.FileUtils; import de.oliver.fancylib.LanguageConfig; -import de.oliver.fancylib.MessageHelper; import de.oliver.fancylib.Metrics; import de.oliver.fancylib.VersionConfig; import de.oliver.fancylib.featureFlags.FeatureFlag; @@ -126,8 +125,6 @@ public void onEnable() { } FancyLib.setPlugin(instance); - MessageHelper.setPrimaryColor("#E33239"); - MessageHelper.setSecondaryColor("#ad1d23"); String mcVersion = Bukkit.getMinecraftVersion(); diff --git a/src/main/java/de/oliver/fancynpcs/listeners/PlayerNpcsListener.java b/src/main/java/de/oliver/fancynpcs/listeners/PlayerNpcsListener.java index a0c174ef..c5ee1fef 100644 --- a/src/main/java/de/oliver/fancynpcs/listeners/PlayerNpcsListener.java +++ b/src/main/java/de/oliver/fancynpcs/listeners/PlayerNpcsListener.java @@ -3,7 +3,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; -import de.oliver.fancylib.MessageHelper; +import de.oliver.fancylib.translations.Translator; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcCreateEvent; @@ -18,6 +18,8 @@ public class PlayerNpcsListener implements Listener { + private final Translator translator = FancyNpcs.getInstance().getTranslator(); + private static final boolean isUsingPlotSquared = FancyNpcs.getInstance().isUsingPlotSquared(); @EventHandler @@ -30,7 +32,7 @@ public void onNpcCreate(NpcCreateEvent event) { PlotPlayer plotPlayer = PlotSquared.platform().playerManager().getPlayer(player.getUniqueId()); Plot currentPlot = plotPlayer.getCurrentPlot(); if ((currentPlot == null || !currentPlot.isOwner(player.getUniqueId())) && !player.hasPermission("fancynpcs.admin")) { - MessageHelper.error(player, "You are only allowed to create npcs on your plot"); + translator.translate("player_npcs_create_failure_not_owned_plot").send(player); event.setCancelled(true); return; } @@ -48,7 +50,7 @@ public void onNpcCreate(NpcCreateEvent event) { npcAmount++; } if (npcAmount >= maxNpcs && !player.hasPermission("fancynpcs.admin")) { - MessageHelper.error(player, "You have reached the maximum amount of npcs"); + translator.translate("player_npcs_create_failure_limit_reached").send(player); event.setCancelled(true); return; } @@ -61,7 +63,7 @@ public void onNpcRemove(NpcRemoveEvent event) { } if (!event.getNpc().getData().getCreator().equals(player.getUniqueId()) && !player.hasPermission("fancynpcs.admin")) { - MessageHelper.error(player, "You can only modify your npcs"); + translator.translate("player_npcs_cannot_modify_npc").send(player); event.setCancelled(true); return; } @@ -74,7 +76,7 @@ public void onNpcModify(NpcModifyEvent event) { } if (!event.getNpc().getData().getCreator().equals(player.getUniqueId()) && !player.hasPermission("fancynpcs.admin")) { - MessageHelper.error(player, "You can only modify your npcs"); + translator.translate("player_npcs_cannot_modify_npc").send(player); event.setCancelled(true); return; } @@ -83,7 +85,7 @@ public void onNpcModify(NpcModifyEvent event) { Plot currentPlot = plotPlayer.getCurrentPlot(); if ((currentPlot == null || !currentPlot.isOwner(player.getUniqueId())) && !player.hasPermission("fancynpcs.admin")) { - MessageHelper.error(player, "You are only allowed to teleport npcs on your plot"); + translator.translate("player_npcs_cannot_move_npc").send(player); event.setCancelled(true); } } diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index c4748f1b..3b604a82 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -36,6 +36,10 @@ messages: # Common (Other) interaction_on_cooldown: "› {errorColor}You're currently on cooldown. {warningColor}{time}{errorColor} remaining." + player_npcs_cannot_modify_npc: "› {errorColor}You can only modify NPCs you own." + player_npcs_cannot_move_npc: "› {errorColor}You are only allowed to teleport NPCs to your plot." + player_npcs_create_failure_limit_reached: "› {errorColor}You have reached maximum number of NPCs." + player_npcs_create_failure_not_owned_plot: "› {errorColor}You can only create NPCs on your plot." # Commands (Common Replies) command_missing_permissions: "› {errorColor}Insufficient permissions. You cannot use this command." From 2c4e7b948c3038885794a63e82e69be019cd54a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 22:06:07 +0200 Subject: [PATCH 84/94] small refactor of GlowingColor --- .../de/oliver/fancynpcs/commands/CloudCommandManager.java | 4 ++-- .../java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java | 2 +- .../java/de/oliver/fancynpcs/commands/npc/InfoCMD.java | 2 +- .../de/oliver/fancynpcs/{util => utils}/GlowingColor.java | 8 +++----- 4 files changed, 7 insertions(+), 9 deletions(-) rename src/main/java/de/oliver/fancynpcs/{util => utils}/GlowingColor.java (89%) diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index dfc38ace..ec365820 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -30,7 +30,7 @@ import de.oliver.fancynpcs.commands.npc.TeleportCMD; import de.oliver.fancynpcs.commands.npc.TurnToPlayerCMD; import de.oliver.fancynpcs.commands.npc.TypeCMD; -import de.oliver.fancynpcs.util.GlowingColor; +import de.oliver.fancynpcs.utils.GlowingColor; import io.leangen.geantyref.TypeToken; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; @@ -202,8 +202,8 @@ else if (exceptionContext.exception().enumClass() == GlowingColor.class) annotationParser.parse(NearbyCMD.INSTANCE); annotationParser.parse(NpcHelpCMD.INSTANCE); annotationParser.parse(PlayerCommandCMD.INSTANCE); - annotationParser.parse(ServerCommandCMD.INSTANCE); annotationParser.parse(RemoveCMD.INSTANCE); + annotationParser.parse(ServerCommandCMD.INSTANCE); annotationParser.parse(ShowInTabCMD.INSTANCE); annotationParser.parse(SkinCMD.INSTANCE); annotationParser.parse(TeleportCMD.INSTANCE); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java index c4eeff47..b5770ae0 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java @@ -5,7 +5,7 @@ import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.events.NpcModifyEvent; -import de.oliver.fancynpcs.util.GlowingColor; +import de.oliver.fancynpcs.utils.GlowingColor; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index b2d85f0b..15f27565 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -7,7 +7,7 @@ import de.oliver.fancynpcs.api.util.Interval; import de.oliver.fancynpcs.api.util.Interval.Unit; import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; -import de.oliver.fancynpcs.util.GlowingColor; +import de.oliver.fancynpcs.utils.GlowingColor; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Command; diff --git a/src/main/java/de/oliver/fancynpcs/util/GlowingColor.java b/src/main/java/de/oliver/fancynpcs/utils/GlowingColor.java similarity index 89% rename from src/main/java/de/oliver/fancynpcs/util/GlowingColor.java rename to src/main/java/de/oliver/fancynpcs/utils/GlowingColor.java index 2fc2e660..d5e1e564 100644 --- a/src/main/java/de/oliver/fancynpcs/util/GlowingColor.java +++ b/src/main/java/de/oliver/fancynpcs/utils/GlowingColor.java @@ -1,11 +1,11 @@ -package de.oliver.fancynpcs.util; +package de.oliver.fancynpcs.utils; import net.kyori.adventure.text.format.NamedTextColor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -// Used by commands. +// Used 'info' and 'glowing' sub-commands. public enum GlowingColor { DISABLED(null, ""), BLACK(NamedTextColor.BLACK, "color_black"), @@ -25,12 +25,10 @@ public enum GlowingColor { YELLOW(NamedTextColor.YELLOW, "color_yellow"), WHITE(NamedTextColor.WHITE, "color_white"); - // Handled as 'disabled' if set to null. private final @Nullable NamedTextColor color; - private final @NotNull String translationKey; - private GlowingColor(final @Nullable NamedTextColor color, final @NotNull String translationKey) { + GlowingColor(final @Nullable NamedTextColor color, final @NotNull String translationKey) { this.color = color; this.translationKey = translationKey; } From d497c67c2c9394c564e463a35bf6140d9c4ffc99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 22:19:33 +0200 Subject: [PATCH 85/94] improve `feature_flags` sub-command format --- .../oliver/fancynpcs/commands/FancyNpcsCMD.java | 13 +++++++------ src/main/resources/languages/en.yml | 17 ++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java index 93d6d09e..0db98ffb 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/FancyNpcsCMD.java @@ -44,26 +44,27 @@ public void onReload(final CommandSender sender) { @Command("fancynpcs save") @Permission("fancynpcs.command.fancynpcs.save") public void onSave(final CommandSender sender) { - // Saving all NPCs. plugin.getNpcManagerImpl().saveNpcs(true); - // Sending success message to the sender. translator.translate("fancynpcs_save_success").send(sender); } + // NOTE: In the future, if there is more than a few feature flags, we might consider listing entries automatically by iterating, just like in 'list' sub-command. @Command("fancynpcs feature_flags") @Permission("fancynpcs.command.fancynpcs.feature_flags") public void onFeatureFlags(final CommandSender sender) { - // Printing the header of the list. translator.translate("fancynpcs_feature_flags_header").send(sender); - // Printing status of all existing feature flags. translator.translate("fancynpcs_feature_flags_entry") .replace("number", "1") .replace("name", "Player NPCs") .replace("id", FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.getName()) .replace("state", getTranslatedState(FancyNpcs.PLAYER_NPCS_FEATURE_FLAG.isEnabled())) .send(sender); - // Printing the footer of the list. - translator.translate("fancynpcs_feature_flags_footer").send(sender); + translator.translate("fancynpcs_feature_flags_footer") + .replace("count", "1") + .replace("count_formatted", "· · 1") + .replace("total", String.valueOf(FancyNpcs.getInstance().getNpcManager().getAllNpcs().size())) + .replace("total_formatted", "· · 1") + .send(sender); } // NOTE: Might need to be improved later down the line, should get work done for now. diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 3b604a82..972ba560 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -109,10 +109,9 @@ messages: # Commands (fancynpcs) fancynpcs_reload_success: "› {successColor}Plugin has been reloaded." fancynpcs_save_success: "› {successColor}NPCs have been saved." - fancynpcs_version: "" # NOT CONFIGURABLE - fancynpcs_feature_flags_header: "Feature Flags:" - fancynpcs_feature_flags_entry: "› <#848484>{number}. {warningColor}{name} <#848484>({id}): {state}" - fancynpcs_feature_flags_footer: "" + fancynpcs_feature_flags_header: "------------------- Feature Flags ------------------" + fancynpcs_feature_flags_entry: " <#848484>{number}. {warningColor}{name} <#848484>({id}): {state}" + fancynpcs_feature_flags_footer: "------------- Showing total of {warningColor}{total_formatted} entries -------------" # Commands (npc help) npc_help_page_header: "------------- {primaryColor}FancyNpcs Commands ({primaryColor}{page}/{primaryColor}{max_page}) --------------" @@ -186,11 +185,11 @@ messages: - "Skin mirroring state of the NPC.. Can be {successColor}true or {errorColor}false.'><#848484>Skin Mirroring: {warningColor}{is_skin_mirror}" - "Cooldown between interactions.'>Interaction Cooldown: {warningColor}{interaction_cooldown}" - "" - - "Click here to browse equipment.'><#848484>Equipment: {warningColor}[Click Here]" - - "Click here to browse attributes.'>Attributes: {warningColor}[Click Here]" - - "Click here to browse list of messages.'><#848484>Messages: {warningColor}[Click Here] ({messages_total} total)" - - "Click here to browse list of player commands.'>Player Commands: {warningColor}[Click Here] ({player_commands_total} total)" - - "Click here to browse list of server commands.'><#848484>Server Commands: {warningColor}[Click Here] ({server_commands_total} total)" + - "Click here to browse equipment.'><#848484>Equipment: {warningColor}[Click Here]" + - "Click here to browse attributes.'>Attributes: {warningColor}[Click Here]" + - "Click here to browse list of messages.'><#848484>Messages: {warningColor}[Click Here] ({messages_total} total)" + - "Click here to browse list of player commands.'>Player Commands: {warningColor}[Click Here] ({player_commands_total} total)" + - "Click here to browse list of server commands.'><#848484>Server Commands: {warningColor}[Click Here] ({server_commands_total} total)" - "" - "› {primaryColor}Can't find what you're looking for?" - "Open the chat window to see all information." From 23f6ef6e9dff93709f0f02fd01acda91ebe0abd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 23:05:23 +0200 Subject: [PATCH 86/94] minor code refactor --- .../de/oliver/fancynpcs/commands/npc/AttributeCMD.java | 2 +- .../java/de/oliver/fancynpcs/commands/npc/CopyCMD.java | 6 ++++-- .../java/de/oliver/fancynpcs/commands/npc/CreateCMD.java | 2 +- .../de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java | 4 ++++ .../de/oliver/fancynpcs/commands/npc/EquipmentCMD.java | 2 +- .../java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java | 8 +++----- .../fancynpcs/commands/npc/InteractionCooldownCMD.java | 4 ++++ .../java/de/oliver/fancynpcs/commands/npc/MessageCMD.java | 2 +- .../java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java | 2 ++ .../oliver/fancynpcs/commands/npc/PlayerCommandCMD.java | 2 +- .../oliver/fancynpcs/commands/npc/ServerCommandCMD.java | 2 +- .../de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java | 3 --- .../java/de/oliver/fancynpcs/commands/npc/SkinCMD.java | 4 ++++ 13 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java index f8c4fe33..102940cc 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/AttributeCMD.java @@ -65,7 +65,7 @@ public void onAttributeList( translator.translate("npc_attribute_list_footer").send(sender); } - /* PARSERS AND SUGGESTION PROVIDERS */ + /* PARSERS AND SUGGESTIONS */ // This parser does not specify a name, making it default parser for the returned type. @Parser(name = "", suggestions = "AttributeCMD/attribute") diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java index 8729b355..f700302e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CopyCMD.java @@ -8,18 +8,20 @@ import org.bukkit.entity.Player; import org.incendo.cloud.annotations.Command; import org.incendo.cloud.annotations.Permission; -import org.jetbrains.annotations.NotNull; import java.util.UUID; import java.util.regex.Pattern; +import org.jetbrains.annotations.NotNull; + // TO-DO: Console support with --position and --world parameter flags. public enum CopyCMD { INSTANCE; // SINGLETON - private static final Pattern NPC_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9/_-]*$"); private final Translator translator = FancyNpcs.getInstance().getTranslator(); + private static final Pattern NPC_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9/_-]*$"); + @Command(value = "npc copy ", requiredSender = Player.class) @Permission("fancynpcs.command.npc.copy") public void onCopy( diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java index 11e0a9aa..5b7ddd47 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/CreateCMD.java @@ -65,7 +65,7 @@ public void onCreate( // Updating World of the Location argument if '--world' flag has been specified. if (world != null) finalLocation.setWorld(world); - // Creating new NPC + // Creating new NPC and applying data. final Npc npc = FancyNpcs.getInstance().getNpcAdapter().apply(new NpcData(name, creator, finalLocation)); // Setting the type of NPC. Flag '--type' is optional and defaults to EntityType.PLAYER. npc.getData().setType(type != null ? type : EntityType.PLAYER); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java index f13d1169..8f2a5b33 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java @@ -57,11 +57,15 @@ public void onDisplayName( } } + /* PARSERS AND SUGGESTIONS */ + @Suggestions("DisplayNameCMD/none") public List suggestNone(final CommandContext sender, CommandInput input) { return NONE_SUGGESTIONS; } + /* UTILITY METHODS */ + /** Returns {@code true} if specified component contains blocked command, {@code false} otherwise. */ private boolean hasBlockedCommands(final @NotNull String message) { // Converting message to a Component. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java index 45407dca..e249892a 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/EquipmentCMD.java @@ -104,7 +104,7 @@ public void onEquipmentList( translator.translate("npc_equipment_list_footer").send(sender); } - /* PARSER AND SUGGESTIONS */ + /* PARSERS AND SUGGESTIONS */ // This parser does not specify a name, making it default parser for the returned type. @Parser(name = "", suggestions = "EquipmentCMD/slot") diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java index b5770ae0..900040ce 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/GlowingCMD.java @@ -50,14 +50,12 @@ else if (color == GlowingColor.DISABLED) { } // Handling 'color' state, which means enabling glowing and changing the color to desired one. } else if (npc.getData().isGlowing() || new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING, true, sender).callEvent()) { - // Updating the glowing state, if previously disabled. - if (!npc.getData().isGlowing()) { - npc.getData().setGlowing(true); - npc.updateForAll(); - } // Calling the event and updating the glowing color if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.GLOWING_COLOR, color.getColor(), sender).callEvent()) { npc.getData().setGlowingColor(color.getColor()); + // Updating the glowing state, if previously disabled. + if (!npc.getData().isGlowing()) + npc.getData().setGlowing(true); npc.updateForAll(); translator.translate("npc_glowing_set_color_success") .replace("npc", npc.getData().getName()) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java index 5e77e718..8254a116 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InteractionCooldownCMD.java @@ -52,6 +52,8 @@ public void onInteractionCooldown( } } + /* PARSERS AND SUGGESTIONS */ + @Parser(name = "InteractionCooldownCMD/cooldown", suggestions = "InteractionCooldownCMD/cooldown") public @NotNull Interval parse(final CommandContext context, final CommandInput input) { final String value = input.readString(); @@ -88,6 +90,8 @@ public void onInteractionCooldown( }}; } + /* UTILITY METHODS */ + private @Nullable Long parseLong(final @NotNull String value) { try { return Long.parseLong(value); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index 6ae923ce..0e5366c4 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -195,7 +195,7 @@ public void onMessageSendRandomly( } - /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ + /* PARSERS AND SUGGESTIONS */ @Suggestions("MessageCMD/none") public List suggestNone(final CommandContext context, final CommandInput input) { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java index e22a18fc..f6c193c5 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java @@ -44,6 +44,8 @@ public void onHelp( translator.translate("npc_help_page_footer").replace("page", String.valueOf(finalPage)).replace("max_page", String.valueOf(maxPage)).send(sender); } + /* PARSERS AND SUGGESTIONS */ + @Suggestions("NpcHelpCMD/page") public List suggestions(final CommandContext context, final CommandInput input) { // Getting the (full) help contents. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java index 27233ce6..1d521599 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java @@ -165,7 +165,7 @@ public void onPlayerCommandList( .send(sender); } - /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ + /* PARSERS AND SUGGESTIONS */ @Suggestions("PlayerCommandCMD/number_range") // Generates number range suggestions based on the number of player commands. public List suggestNumber(final CommandContext context, final CommandInput input) { diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java index 37035d5c..549967dd 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java @@ -165,7 +165,7 @@ public void onServerCommandList( .send(sender); } - /* ARGUMENT PARSERS AND SUGGESTION PROVIDERS */ + /* PARSERS AND SUGGESTIONS */ @Suggestions("ServerCommandCMD/number_range") // Generates number range suggestions based on the number of server commands. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java index 8fa9cd63..998cb71d 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java @@ -26,11 +26,8 @@ public void onCommand( final boolean finalState = (state == null) ? !npc.getData().isShowInTab() : state; // Calling the event and updating the state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SHOW_IN_TAB, finalState, sender).callEvent()) { - // Updating the state. npc.getData().setShowInTab(finalState); - // Sending message to the sender. translator.translate(finalState ? "npc_show_in_tab_set_true" : "npc_show_in_tab_set_false").replace("npc", npc.getData().getName()).send(sender); - // Returning from the command block. return; } // Otherwise, sending error message to the sender. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java index c7b49997..cc21f7c3 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/SkinCMD.java @@ -124,6 +124,8 @@ public void onSkin( } } + /* PARSERS AND SUGGESTIONS */ + @Suggestions("SkinCMD/skin") public List suggestSkin(final CommandContext context, final CommandInput input) { return new ArrayList<>() {{ @@ -133,6 +135,8 @@ public List suggestSkin(final CommandContext context, fin }}; } + /* UTILITY METHODS */ + /** * Returns {@code true} if provided string can be parsed to an {@link URL} object. */ From a648928c79491e2e800059d5131bfa81464ec7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Fri, 17 May 2024 23:09:51 +0200 Subject: [PATCH 87/94] rename NpcHelpCMD to HelpCMD --- .../de/oliver/fancynpcs/commands/CloudCommandManager.java | 4 ++-- .../commands/npc/{NpcHelpCMD.java => HelpCMD.java} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/de/oliver/fancynpcs/commands/npc/{NpcHelpCMD.java => HelpCMD.java} (94%) diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index ec365820..ee89dfac 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -21,7 +21,7 @@ import de.oliver.fancynpcs.commands.npc.MoveHereCMD; import de.oliver.fancynpcs.commands.npc.MoveToCMD; import de.oliver.fancynpcs.commands.npc.NearbyCMD; -import de.oliver.fancynpcs.commands.npc.NpcHelpCMD; +import de.oliver.fancynpcs.commands.npc.HelpCMD; import de.oliver.fancynpcs.commands.npc.PlayerCommandCMD; import de.oliver.fancynpcs.commands.npc.RemoveCMD; import de.oliver.fancynpcs.commands.npc.ServerCommandCMD; @@ -200,7 +200,7 @@ else if (exceptionContext.exception().enumClass() == GlowingColor.class) annotationParser.parse(MoveHereCMD.INSTANCE); annotationParser.parse(MoveToCMD.INSTANCE); annotationParser.parse(NearbyCMD.INSTANCE); - annotationParser.parse(NpcHelpCMD.INSTANCE); + annotationParser.parse(HelpCMD.INSTANCE); annotationParser.parse(PlayerCommandCMD.INSTANCE); annotationParser.parse(RemoveCMD.INSTANCE); annotationParser.parse(ServerCommandCMD.INSTANCE); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java similarity index 94% rename from src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java rename to src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java index f6c193c5..4bc0337b 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/NpcHelpCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java @@ -17,7 +17,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public enum NpcHelpCMD { +public enum HelpCMD { INSTANCE; // SINGLETON private final Translator translator = FancyNpcs.getInstance().getTranslator(); @@ -26,7 +26,7 @@ public enum NpcHelpCMD { @Permission("fancynpcs.command.npc") public void onHelp( final @NotNull CommandSender sender, - final @Nullable @Argument(suggestions = "NpcHelpCMD/page") Integer page + final @Nullable @Argument(suggestions = "HelpCMD/page") Integer page ) { // Getting the (full) help contents. final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); @@ -46,7 +46,7 @@ public void onHelp( /* PARSERS AND SUGGESTIONS */ - @Suggestions("NpcHelpCMD/page") + @Suggestions("HelpCMD/page") public List suggestions(final CommandContext context, final CommandInput input) { // Getting the (full) help contents. final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); From 16b16ac69e2921b0a00b9a6440ec390a8654e881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sat, 18 May 2024 00:07:38 +0200 Subject: [PATCH 88/94] fix `shown_in_tab` not updating --- .../java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java index 998cb71d..7530aa92 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ShowInTabCMD.java @@ -27,6 +27,9 @@ public void onCommand( // Calling the event and updating the state if not cancelled. if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.SHOW_IN_TAB, finalState, sender).callEvent()) { npc.getData().setShowInTab(finalState); + npc.removeForAll(); + npc.create(); + npc.spawnForAll(); translator.translate(finalState ? "npc_show_in_tab_set_true" : "npc_show_in_tab_set_false").replace("npc", npc.getData().getName()).send(sender); return; } From 881412b8cdd6117d1ce81ff478763d93f6ad10dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 19 May 2024 13:58:55 +0200 Subject: [PATCH 89/94] more tweaks and fixes --- .../commands/npc/DisplayNameCMD.java | 2 +- .../fancynpcs/commands/npc/HelpCMD.java | 7 +++--- .../fancynpcs/commands/npc/InfoCMD.java | 22 ++++--------------- .../fancynpcs/commands/npc/MessageCMD.java | 2 +- .../commands/npc/PlayerCommandCMD.java | 2 +- .../commands/npc/ServerCommandCMD.java | 2 +- .../fancynpcs/commands/npc/TeleportCMD.java | 3 +-- src/main/resources/languages/en.yml | 14 ++++++------ 8 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java index 8f2a5b33..2d17110a 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/DisplayNameCMD.java @@ -72,7 +72,7 @@ private boolean hasBlockedCommands(final @NotNull String message) { final Component component = ModernChatColorHandler.translate(message); // Getting the list of all blocked commands. final List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); - // Iterating over all children of the component... + // Iterating over all elements of the component. return StreamSupport.stream(component.iterable(ComponentIteratorType.DEPTH_FIRST).spliterator(), false).anyMatch(it -> { final ClickEvent event = it.clickEvent(); // We only care about click events with run_command as an action. Continuing if not found. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java index 4bc0337b..10199741 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java @@ -31,7 +31,7 @@ public void onHelp( // Getting the (full) help contents. final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); // Calculating max page number. - final int maxPage = contents.getRawMessages().size() / 6 + 1; + final int maxPage = Math.max(1, contents.getRawMessages().size() / 6); // Getting the requested page. Defaults to 1 for invalid input and is capped by number of the last page. final int finalPage = Math.min(page != null ? page : 1, maxPage); // Getting help contents for requested page, or defaulting to 1. @@ -54,10 +54,9 @@ public List suggestions(final CommandContext context, fin final int maxPage = contents.getRawMessages().size() / 6 + 1; // Returning suggestions... return new ArrayList<>() {{ - for (int i = 1; i <= maxPage; i++) { + for (int i = 1; i <= maxPage; i++) add(String.valueOf(i)); - }} - }; + }}; } } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java index 15f27565..7955bd3e 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/InfoCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancynpcs.commands.npc; import de.oliver.fancylib.translations.Translator; +import de.oliver.fancylib.translations.message.Message; import de.oliver.fancylib.translations.message.SimpleMessage; import de.oliver.fancynpcs.FancyNpcs; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.util.Interval; import de.oliver.fancynpcs.api.util.Interval.Unit; -import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; import de.oliver.fancynpcs.utils.GlowingColor; import org.bukkit.Location; import org.bukkit.command.CommandSender; @@ -36,7 +36,7 @@ public void onInfo( final String glowingStateTranslated = (!npc.getData().isGlowing() || npc.getData().getGlowingColor() != null) ? ((SimpleMessage) translator.translate(GlowingColor.fromAdventure(npc.getData().getGlowingColor()).getTranslationKey())).getMessage() : ((SimpleMessage) translator.translate("disabled")).getMessage(); - translator.translate("npc_info_general") + final Message message = translator.translate("npc_info_general") .replace("name", npc.getData().getName()) .replace("id", npc.getData().getId()) .replace("id_short", npc.getData().getId().substring(0, 13) + "...") @@ -56,8 +56,8 @@ public void onInfo( .replace("interaction_cooldown", npc.getData().getInteractionCooldown() <= 0 ? getTranslatedState(false) : interactionCooldown.toString()) .replace("messages_total", String.valueOf(npc.getData().getMessages().size())) .replace("player_commands_total", String.valueOf(npc.getData().getPlayerCommands().size())) - .replace("server_commands_total", String.valueOf(npc.getData().getServerCommands().size())) - .send(sender); + .replace("server_commands_total", String.valueOf(npc.getData().getServerCommands().size())); + message.send(sender); } // NOTE: Might need to be improved later down the line, should get work done for now. @@ -70,18 +70,4 @@ public void onInfo( return (bool) ? ((SimpleMessage) translator.translate("enabled")).getMessage() : ((SimpleMessage) translator.translate("disabled")).getMessage(); } - // NOTE: Might need to be improved later down the line, should get work done for now. - private @NotNull String getTranslatedSlot(final @NotNull NpcEquipmentSlot slot) { - return ((SimpleMessage) translator.translate( - switch (slot) { - case MAINHAND -> "main_hand"; - case OFFHAND -> "off_hand"; - case HEAD -> "head"; - case CHEST -> "chest"; - case LEGS -> "legs"; - case FEET -> "feet"; - } - )).getMessage(); - } - } diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java index 0e5366c4..f1ded244 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/MessageCMD.java @@ -222,7 +222,7 @@ private boolean hasBlockedCommands(final @NotNull String message) { final Component component = ModernChatColorHandler.translate(message); // Getting the list of all blocked commands. final List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); - // Iterating over all children of the component... + // Iterating over all elements of the component. return StreamSupport.stream(component.iterable(ComponentIteratorType.DEPTH_FIRST).spliterator(), false).anyMatch(it -> { final ClickEvent event = it.clickEvent(); // We only care about click events with run_command as an action. Continuing if not found. diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java index 1d521599..fd96d141 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/PlayerCommandCMD.java @@ -192,7 +192,7 @@ public Collection suggestCommand(final CommandContext con private boolean hasBlockedCommands(final @NotNull String string) { // Getting the list of all blocked commands. final List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); - // Iterating over list of blocked commands... + // Iterating over all elements of the component. for (final String blockedCommand : blockedCommands) { // Transforming the command to a base command with trailed whitespaces and slashes. This also removes namespaced part from the beginning of the command. final String transformedBaseCommand = blockedCommand.replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", ""); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java index 549967dd..3230f0e7 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/ServerCommandCMD.java @@ -195,7 +195,7 @@ public Collection suggestCommand(final CommandContext con private boolean hasBlockedCommands(final @NotNull String string) { // Getting the list of all blocked commands. final List blockedCommands = FancyNpcs.getInstance().getFancyNpcConfig().getBlockedCommands(); - // Iterating over list of blocked commands... + // Iterating over all elements of the component. for (final String blockedCommand : blockedCommands) { // Transforming the command to a base command with trailed whitespaces and slashes. This also removes namespaced part from the beginning of the command. final String transformedBaseCommand = blockedCommand.replace('/', ' ').strip().split(" ")[0].replaceAll(".*?:+", ""); diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java index c229d4b2..60598031 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/TeleportCMD.java @@ -27,9 +27,8 @@ public void onTeleport( translator.translate("npc_teleport_failure_world_not_loaded").send(sender); return; } - // Teleporting... + // Teleporting and sending message to the sender. This operation can occasionally fail. sender.teleportAsync(location).whenComplete((isSuccess, thr) -> { - // Sending message to the sender. translator.translate(isSuccess ? "npc_teleport_success" : "npc_teleport_failure_exception").replace("npc", npc.getData().getName()).send(sender); // Printing stacktrace to the console in case an exception occurred. if (thr != null) diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 972ba560..855f3170 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -147,7 +147,7 @@ messages: npc_create_failure_must_specify_world: "› {errorColor}You must specify {warningColor}--world{errorColor} flag when running this command from the console." # Commands (npc displayname) - npc_displayname_set_name: "NPC {warningColor}{npc} is now using {name} as their display name." + npc_displayname_set_name: "NPC {warningColor}{npc} is now using {name} as their display name." npc_displayname_set_empty: "NPC {warningColor}{npc} is no longer showing display name." # Commands (npc equipment) @@ -175,7 +175,7 @@ messages: - "Unique, permanent identifier of the NPC.'><#848484>Identifier: Click to copy identifier to clipboard.'>{warningColor}{id_short}" - "Identifier of player who created this NPC.'>Creator: Click to copy creator to clipboard.'>{warningColor}{creator_short}" - "Name of the NPC, used in commands and displayed above their head if display name is not set.'><#848484>Name: {warningColor}{name}" - - "Display name of the NPC, displayed above their head.'>Display Name: {displayname}" + - "Display name of the NPC, displayed above their head.'>Display Name: {displayname}" - "Entity type of the NPC.'><#848484>Type: {warningColor}{type}" - "Current location of the NPC.'>Location: Click to copy location to clipboard.'>{warningColor}{location_x}, {warningColor}{location_y}, {warningColor}{location_z} in {warningColor}{world}" - "Glowing state of the NPC. Can be a {warningColor}color or {errorColor}disabled.'><#848484>Glow: {glow}" @@ -185,11 +185,11 @@ messages: - "Skin mirroring state of the NPC.. Can be {successColor}true or {errorColor}false.'><#848484>Skin Mirroring: {warningColor}{is_skin_mirror}" - "Cooldown between interactions.'>Interaction Cooldown: {warningColor}{interaction_cooldown}" - "" - - "Click here to browse equipment.'><#848484>Equipment: {warningColor}[Click Here]" - - "Click here to browse attributes.'>Attributes: {warningColor}[Click Here]" - - "Click here to browse list of messages.'><#848484>Messages: {warningColor}[Click Here] ({messages_total} total)" - - "Click here to browse list of player commands.'>Player Commands: {warningColor}[Click Here] ({player_commands_total} total)" - - "Click here to browse list of server commands.'><#848484>Server Commands: {warningColor}[Click Here] ({server_commands_total} total)" + - "Click here to browse equipment.'><#848484>Equipment: {warningColor}[Click Here]" + - "Click here to browse attributes.'>Attributes: {warningColor}[Click Here]" + - "Click here to browse list of messages.'><#848484>Messages: {warningColor}[Click Here] ({messages_total} total)" + - "Click here to browse list of player commands.'>Player Commands: {warningColor}[Click Here] ({player_commands_total} total)" + - "Click here to browse list of server commands.'><#848484>Server Commands: {warningColor}[Click Here] ({server_commands_total} total)" - "" - "› {primaryColor}Can't find what you're looking for?" - "Open the chat window to see all information." From 802795910a4e151cb6c04504a2ec4401843b09c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Sun, 19 May 2024 22:49:52 +0200 Subject: [PATCH 90/94] some help stuff (not finished) --- src/main/resources/languages/en.yml | 52 +++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index 855f3170..a50528bb 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -117,13 +117,51 @@ messages: npc_help_page_header: "------------- {primaryColor}FancyNpcs Commands ({primaryColor}{page}/{primaryColor}{max_page}) --------------" npc_help_page_footer: "----------- Click {primaryColor}here to open documentation -----------" npc_help_contents: - - "Creates a new NPC at your location.'>{primaryColor}/npc create {secondaryColor}(npc) <#6B1216>[--type] [--position] [--world]" - - "Removes specified NPC.'>{primaryColor}/npc remove {secondaryColor}(npc)" - - "Copies/clones specified NPC.'>{primaryColor}/npc copy {secondaryColor}(npc) (new_name)" - - "Lists all NPCs in all worlds. Filters can be applied.'>{primaryColor}/npc list <#6B1216>[--type] [--sort]" - - "Lists all NPCs in player''s world. Filters can be applied.'>{primaryColor}/npc nearby <#6B1216>[--radius] [--type] [--sort]" - - "Changes skin of the NPC.'>{primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url)" - # TO-DO: ... + #- "Creates a new NPC at your location.'>{primaryColor}/npc create {secondaryColor}(npc) <#6B1216>[--type] [--position] [--world]" + #- "Removes specified NPC.'>{primaryColor}/npc remove {secondaryColor}(npc)" + #- "Copies/clones specified NPC.'>{primaryColor}/npc copy {secondaryColor}(npc) (new_name)" + #- "Lists all NPCs in all worlds. Filters can be applied.'>{primaryColor}/npc list <#6B1216>[--type] [--sort]" + #- "Lists all NPCs in player''s world. Filters can be applied.'>{primaryColor}/npc nearby <#6B1216>[--radius] [--type] [--sort]" + #- "Changes skin of the NPC.'>{primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url)" + + - "Sets an attribute of the NPC.'>{primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}set {secondaryColor}(attribute) (value)" + - "Lists all modified attributes of the NPC.'>{primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}list" + - "Changes whether the NPC can collide with other entities.'>{primaryColor}/npc collidable {secondaryColor}(npc) [state]" + - "Copies (duplicates) specified NPC.'>{primaryColor}/npc copy {secondaryColor}(npc) (new_name)" + - "Creates a new NPC. Can be customized with flags.'>{primaryColor}/npc create {secondaryColor}(npc) [--type] [--location] [--world]" + - "Changes display-name of the NPC. Supports MiniMessage formatting.'>{primaryColor}/npc displayname {secondaryColor}(npc) (name)" + - "Sets equipment slot of the NPC to item currently held in main hand, none or a specific item type.'>{primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}set {secondaryColor}(slot) (@hand | @none | item)" + - "Clears all equipment slots of the NPC.'>{primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}clear" + - "Lists all equipment of the NPC.'>{primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}list" + - "Changes glowing state and color of the NPC.'>{primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color)" + - "Shows information about specified NPC.'>{primaryColor}/npc info {secondaryColor}(npc)" + - "Changes duration between interactions (cooldown) of the NPC.'>{primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (disabled | time)" + - "Lists all NPCs in all worlds. Can be filtered and sorted.'>{primaryColor}/npc list {secondaryColor}[filters...]" + - "Messages are shown to player upon interaction with the NPC.Adds a new message to the list.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}add {secondaryColor}(@none | message)" + - "Messages are shown to player upon interaction with the NPC.Removes message at a specified index.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + - "Messages are shown to player upon interaction with the NPC.Changes message at a specified index.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (@none | message)" + - "Messages are shown to player upon interaction with the NPC.Clears all attached messages.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}clear" + - "Messages are shown to player upon interaction with the NPC.Lists all attached messages.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}list" + - "Messages are shown to player upon interaction with the NPC.Changes whether messages in the list should be sent randomly.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}send_randomly [state]" + - "'>{primaryColor}/npc move_here {secondaryColor}(npc)" + - "'>{primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" + - "'>{primaryColor}/npc nearby {secondaryColor}[filters...]" + - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" + - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" + - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}clear" + - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}list" + - "'>{primaryColor}/npc remove {secondaryColor}(npc)" + - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" + - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" + - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}clear" + - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}list" + - "'>{primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" + - "'>{primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" + - "'>{primaryColor}/npc teleport {secondaryColor}(npc)" + - "'>{primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" + - "'>{primaryColor}/npc type {secondaryColor}(npc) (type)" # Commands (npc attribute) npc_attribute_set: "Attribute {warningColor}{attribute} has been set to {warningColor}{value}." From 2c318276842540507a5e6276a42929811189f027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Mon, 20 May 2024 18:10:47 +0200 Subject: [PATCH 91/94] fix help pagination, add remaining help entries --- .../fancynpcs/commands/npc/HelpCMD.java | 2 +- src/main/resources/languages/en.yml | 64 ++++++++----------- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java index 10199741..4612b845 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java @@ -31,7 +31,7 @@ public void onHelp( // Getting the (full) help contents. final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); // Calculating max page number. - final int maxPage = Math.max(1, contents.getRawMessages().size() / 6); + final int maxPage = (int) Math.ceil(Math.max(1, contents.getRawMessages().size() - 1) / 6F); // Getting the requested page. Defaults to 1 for invalid input and is capped by number of the last page. final int finalPage = Math.min(page != null ? page : 1, maxPage); // Getting help contents for requested page, or defaulting to 1. diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/en.yml index a50528bb..267a7d27 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/en.yml @@ -88,6 +88,7 @@ messages: npc_message_add: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}add {secondaryColor}(@none | message)" npc_message_remove: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" npc_message_set: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (@none | message)" + npc_message_send_randomly: "Syntax: {primaryColor}/npc message {secondaryColor}(npc) {primaryColor}send_randomly {secondaryColor}[state]" npc_move_here: "Syntax: {primaryColor}/npc move_here {secondaryColor}(npc)" npc_move_to: "Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" npc_nearby: "Syntax: {primaryColor}/npc nearby {secondaryColor}[filters...]" @@ -117,51 +118,44 @@ messages: npc_help_page_header: "------------- {primaryColor}FancyNpcs Commands ({primaryColor}{page}/{primaryColor}{max_page}) --------------" npc_help_page_footer: "----------- Click {primaryColor}here to open documentation -----------" npc_help_contents: - #- "Creates a new NPC at your location.'>{primaryColor}/npc create {secondaryColor}(npc) <#6B1216>[--type] [--position] [--world]" - #- "Removes specified NPC.'>{primaryColor}/npc remove {secondaryColor}(npc)" - #- "Copies/clones specified NPC.'>{primaryColor}/npc copy {secondaryColor}(npc) (new_name)" - #- "Lists all NPCs in all worlds. Filters can be applied.'>{primaryColor}/npc list <#6B1216>[--type] [--sort]" - #- "Lists all NPCs in player''s world. Filters can be applied.'>{primaryColor}/npc nearby <#6B1216>[--radius] [--type] [--sort]" - #- "Changes skin of the NPC.'>{primaryColor}/npc skin {secondaryColor}(@none | @mirror | name | url)" - - "Sets an attribute of the NPC.'>{primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}set {secondaryColor}(attribute) (value)" - "Lists all modified attributes of the NPC.'>{primaryColor}/npc attribute {secondaryColor}(npc) {primaryColor}list" - "Changes whether the NPC can collide with other entities.'>{primaryColor}/npc collidable {secondaryColor}(npc) [state]" - "Copies (duplicates) specified NPC.'>{primaryColor}/npc copy {secondaryColor}(npc) (new_name)" - "Creates a new NPC. Can be customized with flags.'>{primaryColor}/npc create {secondaryColor}(npc) [--type] [--location] [--world]" - - "Changes display-name of the NPC. Supports MiniMessage formatting.'>{primaryColor}/npc displayname {secondaryColor}(npc) (name)" + - "Changes displayname of the NPC. Supports MiniMessage, PlaceholderAPI and MiniPlaceholders.'>{primaryColor}/npc displayname {secondaryColor}(npc) (name)" - "Sets equipment slot of the NPC to item currently held in main hand, none or a specific item type.'>{primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}set {secondaryColor}(slot) (@hand | @none | item)" - "Clears all equipment slots of the NPC.'>{primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}clear" - "Lists all equipment of the NPC.'>{primaryColor}/npc equipment {secondaryColor}(npc) {primaryColor}list" - "Changes glowing state and color of the NPC.'>{primaryColor}/npc glowing {secondaryColor}(npc) (disabled | color)" - "Shows information about specified NPC.'>{primaryColor}/npc info {secondaryColor}(npc)" - "Changes duration between interactions (cooldown) of the NPC.'>{primaryColor}/npc interaction_cooldown {secondaryColor}(npc) (disabled | time)" - - "Lists all NPCs in all worlds. Can be filtered and sorted.'>{primaryColor}/npc list {secondaryColor}[filters...]" - - "Messages are shown to player upon interaction with the NPC.Adds a new message to the list.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}add {secondaryColor}(@none | message)" - - "Messages are shown to player upon interaction with the NPC.Removes message at a specified index.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" - - "Messages are shown to player upon interaction with the NPC.Changes message at a specified index.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (@none | message)" - - "Messages are shown to player upon interaction with the NPC.Clears all attached messages.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}clear" - - "Messages are shown to player upon interaction with the NPC.Lists all attached messages.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}list" - - "Messages are shown to player upon interaction with the NPC.Changes whether messages in the list should be sent randomly.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}send_randomly [state]" - - "'>{primaryColor}/npc move_here {secondaryColor}(npc)" - - "'>{primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" - - "'>{primaryColor}/npc nearby {secondaryColor}[filters...]" - - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" - - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" - - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" - - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}clear" - - "'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}list" - - "'>{primaryColor}/npc remove {secondaryColor}(npc)" - - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" - - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" - - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" - - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}clear" - - "'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}list" - - "'>{primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" - - "'>{primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" - - "'>{primaryColor}/npc teleport {secondaryColor}(npc)" - - "'>{primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" - - "'>{primaryColor}/npc type {secondaryColor}(npc) (type)" + - "Lists all NPCs in all worlds. Can be filtered and sorted.'>{primaryColor}/npc list {secondaryColor}[--type] [--sort]" + - "Adds a new message to the list. Supports MiniMessage, PlaceholderAPI and MiniPlaceholders.Messages are shown to the player upon interaction with the NPC.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}add {secondaryColor}(@none | message)" + - "Removes message at a specified index.Messages are shown to the player upon interaction with the NPC.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + - "Changes message at a specified index. Supports MiniMessage, PlaceholderAPI and MiniPlaceholders.Messages are shown to the player upon interaction with the NPC.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (@none | message)" + - "Clears all attached messages.Messages are shown to the player upon interaction with the NPC.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}clear" + - "Lists all attached messages.Messages are shown to the player upon interaction with the NPC.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}list" + - "Changes whether messages in the list should be sent randomly.Messages are shown to the player upon interaction with the NPC.'>{primaryColor}/npc message {secondaryColor}(npc) {primaryColor}send_randomly {secondaryColor}[state]" + - "Teleports specified NPC to your location.'>{primaryColor}/npc move_here {secondaryColor}(npc)" + - "Teleports NPC to specified location.'>{primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]" + - "Lists all NPCs in your world. Can be filtered and sorted.'>{primaryColor}/npc nearby {secondaryColor}[--radius] [--type] [--sort]" + - "Adds a new command to the list. Supports PlaceholderAPI and MiniPlaceholders.Commands are executed by the player upon interaction with the NPC.'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" + - "Removes command at specified index.Commands are executed by the player upon interaction with the NPC.'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + - "Changes command at specified index. Supports PlaceholderAPI and MiniPlaceholders.Commands are executed by the player upon interaction with the NPC.'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" + - "Clears all attached player commands.Commands are executed by the player upon interaction with the NPC.'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}clear" + - "Lists all attached player commands.Commands are executed by the player upon interaction with the NPC.'>{primaryColor}/npc player_command {secondaryColor}(npc) {primaryColor}list" + - "Removes (deletes) specified NPC.'>{primaryColor}/npc remove {secondaryColor}(npc)" + - "Adds a new command to the list.Commands are executed by the console upon interaction with the NPC.'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}add {secondaryColor}(command)" + - "Removes command at specified index.Commands are executed by the console upon interaction with the NPC.'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}remove {secondaryColor}(number)" + - "Changes command at specified index.Commands are executed by the console upon interaction with the NPC.'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}set {secondaryColor}(number) (command)" + - "Clears all attached server commands.Commands are executed by the console upon interaction with the NPC.'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}clear" + - "Lists all attached server commands.Commands are executed by the console upon interaction with the NPC.'>{primaryColor}/npc server_command {secondaryColor}(npc) {primaryColor}list" + - "Changes whether the NPC is shown in the player-list. This works only on NPCs of PLAYER type.{errorColor}Re-connecting to the server might be required for changes to take effect.'>{primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)" + - "Changes skin of the NPC.{warningColor}@none - removes the skin{warningColor}@mirror - mirrors player skin{warningColor}(name) - name of any player{warningColor}(url) - url of the skin texture'>{primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url)" + - "Teleports you to the specified NPC.'>{primaryColor}/npc teleport {secondaryColor}(npc)" + - "Changes whether the NPC should turn to the player when in range.'>{primaryColor}/npc turn_to_player {secondaryColor}(npc) (state)" + - "Changes the type of the NPC.'>{primaryColor}/npc type {secondaryColor}(npc) (type)" # Commands (npc attribute) npc_attribute_set: "Attribute {warningColor}{attribute} has been set to {warningColor}{value}." @@ -327,5 +321,3 @@ messages: # Commands (npc type) npc_type_success: "NPC {warningColor}{npc} type has been changed to {warningColor}{type}." - - From 80903ac616813e40125d0c973389577037620022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Mon, 20 May 2024 18:34:57 +0200 Subject: [PATCH 92/94] fix help pagination (again) --- .../oliver/fancynpcs/commands/npc/HelpCMD.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java b/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java index 4612b845..42d321ce 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java +++ b/src/main/java/de/oliver/fancynpcs/commands/npc/HelpCMD.java @@ -6,6 +6,7 @@ import org.bukkit.command.CommandSender; import org.incendo.cloud.annotations.Argument; import org.incendo.cloud.annotations.Command; +import org.incendo.cloud.annotations.Default; import org.incendo.cloud.annotations.Permission; import org.incendo.cloud.annotations.suggestion.Suggestions; import org.incendo.cloud.context.CommandContext; @@ -15,7 +16,6 @@ import java.util.List; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public enum HelpCMD { INSTANCE; // SINGLETON @@ -26,28 +26,24 @@ public enum HelpCMD { @Permission("fancynpcs.command.npc") public void onHelp( final @NotNull CommandSender sender, - final @Nullable @Argument(suggestions = "HelpCMD/page") Integer page + final @Argument(suggestions = "HelpCMD/page") @Default("1") int page ) { // Getting the (full) help contents. final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); // Calculating max page number. - final int maxPage = (int) Math.ceil(Math.max(1, contents.getRawMessages().size() - 1) / 6F); + final int maxPage = (int) Math.ceil(contents.getRawMessages().size() / 6F); // Getting the requested page. Defaults to 1 for invalid input and is capped by number of the last page. - final int finalPage = Math.min(page != null ? page : 1, maxPage); - // Getting help contents for requested page, or defaulting to 1. - final MultiMessage requestedContents = contents.page(finalPage, 6); - // Sending help header to the sender. + final int finalPage = Math.clamp(page, 1, maxPage); + // Sending help contents to the sender. translator.translate("npc_help_page_header").replace("page", String.valueOf(finalPage)).replace("max_page", String.valueOf(maxPage)).send(sender); - // Sending (requested) help contents to the sender. - requestedContents.send(sender); - // Sending help footer to the sender. + contents.page(finalPage, 6).send(sender); translator.translate("npc_help_page_footer").replace("page", String.valueOf(finalPage)).replace("max_page", String.valueOf(maxPage)).send(sender); } /* PARSERS AND SUGGESTIONS */ @Suggestions("HelpCMD/page") - public List suggestions(final CommandContext context, final CommandInput input) { + public List suggestPage(final CommandContext context, final CommandInput input) { // Getting the (full) help contents. final MultiMessage contents = (MultiMessage) translator.translate("npc_help_contents"); // Calculating max page number. From de8bfe8767eccfdab7b1fa05d370e7d394547bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Thu, 23 May 2024 19:18:44 +0200 Subject: [PATCH 93/94] FancyLib 1.0.24, use release versions of cloud instead of snapshots --- .../oliver/fancynpcs/api/FancyNpcsPlugin.java | 3 - gradle.properties | 6 +- .../java/de/oliver/fancynpcs/FancyNpcs.java | 29 ------ .../oliver/fancynpcs/FancyNpcsConfigImpl.java | 2 +- .../commands/CloudCommandManager.java | 24 ++--- src/main/resources/lang.yml | 96 ------------------- .../languages/{en.yml => default.yml} | 13 ++- 7 files changed, 29 insertions(+), 144 deletions(-) delete mode 100644 src/main/resources/lang.yml rename src/main/resources/languages/{en.yml => default.yml} (98%) diff --git a/api/src/main/java/de/oliver/fancynpcs/api/FancyNpcsPlugin.java b/api/src/main/java/de/oliver/fancynpcs/api/FancyNpcsPlugin.java index d9b5ec06..9d44ac12 100644 --- a/api/src/main/java/de/oliver/fancynpcs/api/FancyNpcsPlugin.java +++ b/api/src/main/java/de/oliver/fancynpcs/api/FancyNpcsPlugin.java @@ -1,6 +1,5 @@ package de.oliver.fancynpcs.api; -import de.oliver.fancylib.LanguageConfig; import de.oliver.fancylib.serverSoftware.schedulers.FancyScheduler; import de.oliver.fancylib.translations.Translator; import org.bukkit.Bukkit; @@ -33,7 +32,5 @@ static FancyNpcsPlugin get() { AttributeManager getAttributeManager(); - LanguageConfig getLanguageConfig(); - Translator getTranslator(); } diff --git a/gradle.properties b/gradle.properties index 8c71dead..5070d8e7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ minecraftVersion=1.20.6 -fancyLibVersion=1.0.22 +fancyLibVersion=1.0.24 plotsquaredVersion=7.2.0 chatcolorhandlerVersion=v2.5.3 cloudCoreVersion=2.0.0-rc.1 -cloudPaperVersion=2.0.0-SNAPSHOT -cloudAnnotationsVersion=2.0.0-SNAPSHOT \ No newline at end of file +cloudPaperVersion=2.0.0-beta.7 +cloudAnnotationsVersion=2.0.0-rc.1 \ No newline at end of file diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java index 46e104b2..c15b6071 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcs.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcs.java @@ -1,8 +1,6 @@ package de.oliver.fancynpcs; import de.oliver.fancylib.FancyLib; -import de.oliver.fancylib.FileUtils; -import de.oliver.fancylib.LanguageConfig; import de.oliver.fancylib.Metrics; import de.oliver.fancylib.VersionConfig; import de.oliver.fancylib.featureFlags.FeatureFlag; @@ -38,9 +36,6 @@ import de.oliver.fancynpcs.v1_20_6.Npc_1_20_6; import org.apache.maven.artifact.versioning.ComparableVersion; import org.bukkit.Bukkit; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; @@ -54,7 +49,6 @@ public class FancyNpcs extends JavaPlugin implements FancyNpcsPlugin { private static FancyNpcs instance; private final FancyScheduler scheduler; private final FancyNpcsConfigImpl config; - private final LanguageConfig languageConfig; private final VersionConfig versionConfig; private final FeatureFlagConfig featureFlagConfig; private final VersionFetcher versionFetcher; @@ -74,7 +68,6 @@ public FancyNpcs() { : new BukkitScheduler(instance); this.config = new FancyNpcsConfigImpl(); this.versionFetcher = new MasterVersionFetcher(getName()); - this.languageConfig = new LanguageConfig(this); this.versionConfig = new VersionConfig(this, versionFetcher); this.featureFlagConfig = new FeatureFlagConfig(this); } @@ -114,8 +107,6 @@ public void onLoad() { pluginManager.disablePlugin(this); return; } - - new FileUtils().saveFile(this, "lang.yml"); } @Override @@ -132,22 +123,6 @@ public void onEnable() { attributeManager = new AttributeManagerImpl(); - // Load language file - String defaultLang = new FileUtils().readResource("lang.yml"); - if (defaultLang != null) { - // Update language file - try { - FileConfiguration defaultLangConfig = new YamlConfiguration(); - defaultLangConfig.loadFromString(defaultLang); - for (String key : defaultLangConfig.getConfigurationSection("messages").getKeys(false)) { - languageConfig.addDefaultLang(key, defaultLangConfig.getString("messages." + key)); - } - } catch (InvalidConfigurationException e) { - e.printStackTrace(); - } - } - languageConfig.load(); - textConfig = new TextConfig("#E33239", "#AD1D23", "#81E366", "#E3CA66", "#E36666", ""); translator = new Translator(textConfig); translator.loadLanguages(getDataFolder().getAbsolutePath()); @@ -268,10 +243,6 @@ public FancyNpcsConfigImpl getFancyNpcConfig() { return config; } - public LanguageConfig getLanguageConfig() { - return languageConfig; - } - public VersionConfig getVersionConfig() { return versionConfig; } diff --git a/src/main/java/de/oliver/fancynpcs/FancyNpcsConfigImpl.java b/src/main/java/de/oliver/fancynpcs/FancyNpcsConfigImpl.java index 7b71b022..ca19e7b2 100644 --- a/src/main/java/de/oliver/fancynpcs/FancyNpcsConfigImpl.java +++ b/src/main/java/de/oliver/fancynpcs/FancyNpcsConfigImpl.java @@ -65,7 +65,7 @@ public void reload() { FancyNpcs.getInstance().reloadConfig(); FileConfiguration config = FancyNpcs.getInstance().getConfig(); - language = (String) ConfigHelper.getOrDefault(config, "language", "english"); + language = (String) ConfigHelper.getOrDefault(config, "language", "default"); config.setInlineComments("language", List.of("Language to use for translatable messages.")); disabledInteractionCooldownMessage = (boolean) ConfigHelper.getOrDefault(config, "disable_interaction_cooldown_message", false); diff --git a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java index ee89dfac..be57289f 100644 --- a/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java +++ b/src/main/java/de/oliver/fancynpcs/commands/CloudCommandManager.java @@ -47,10 +47,12 @@ import org.incendo.cloud.exception.parsing.NumberParseException; import org.incendo.cloud.exception.parsing.ParserException; import org.incendo.cloud.execution.ExecutionCoordinator; -import org.incendo.cloud.paper.LegacyPaperCommandManager; +import org.incendo.cloud.paper.PaperCommandManager; import org.incendo.cloud.parser.standard.BooleanParser; import org.incendo.cloud.parser.standard.EnumParser; +import java.util.Optional; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -64,13 +66,13 @@ public final class CloudCommandManager { private final @NotNull FancyNpcs plugin; - private final @NotNull LegacyPaperCommandManager commandManager; + private final @NotNull PaperCommandManager commandManager; private final @NotNull AnnotationParser annotationParser; public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrigadier) { this.plugin = plugin; - // Creating instance of Cloud's LegacyPaperCommandManager, which is used for anything command-related. - this.commandManager = LegacyPaperCommandManager.createNative(plugin, ExecutionCoordinator.simpleCoordinator()); + // Creating instance of Cloud's PaperCommandManager, which is used for anything command-related. + this.commandManager = PaperCommandManager.createNative(plugin, ExecutionCoordinator.simpleCoordinator()); // Registering Brigadier, if available. if (isBrigadier && commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) commandManager.registerBrigadier(); @@ -79,7 +81,7 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig } /** - * Registers arguments (parsers and suggestion providers) to the {@link LegacyPaperCommandManager}. + * Registers arguments (parsers and suggestion providers) to the {@link PaperCommandManager}. */ public @NotNull CloudCommandManager registerArguments() { annotationParser.parse(NpcArgument.INSTANCE); @@ -89,7 +91,7 @@ public CloudCommandManager(final @NotNull FancyNpcs plugin, final boolean isBrig } /** - * Registers exception handlers to the {@link LegacyPaperCommandManager}. + * Registers exception handlers to the {@link PaperCommandManager}. */ public @NotNull CloudCommandManager registerExceptionHandlers() { final Translator translator = plugin.getTranslator(); @@ -165,8 +167,8 @@ else if (exceptionContext.exception().enumClass() == GlowingColor.class) // Trimming input (last character ends up being blank) and replacing whitespaces with underscores, as that's how translations are defined inside the language file. final String translationKey = translationKeyBuilder.toString().trim().replace(' ', '_'); // Getting the message, it's not finished as there we need to handle fallback language etc. - // Currently, Translator#translate(String) throws NPE on invalid message and that's why we're not using it here. - final @Nullable Message message = plugin.getTranslator().getSelectedLanguage().getMessage(translationKey); + final @Nullable Message message = Optional.ofNullable(plugin.getTranslator().getSelectedLanguage().getMessage(translationKey)) + .orElse(plugin.getTranslator().getFallbackLanguage().getMessage(translationKey)); // "Fall-backing" to generic syntax error, if no specialized syntax message has been defined in the language file. if (message == null) { plugin.getTranslator().translate("command_invalid_syntax_generic") @@ -181,7 +183,7 @@ else if (exceptionContext.exception().enumClass() == GlowingColor.class) } /** - * Registers plugin commands to the {@link LegacyPaperCommandManager}. + * Registers plugin commands to the {@link PaperCommandManager}. */ public @NotNull CloudCommandManager registerCommands() { annotationParser.parse(AttributeCMD.INSTANCE); @@ -214,9 +216,9 @@ else if (exceptionContext.exception().enumClass() == GlowingColor.class) } /** - * Returns the internal {@link LegacyPaperCommandManager} associated with this instance of {@link CloudCommandManager}. + * Returns the internal {@link PaperCommandManager} associated with this instance of {@link CloudCommandManager}. */ - public @NotNull LegacyPaperCommandManager getCommandManager() { + public @NotNull PaperCommandManager getCommandManager() { return commandManager; } diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml deleted file mode 100644 index 83e2f3b0..00000000 --- a/src/main/resources/lang.yml +++ /dev/null @@ -1,96 +0,0 @@ -messages: - reloaded-config: Reloaded the config - saved-npcs: Saved all NPCs - fancynpcs-syntax: /FancyNpcs - illegal-command: This command is not allowed to use in playerCommand, serverCommand and message - only-players: Only players can execute this command - no-permission-subcommand: You don't have permission for this subcommand - wrong-usage: 'Wrong usage: /npc help' - could-not-parse-number: Could not parse number - world-not-found: Could not find world - npc-not-found: This feature is only available for player-type NPCs. - npc-must-be-player: This feature is only available for player-type NPCs. - on-interaction-cooldown: You need to wait {time} seconds uasdsssssssssssssssssssssssssssssssssssssssssssssssssss - npc-command-help-header: 'Commands for FancyNpcs plugin: ({page}/{max_pages})' - npc-command-help-footer: Full command reference available here. - npc-command-help-create: /npc create (npc) - Creates a new NPC at your location. - npc-command-help-remove: /npc remove (npc) - Removes specified NPC. - npc-command-help-copy: /npc copy (npc) (new_name) - Copies/clones specified NPC. - npc-command-help-list: /npc list - Lists all loaded NPCs. - npc-command-help-skin: /npc skin (skin) - Changes skin of an NPC. - npc-command-help-type: /npc type (npc) (type) - Changes entity type of an NPC. - npc-command-help-moveHere: /npc movehere (npc) - Teleports NPC to your location. - npc-command-help-teleport: /npc teleport (npc) (x) (y) (z) [world] - Teleports NPC. - npc-command-help-displayName: /npc displayname (npc) (name) - Changes NPC's displayname. - npc-command-help-equipment: /npc equipment (npc) (slot) - Changes equipement of an NPC. - npc-command-help-message: /npc message (npc) (...) - Changes click message(s). - npc-command-help-playerCommand: /npc playerCommand (npc) (...) - Changes click command(s). - npc-command-help-serverCommand: /npc serverCommand (npc) (...) - Changes click command(s). - npc-command-help-showInTab: /npc showInTab (npc) (state) - Changes tab-list visibility. - npc-command-help-glowing: /npc glowing (npc) (state) - Changes glowing effect state. - npc-command-help-glowingColor: /npc glowingColor (npc) (color) - Changes glowing color. - npc-command-help-collidable: /npc collidable (npc) (state) - Changes collidable state. - npc-command-help-turnToPlayer: /npc turnToPlayer (npc) (state) - Changes turning state. - npc-command-help-attribute: /npc attribute (npc) (attr) (value) - Sets entity attribute. - npc-command-help-interactionCooldown: /npc interactionCooldown (npc) (sec) - Sets inter. cooldown. - npc-command-help-mirrorSkin: /npc mirrorSkin (npc) (state) - Changes skin mirroring state. - npc-command-list-header: All NPCs: # todo - npc-command-list-no-npcs: No NPCs found, use /npc create (npc) to create one. - npc-command-list-tp-hover: Click to teleport'> - {name} ({x}/{y}/{z}) - npc-command-create-name-already-exists: NPC named {npc} already exists. - npc-command-create-created: NPC named {npc} has been created. - npc-command-create-cancelled: Creation of NPC named {npc} has been cancelled by the API. - npc-command-collidable-true: NPC named {npc} is now collidable. - npc-command-collidable-false: NPC named {npc} is no longer collidable. - npc-command-copy-success: NPC named {npc} has been copied to {new_npc}. - npc-command-copy-cancelled: Copying of NPC named {npc} has been cancelled by the API. - npc-command-remove-removed: NPC named {npc} has been removed. - npc-command-remove-cancelled: Removal of NPC named {npc} has been cancelled by the API. - npc-command-moveHere-moved: NPC named {npc} has been moved to your location. - npc-command-message-updated: NPC named {npc} has had their message(s) updated. - npc-command-message-removed: NPC named {npc} has had their message(s) removed. - npc-command-message-invalid: N/A - npc-command-message-invalid-index: Specified value {input} is not a valid index. - npc-command-message-cancelled: N/A - npc-command-message-sendMessagesRandomly-true: NPC named {npc} is now sending messages randomly. - npc-command-message-sendMessagesRandomly-false: NPC named {npc} is no longer sending messages randomly. - npc-command-skin-invalid: Specified value {input} is not a valid player name or URL. - npc-command-skin-failed_header: 'Could not load skin. Possible causes:' # todo - npc-command-skin-failed_url: ' - Invalid URL (check the url)' # todo - npc-command-skin-failed_limited: ' - Rate limit reached (try again later)' # todo - npc-command-skin-updated: NPC named {npc} has had their skin updated. - npc-command-displayName-updated: NPC named {npc} has had their display-name updated. - npc-command-equipment-invalid-slot: Specified value {input} is not a valid equipment slot. - npc-command-equipment-updated: NPC named {npc} has had their equipment updated. - npc-command-serverCommand-updated: NPC named {npc} has had their command(s) updated. - npc-command-playercommand-updated: NPC named {npc} has had their command(s) updated. - npc-command-playercommand-removed: NPC named {npc} has had their command(s) removed. - npc-command-playercommand-invalid: N/A - npc-command-playercommand-invalid-index: Specified value {input} is not a valid index. - npc-command-playercommand-cancelled: N/A - - - npc-command-showInTab-invalid-argument: Specified value {input} is not a valid boolean. - npc-command-showInTab-same: N/A - npc-command-showInTab-true: NPC named {npc} is now shown in player-list. - npc-command-showInTab-false: NPC named {npc} is no longer shown in player-list. - npc-command-glowing-true: NPC named {npc} is now glowing. - npc-command-glowing-false: NPC named {npc} is no longer glowing. - npc-command-glowingColor-invalid: Specified value {input} is not a valid color. - npc-command-glowingColor-updated: NPC named {npc} has had their glowing color updated. - npc-command-turnToPlayer-true: NPC named {npc} is now turning to player. - npc-command-turnToPlayer-false: NPC named {npc} is no longer turning to player. - npc-command-type-invalid: Specified value {input} is not a valid entity type. - npc-command-type-updated: NPC named {npc} has had their type set to {type}. - npc-command-attribute-attribute-not-found: Could not find attribute - npc-command-attribute-wrong-entity-type: This attribute can not be applied to this entity type - npc-command-attribute-invalid-value: Invalid attribute value - npc-command-attribute-success: Attribute {attribute} set to {value} - - npc-command-interactioncooldown-updated: NPC named {npc} has had their interaction cooldown updated. - - npc-command-teleport-success: You have been teleported to NPC {npc}. - npc-command-mirrorSkin-true: NPC named {npc} is now mirroring player skin. - npc-command-mirrorSkin-false: NPC named {npc} is no longer mirroring player skin. - npc-command-mirrorSkin-cancelled: N/A - npc-command-fix-success: Trying to fix NPC named {npc}... \ No newline at end of file diff --git a/src/main/resources/languages/en.yml b/src/main/resources/languages/default.yml similarity index 98% rename from src/main/resources/languages/en.yml rename to src/main/resources/languages/default.yml index 267a7d27..91f34c42 100644 --- a/src/main/resources/languages/en.yml +++ b/src/main/resources/languages/default.yml @@ -1,4 +1,15 @@ -language_name: english +# ======================================================================== +# THIS FILE IS A TEMPLATE, ANY MODIFICATIONS MADE HERE MAY NOT BE APPLIED. +# ======================================================================== +# HOW TO CREATE CUSTOM LANGUAGE: +# 1. Copy this file and name it eg. "en.yml" +# 2. Change "language_name" property to eg. "english" and update "language" property inside config.yml to match this value. +# 3. Modify contents to your liking. +# 4. Reload the plugin using "/fancynpcs reload" command. +# ======================================================================== + +# Language name. This value can be used to specify "language" property in the config.yml file. +language_name: default # Messages support MiniMessage formatting: https://docs.advntr.dev/minimessage/format.html messages: From afc64adbd40ac14c464ab109604495e1b1690f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czopek?= <44530932+Grabsky@users.noreply.github.com> Date: Thu, 23 May 2024 19:22:24 +0200 Subject: [PATCH 94/94] remove snapshot repo --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1fe7eec0..dff8557b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,6 @@ allprojects { maven(url = "https://repo.papermc.io/repository/maven-public/") maven(url = "https://repo.fancyplugins.de/releases") maven(url = "https://repo.smrt-1.com/releases") - maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") } }