From 7db0af38b300a5e0f8bbbb92f43d48e6445a2e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Miguel=20Moreno?= Date: Thu, 27 Oct 2022 21:10:33 +0200 Subject: [PATCH 1/5] Fixed bug allowing removals of image items - Updated ItemService to check block permissions also on image removal - Updated ImageCommand class > Fixes #60 --- .../bukkit/plugin/commands/ImageCommand.java | 29 +++++++++++-------- .../bukkit/plugin/renderer/ItemService.java | 10 +++++-- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommand.java b/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommand.java index f7cde62..b64141b 100644 --- a/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommand.java +++ b/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommand.java @@ -232,32 +232,37 @@ public static boolean placeImage( } public static void removeImage(@NotNull Player player) { - ImageRenderer renderer = YamipaPlugin.getInstance().getRenderer(); - - // Ask user to select fake image SelectBlockTask task = new SelectBlockTask(player); task.onSuccess((location, face) -> { - FakeImage image = renderer.getImage(location, face); + FakeImage image = YamipaPlugin.getInstance().getRenderer().getImage(location, face); if (image == null) { ActionBar.send(player, ChatColor.RED + "That is not a valid image!"); return; } - // Check player permissions - for (Location loc : image.getAllLocations()) { - if (!Permissions.canEditBlock(player, loc)) { - ActionBar.send(player, ChatColor.RED + "You're not allowed to remove this image!"); - return; - } } - // Trigger image removal - renderer.removeImage(image); + // Attempt to remove image + removeImage(player, image); }); task.onFailure(() -> ActionBar.send(player, ChatColor.RED + "Image removing canceled")); task.run("Right click an image to continue"); } + public static boolean removeImage(@NotNull Player player, @NotNull FakeImage image) { + // Check block permissions + for (Location loc : image.getAllLocations()) { + if (!Permissions.canEditBlock(player, loc)) { + ActionBar.send(player, ChatColor.RED + "You're not allowed to remove this image!"); + return false; + } + } + + // Trigger image removal + YamipaPlugin.getInstance().getRenderer().removeImage(image); + return true; + } + public static void clearImages( @NotNull CommandSender sender, @NotNull Location origin, diff --git a/src/main/java/io/josemmo/bukkit/plugin/renderer/ItemService.java b/src/main/java/io/josemmo/bukkit/plugin/renderer/ItemService.java index c962cb8..f8a6574 100644 --- a/src/main/java/io/josemmo/bukkit/plugin/renderer/ItemService.java +++ b/src/main/java/io/josemmo/bukkit/plugin/renderer/ItemService.java @@ -3,6 +3,7 @@ import io.josemmo.bukkit.plugin.YamipaPlugin; import io.josemmo.bukkit.plugin.commands.ImageCommand; import io.josemmo.bukkit.plugin.storage.ImageFile; +import io.josemmo.bukkit.plugin.utils.ActionBar; import io.josemmo.bukkit.plugin.utils.InteractWithEntityListener; import org.bukkit.*; import org.bukkit.block.Block; @@ -139,7 +140,7 @@ public void onPlaceItem(@NotNull HangingPlaceEvent event) { ImageFile image = YamipaPlugin.getInstance().getStorage().get(filename); if (image == null) { plugin.warning(player + " tried to place corrupted image item (\"" + filename + "\" no longer exists)"); - player.sendMessage(ChatColor.RED + "Image file \"" + filename + "\" no longer exists"); + ActionBar.send(player, ChatColor.RED + "Image file \"" + filename + "\" no longer exists"); return; } @@ -176,8 +177,11 @@ public boolean onAttack(@NotNull Player player, @NotNull Block block, @NotNull B FakeImage image = renderer.getImage(location, face); if (image == null || !image.hasFlag(FakeImage.FLAG_REMOVABLE)) return true; - // Remove image from renderer - renderer.removeImage(image); + // Attempt to remove image + boolean success = ImageCommand.removeImage(player, image); + if (!success) { + return true; + } // Drop image item if (player.getGameMode() == GameMode.SURVIVAL && image.hasFlag(FakeImage.FLAG_DROPPABLE)) { From 7ee41b3bac1e63cc1fc0fccce4a060c99bcbcd58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Miguel=20Moreno?= Date: Thu, 27 Oct 2022 21:19:48 +0200 Subject: [PATCH 2/5] Improved debug logging of fake images - Updated FakeImage class --- .../java/io/josemmo/bukkit/plugin/renderer/FakeImage.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/io/josemmo/bukkit/plugin/renderer/FakeImage.java b/src/main/java/io/josemmo/bukkit/plugin/renderer/FakeImage.java index b2c0980..fd4458e 100644 --- a/src/main/java/io/josemmo/bukkit/plugin/renderer/FakeImage.java +++ b/src/main/java/io/josemmo/bukkit/plugin/renderer/FakeImage.java @@ -394,6 +394,8 @@ private void load() { * @param player Player instance */ public void spawn(@NotNull Player player) { + plugin.fine("Received request to spawn FakeImage#(" + location + "," + face + ") for Player#" + player.getName()); + // Send pixels if instance is already loaded if (frames != null) { spawnOnceLoaded(player); @@ -447,6 +449,11 @@ public void destroy() { * @param player Player instance or NULL for all observing players */ public void destroy(@Nullable Player player) { + plugin.fine( + "Received request to destroy FakeImage#(" + location + "," + face + ") for " + + (player == null ? "all players" : "Player#" + player.getName()) + ); + // Send packets to destroy item frames if (frames != null) { Set targets = (player == null) ? observingPlayers : Collections.singleton(player); From d8b784ab9a5b9c8e33b0deb849028ef6cea060c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Miguel=20Moreno?= Date: Fri, 28 Oct 2022 18:28:00 +0200 Subject: [PATCH 3/5] New permission system - Updated Command#withPermission() method - Updated ImageCommand and ImageCommandBridge classes - Updated ItemService class - Updated plugin.yml - Updated README.md --- README.md | 35 ++++++----- .../bukkit/plugin/commands/Command.java | 15 +++-- .../bukkit/plugin/commands/ImageCommand.java | 24 +++++--- .../plugin/commands/ImageCommandBridge.java | 48 +++++++-------- .../bukkit/plugin/renderer/ItemService.java | 19 ++++++ src/main/resources/plugin.yml | 58 +++++++++++++++++++ 6 files changed, 150 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 54d43b8..805c1e1 100644 --- a/README.md +++ b/README.md @@ -97,20 +97,29 @@ This plugin adds the following commands: ## Permissions If you want more granular control over the players who can use a particular set of commands, permissions are the way to go! -Yamipa defines the following permissions, each one corresponding to the command with the same name: - -- `yamipa.clear` -- `yamipa.describe` -- `yamipa.download` -- `yamipa.give` -- `yamipa.list` -- `yamipa.place` -- `yamipa.remove` -- `yamipa.top` - -By default, only server OPs have all permissions granted. You can change this by using a permission plugin, +Yamipa defines the following permissions: + +| Command | Default | Description | +|:----------------------------|:-----------:|:----------------------------------------------------------------| +| `yamipa.command.clear` | OPs | To use the `/image clear` command | +| `yamipa.command.describe` | OPs | To use the `/image describe` command | +| `yamipa.command.download` | OPs | To use the `/image download` command | +| `yamipa.command.give` | OPs | To use the `/image give` download | +| `yamipa.command.list` | OPs | To use the `/image list` command | +| `yamipa.command.place` | OPs | To use the `/image place` command | +| `yamipa.command.remove` | OPs | To use the `/image remove` command | +| `yamipa.command.remove.own` | OPs | Same as previous, but only for images placed by the same player | +| `yamipa.command.top` | OPs | To use the `/image top` command | +| `yamipa.item.place` | All players | To place image items | +| `yamipa.item.remove` | All players | To remove image items (that have the `REMO` flag) | +| `yamipa.item.remove.own` | All players | Same as previous, but only for images placed by the same player | + +Note that permissions work **as a tree**. This means that if you grant a permission, by default its children will also +be granted. For instance, you can grant access to all commands with `yamipa.command.*`. +Similarly, if you grant the `yamipa.command.remove`, the permission `yamipa.command.remove.own` will also be granted. + +You can change which roles or players are granted these commands by using a permission plugin, such as [LuckPerms](https://luckperms.net/) or [GroupManager](https://elgarl.github.io/GroupManager/). - Both these plugins have been tested to work with Yamipa, although any similar one should work just fine. ## Protecting areas diff --git a/src/main/java/io/josemmo/bukkit/plugin/commands/Command.java b/src/main/java/io/josemmo/bukkit/plugin/commands/Command.java index 960cd0e..c29b4e8 100644 --- a/src/main/java/io/josemmo/bukkit/plugin/commands/Command.java +++ b/src/main/java/io/josemmo/bukkit/plugin/commands/Command.java @@ -53,11 +53,18 @@ public Command(@NotNull String name) { /** * Add permission requirement to this command - * @param permission Permission name - * @return This instance + * @param permissions Permission names (match as least one) + * @return This instance */ - public @NotNull Command withPermission(@NotNull String permission) { - return withRequirement(sender -> sender.hasPermission(permission)); + public @NotNull Command withPermission(@NotNull String ...permissions) { + return withRequirement(sender -> { + for (String permission : permissions) { + if (sender.hasPermission(permission)) { + return true; + } + } + return false; + }); } /** diff --git a/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommand.java b/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommand.java index b64141b..73c712e 100644 --- a/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommand.java +++ b/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommand.java @@ -35,28 +35,28 @@ public static void showHelp(@NotNull CommandSender s, @NotNull String commandNam String cmd = "/" + commandName; s.sendMessage(ChatColor.BOLD + "=== Yamipa Plugin Help ==="); s.sendMessage(ChatColor.AQUA + cmd + ChatColor.RESET + " - Show this help"); - if (s.hasPermission("yamipa.clear")) { + if (s.hasPermission("yamipa.command.clear") || s.hasPermission("yamipa.clear")) { s.sendMessage(ChatColor.AQUA + cmd + " clear []" + ChatColor.RESET + " - Remove placed images"); } - if (s.hasPermission("yamipa.describe")) { + if (s.hasPermission("yamipa.command.describe") || s.hasPermission("yamipa.describe")) { s.sendMessage(ChatColor.AQUA + cmd + " describe" + ChatColor.RESET + " - Describe placed image"); } - if (s.hasPermission("yamipa.download")) { + if (s.hasPermission("yamipa.command.download") || s.hasPermission("yamipa.download")) { s.sendMessage(ChatColor.AQUA + cmd + " download " + ChatColor.RESET + " - Download image"); } - if (s.hasPermission("yamipa.give")) { + if (s.hasPermission("yamipa.command.give") || s.hasPermission("yamipa.give")) { s.sendMessage(ChatColor.AQUA + cmd + " give

<#> [] []" + ChatColor.RESET + " - Give items"); } - if (s.hasPermission("yamipa.list")) { + if (s.hasPermission("yamipa.command.list") || s.hasPermission("yamipa.list")) { s.sendMessage(ChatColor.AQUA + cmd + " list []" + ChatColor.RESET + " - List all images"); } - if (s.hasPermission("yamipa.place")) { + if (s.hasPermission("yamipa.command.place") || s.hasPermission("yamipa.place")) { s.sendMessage(ChatColor.AQUA + cmd + " place [] []" + ChatColor.RESET + " - Place image"); } - if (s.hasPermission("yamipa.remove")) { + if (s.hasPermission("yamipa.command.remove.own") || s.hasPermission("yamipa.remove")) { s.sendMessage(ChatColor.AQUA + cmd + " remove" + ChatColor.RESET + " - Remove a single placed image"); } - if (s.hasPermission("yamipa.top")) { + if (s.hasPermission("yamipa.command.top") || s.hasPermission("yamipa.top")) { s.sendMessage(ChatColor.AQUA + cmd + " top" + ChatColor.RESET + " - List players with the most images"); } } @@ -240,6 +240,14 @@ public static void removeImage(@NotNull Player player) { return; } + // Check player's command permissions + if ( + !player.getUniqueId().equals(image.getPlacedBy().getUniqueId()) && + !player.hasPermission("yamipa.command.remove") && + !player.hasPermission("yamipa.remove") + ) { + ActionBar.send(player, ChatColor.RED + "You cannot remove images from other players!"); + return; } // Attempt to remove image diff --git a/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommandBridge.java b/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommandBridge.java index c139bb7..ea26427 100644 --- a/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommandBridge.java +++ b/src/main/java/io/josemmo/bukkit/plugin/commands/ImageCommandBridge.java @@ -58,23 +58,23 @@ public static void register(@NotNull YamipaPlugin plugin) { Command root = new Command(COMMAND_NAME); // Help command - root.withRequirement(sender -> - sender.hasPermission("yamipa.*") || - sender.hasPermission("yamipa.clear") || - sender.hasPermission("yamipa.describe") || - sender.hasPermission("yamipa.download") || - sender.hasPermission("yamipa.give") || - sender.hasPermission("yamipa.list") || - sender.hasPermission("yamipa.place") || - sender.hasPermission("yamipa.remove") || - sender.hasPermission("yamipa.top")) + root.withPermission( + "yamipa.command.clear", "yamipa.clear", + "yamipa.command.describe", "yamipa.describe", + "yamipa.command.download", "yamipa.download", + "yamipa.command.give", "yamipa.give", + "yamipa.command.list", "yamipa.list", + "yamipa.command.place", "yamipa.place", + "yamipa.command.remove.own", "yamipa.remove", + "yamipa.command.top", "yamipa.top" + ) .executes((sender, args) -> { ImageCommand.showHelp(sender, (String) args[0]); }); // Clear command root.addSubcommand("clear") - .withPermission("yamipa.clear") + .withPermission("yamipa.command.clear", "yamipa.clear") .withArgument(new IntegerArgument("x")) .withArgument(new IntegerArgument("z")) .withArgument(new WorldArgument("world")) @@ -85,7 +85,7 @@ public static void register(@NotNull YamipaPlugin plugin) { ImageCommand.clearImages(sender, origin, (int) args[4], (OfflinePlayer) args[5]); }); root.addSubcommand("clear") - .withPermission("yamipa.clear") + .withPermission("yamipa.command.clear", "yamipa.clear") .withArgument(new IntegerArgument("x")) .withArgument(new IntegerArgument("z")) .withArgument(new WorldArgument("world")) @@ -97,14 +97,14 @@ public static void register(@NotNull YamipaPlugin plugin) { // Describe command root.addSubcommand("describe") - .withPermission("yamipa.describe") + .withPermission("yamipa.command.describe", "yamipa.describe") .executesPlayer((player, __) -> { ImageCommand.describeImage(player); }); // Download command root.addSubcommand("download") - .withPermission("yamipa.download") + .withPermission("yamipa.command.download", "yamipa.download") .withArgument(new StringArgument("url")) .withArgument(new StringArgument("filename")) .executes((sender, args) -> { @@ -113,7 +113,7 @@ public static void register(@NotNull YamipaPlugin plugin) { // Give subcommand root.addSubcommand("give") - .withPermission("yamipa.give") + .withPermission("yamipa.command.give", "yamipa.give") .withArgument(new OnlinePlayerArgument("player")) .withArgument(new ImageFileArgument("filename")) .withArgument(new IntegerArgument("amount", 1, 64)) @@ -125,7 +125,7 @@ public static void register(@NotNull YamipaPlugin plugin) { (int) args[4], (int) args[5], (int) args[6]); }); root.addSubcommand("give") - .withPermission("yamipa.give") + .withPermission("yamipa.command.give", "yamipa.give") .withArgument(new OnlinePlayerArgument("player")) .withArgument(new ImageFileArgument("filename")) .withArgument(new IntegerArgument("amount", 1, 64)) @@ -136,7 +136,7 @@ public static void register(@NotNull YamipaPlugin plugin) { (int) args[4], (int) args[5], FakeImage.DEFAULT_GIVE_FLAGS); }); root.addSubcommand("give") - .withPermission("yamipa.give") + .withPermission("yamipa.command.give", "yamipa.give") .withArgument(new OnlinePlayerArgument("player")) .withArgument(new ImageFileArgument("filename")) .withArgument(new IntegerArgument("amount", 1, 64)) @@ -148,13 +148,13 @@ public static void register(@NotNull YamipaPlugin plugin) { // List subcommand root.addSubcommand("list") - .withPermission("yamipa.list") + .withPermission("yamipa.command.list", "yamipa.list") .withArgument(new IntegerArgument("page", 1)) .executes((sender, args) -> { ImageCommand.listImages(sender, (int) args[1]); }); root.addSubcommand("list") - .withPermission("yamipa.list") + .withPermission("yamipa.command.list", "yamipa.list") .executes((sender, __) -> { boolean isPlayer = (sender instanceof Player); ImageCommand.listImages(sender, isPlayer ? 1 : 0); @@ -162,7 +162,7 @@ public static void register(@NotNull YamipaPlugin plugin) { // Place subcommand root.addSubcommand("place") - .withPermission("yamipa.place") + .withPermission("yamipa.command.place", "yamipa.place") .withArgument(new ImageFileArgument("filename")) .withArgument(new IntegerArgument("width", 1, FakeImage.MAX_DIMENSION)) .withArgument(new IntegerArgument("height", 1, FakeImage.MAX_DIMENSION)) @@ -171,7 +171,7 @@ public static void register(@NotNull YamipaPlugin plugin) { ImageCommand.placeImage(player, (ImageFile) args[1], (int) args[2], (int) args[3], (int) args[4]); }); root.addSubcommand("place") - .withPermission("yamipa.place") + .withPermission("yamipa.command.place", "yamipa.place") .withArgument(new ImageFileArgument("filename")) .withArgument(new IntegerArgument("width", 1, FakeImage.MAX_DIMENSION)) .withArgument(new IntegerArgument("height", 1, FakeImage.MAX_DIMENSION)) @@ -180,7 +180,7 @@ public static void register(@NotNull YamipaPlugin plugin) { FakeImage.DEFAULT_PLACE_FLAGS); }); root.addSubcommand("place") - .withPermission("yamipa.place") + .withPermission("yamipa.command.place", "yamipa.place") .withArgument(new ImageFileArgument("filename")) .withArgument(new IntegerArgument("width", 1, FakeImage.MAX_DIMENSION)) .executesPlayer((player, args) -> { @@ -190,14 +190,14 @@ public static void register(@NotNull YamipaPlugin plugin) { // Remove subcommand root.addSubcommand("remove") - .withPermission("yamipa.remove") + .withPermission("yamipa.command.remove.own", "yamipa.remove") .executesPlayer((player, __) -> { ImageCommand.removeImage(player); }); // Top subcommand root.addSubcommand("top") - .withPermission("yamipa.top") + .withPermission("yamipa.command.top", "yamipa.top") .executes((sender, __) -> { ImageCommand.showTopPlayers(sender); }); diff --git a/src/main/java/io/josemmo/bukkit/plugin/renderer/ItemService.java b/src/main/java/io/josemmo/bukkit/plugin/renderer/ItemService.java index f8a6574..5e34c33 100644 --- a/src/main/java/io/josemmo/bukkit/plugin/renderer/ItemService.java +++ b/src/main/java/io/josemmo/bukkit/plugin/renderer/ItemService.java @@ -147,6 +147,12 @@ public void onPlaceItem(@NotNull HangingPlaceEvent event) { // Prevent item frame placing event.setCancelled(true); + // Validate player permissions + if (!player.hasPermission("yamipa.item.place")) { + ActionBar.send(player, ChatColor.RED + "You're not allowed to place image items!"); + return; + } + // Try to place image in world Location location = event.getBlock().getLocation(); boolean success = ImageCommand.placeImage(player, image, width, height, flags, location, event.getBlockFace()); @@ -177,6 +183,19 @@ public boolean onAttack(@NotNull Player player, @NotNull Block block, @NotNull B FakeImage image = renderer.getImage(location, face); if (image == null || !image.hasFlag(FakeImage.FLAG_REMOVABLE)) return true; + // Validate player permissions + if (!player.hasPermission("yamipa.item.remove.own")) { + ActionBar.send(player, ChatColor.RED + "You're not allowed to remove image items!"); + return true; + } + if ( + !player.getUniqueId().equals(image.getPlacedBy().getUniqueId()) && + !player.hasPermission("yamipa.item.remove") + ) { + ActionBar.send(player, ChatColor.RED + "You cannot remove image items from other players!"); + return true; + } + // Attempt to remove image boolean success = ImageCommand.removeImage(player, image); if (!success) { diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index fcc4afd..f100005 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -11,9 +11,13 @@ softdepend: - WorldGuard permissions: + # All plugin permissions yamipa.*: default: op children: + yamipa.command.*: true + yamipa.item.*: true + # Legacy children yamipa.clear: true yamipa.describe: true yamipa.download: true @@ -22,6 +26,60 @@ permissions: yamipa.place: true yamipa.remove: true yamipa.top: true + + # All command permissions + yamipa.command.*: + default: op + children: + yamipa.command.clear: true + yamipa.command.describe: true + yamipa.command.download: true + yamipa.command.give: true + yamipa.command.list: true + yamipa.command.place: true + yamipa.command.remove: true + yamipa.command.top: true + + # Command permissions + yamipa.command.clear: + default: op + yamipa.command.describe: + default: op + yamipa.command.download: + default: op + yamipa.command.give: + default: op + yamipa.command.list: + default: op + yamipa.command.place: + default: op + yamipa.command.remove: + default: op + children: + yamipa.command.remove.own: true + yamipa.command.remove.own: + default: op + yamipa.command.top: + default: op + + # All item permissions + yamipa.item.*: + default: true + children: + yamipa.item.place: true + yamipa.item.remove: true + + # Item permissions + yamipa.item.place: + default: true + yamipa.item.remove: + default: true + children: + yamipa.item.remove.own: true + yamipa.item.remove.own: + default: true + + # Legacy permissions yamipa.clear: default: op yamipa.describe: From 7b7360ee03d48d6cc03ede65367338ea3c657235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Miguel=20Moreno?= Date: Sat, 29 Oct 2022 17:44:04 +0200 Subject: [PATCH 4/5] Fixed commands ignoring permissions - Updated Command#buildElement() method --- .../io/josemmo/bukkit/plugin/commands/Command.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/josemmo/bukkit/plugin/commands/Command.java b/src/main/java/io/josemmo/bukkit/plugin/commands/Command.java index c29b4e8..afaebae 100644 --- a/src/main/java/io/josemmo/bukkit/plugin/commands/Command.java +++ b/src/main/java/io/josemmo/bukkit/plugin/commands/Command.java @@ -119,6 +119,12 @@ public Command(@NotNull String name) { @SuppressWarnings({"rawtypes", "unchecked"}) private @NotNull ArgumentBuilder buildElement(@NotNull ArgumentBuilder parent, int argIndex) { + // Attach requirement handler to each command element + parent.requires(source -> { + CommandSender sender = Internals.getBukkitSender(source); + return requirementHandler.test(sender); + }); + // Chain command elements from the bottom-up if (argIndex < arguments.size()) { parent.then(buildElement(arguments.get(argIndex).build(), argIndex+1)).executes(ctx -> { @@ -129,12 +135,6 @@ public Command(@NotNull String name) { return parent; } - // Attach requirement handler to last command element - parent.requires(source -> { - CommandSender sender = Internals.getBukkitSender(source); - return requirementHandler.test(sender); - }); - // Attach execution handler to last command element if (executesPlayerHandler != null) { parent.executes(ctx -> { From 2ae0dc3727e8d42d705a85b91ae80ff731204b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Miguel=20Moreno?= Date: Sat, 29 Oct 2022 17:44:50 +0200 Subject: [PATCH 5/5] v1.2.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6454425..bd08782 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.josemmo.bukkit.plugin YamipaPlugin - 1.2.5 + 1.2.6 8