From ecdd0181e0ab6d8cdf48a67d1278c2d20d450a66 Mon Sep 17 00:00:00 2001 From: MrGazdag <44264503+MrGazdag@users.noreply.github.com> Date: Tue, 20 Jul 2021 03:56:48 +0200 Subject: [PATCH 1/5] Modify /gamemode to function more like vanilla Modifies the /gamemode command in the demo, to function like the vanilla /gamemode command, with the syntax `/gamemode [target]`. It also utilizes translation components for players, and allows the console to run the command as well as players. --- .../java/demo/commands/GamemodeCommand.java | 107 ++++++++++-------- 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/src/test/java/demo/commands/GamemodeCommand.java b/src/test/java/demo/commands/GamemodeCommand.java index 8400c104a..439ea60b8 100644 --- a/src/test/java/demo/commands/GamemodeCommand.java +++ b/src/test/java/demo/commands/GamemodeCommand.java @@ -1,73 +1,88 @@ package demo.commands; +import net.kyori.adventure.audience.MessageType; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.Command; -import net.minestom.server.command.builder.CommandContext; import net.minestom.server.command.builder.arguments.ArgumentEnum; import net.minestom.server.command.builder.arguments.ArgumentType; -import net.minestom.server.command.builder.condition.Conditions; -import net.minestom.server.command.builder.exception.ArgumentSyntaxException; +import net.minestom.server.command.builder.arguments.minecraft.ArgumentEntity; +import net.minestom.server.entity.Entity; import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.utils.entity.EntityFinder; +import java.util.List; +import java.util.Locale; + /** - * Command that make a player change gamemode + * Command that make a player change gamemode, made in + * the style of the vanilla /gamemode command. */ public class GamemodeCommand extends Command { + public GamemodeCommand() { - super("gamemode", "g", "gm"); + super("gamemode", "gm"); - setCondition(Conditions::playerOnly); + ArgumentEnum gamemode = ArgumentType.Enum("gamemode", GameMode.class).setFormat(ArgumentEnum.Format.LOWER_CASED); + gamemode.setCallback((sender, exception) -> { + sender.sendMessage( + Component.text("Invalid gamemode ", NamedTextColor.RED) + .append(Component.text(exception.getInput(), NamedTextColor.WHITE)) + .append(Component.text("!")), MessageType.SYSTEM); + }); - setDefaultExecutor(this::usage); - var player = ArgumentType.Entity("player") - .onlyPlayers(true) - .singleEntity(true); + ArgumentEntity player = ArgumentType.Entity("targets").onlyPlayers(true); - var mode = ArgumentType.Enum("gamemode", GameMode.class) - .setFormat(ArgumentEnum.Format.LOWER_CASED); + setDefaultExecutor((sender, context) -> { + sender.sendMessage(Component.text("Usage: /" + context.getCommandName() + " [targets]", NamedTextColor.RED), MessageType.SYSTEM); + }); - setArgumentCallback(this::targetCallback, player); - setArgumentCallback(this::gameModeCallback, mode); + addSyntax((sender, context) -> { + if (!sender.isPlayer()) { + sender.sendMessage(Component.text("Please run this command in-game.", NamedTextColor.RED)); + return; + } + if (sender.asPlayer().getPermissionLevel() < 2) { + sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); + return; + } + GameMode mode = context.get(gamemode); + executeSelf(sender.asPlayer(), mode); + }, gamemode); - addSyntax(this::executeOnSelf, mode); - addSyntax(this::executeOnOther, player, mode); + addSyntax((sender, context) -> { + if (sender.isPlayer() && sender.asPlayer().getPermissionLevel() < 2) { + sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); + return; + } + EntityFinder finder = context.get(player); + GameMode mode = context.get(gamemode); + executeOthers(sender.asPlayer(), mode, finder.find(sender)); + }, gamemode, player); } - private void usage(CommandSender sender, CommandContext context) { - sender.sendMessage(Component.text("Usage: /gamemode [player] ") - .hoverEvent(Component.text("Click to get this command.")) - .clickEvent(ClickEvent.suggestCommand("/gamemode player gamemode"))); + private void executeOthers(CommandSender sender, GameMode mode, List entities) { + if (entities.size() == 0) { + if (sender.isPlayer()) sender.sendMessage(Component.translatable("argument.entity.notfound.player", NamedTextColor.RED), MessageType.SYSTEM); + else sender.sendMessage(Component.text("No player was found", NamedTextColor.RED), MessageType.SYSTEM); + } else for (Entity entity : entities) { + if (entity instanceof Player p) { + if (p == sender) { + executeSelf(sender.asPlayer(), mode); + } else { + p.setGameMode(mode); + p.sendMessage(Component.translatable("gameMode.changed").args(Component.translatable("gameMode." + mode.name().toLowerCase(Locale.ROOT))), MessageType.SYSTEM); + sender.sendMessage(Component.translatable("commands.gamemode.success.other").args(p.getDisplayName() == null ? p.getName() : p.getDisplayName(), Component.translatable("gameMode." + mode.name().toLowerCase(Locale.ROOT))), MessageType.SYSTEM); + } + } + } } - private void executeOnSelf(CommandSender sender, CommandContext context) { - Player player = (Player) sender; - - GameMode gamemode = context.get("gamemode"); - assert gamemode != null; // mode is not supposed to be null, because gamemodeName will be valid - player.setGameMode(gamemode); - player.sendMessage(Component.text("You are now playing in " + gamemode.toString().toLowerCase())); - } - - private void executeOnOther(CommandSender sender, CommandContext context) { - GameMode gamemode = context.get("gamemode"); - EntityFinder targetFinder = context.get("player"); - Player target = targetFinder.findFirstPlayer(sender); - assert gamemode != null; // mode is not supposed to be null, because gamemodeName will be valid - assert target != null; - target.setGameMode(gamemode); - target.sendMessage(Component.text("You are now playing in " + gamemode.toString().toLowerCase())); - } - - private void targetCallback(CommandSender sender, ArgumentSyntaxException exception) { - sender.sendMessage(Component.text("'" + exception.getInput() + "' is not a valid player name.")); - } - - private void gameModeCallback(CommandSender sender, ArgumentSyntaxException exception) { - sender.sendMessage(Component.text("'" + exception.getInput() + "' is not a valid gamemode!")); + private void executeSelf(Player sender, GameMode mode) { + sender.setGameMode(mode); + sender.sendMessage(Component.translatable("commands.gamemode.success.self").args(Component.translatable("gameMode." + mode.name().toLowerCase(Locale.ROOT))), MessageType.SYSTEM); } } From ed97de417eefca9e8ce7237383371ff64035ee2b Mon Sep 17 00:00:00 2001 From: MrGazdag <44264503+MrGazdag@users.noreply.github.com> Date: Tue, 20 Jul 2021 04:15:43 +0200 Subject: [PATCH 2/5] remove pattern matching --- src/test/java/demo/commands/GamemodeCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/demo/commands/GamemodeCommand.java b/src/test/java/demo/commands/GamemodeCommand.java index 439ea60b8..584c35d79 100644 --- a/src/test/java/demo/commands/GamemodeCommand.java +++ b/src/test/java/demo/commands/GamemodeCommand.java @@ -69,7 +69,8 @@ public class GamemodeCommand extends Command { if (sender.isPlayer()) sender.sendMessage(Component.translatable("argument.entity.notfound.player", NamedTextColor.RED), MessageType.SYSTEM); else sender.sendMessage(Component.text("No player was found", NamedTextColor.RED), MessageType.SYSTEM); } else for (Entity entity : entities) { - if (entity instanceof Player p) { + if (entity instanceof Player) { + Player p = (Player) entity; if (p == sender) { executeSelf(sender.asPlayer(), mode); } else { From 037dfc20034a8552d1260301a96c511696a015e9 Mon Sep 17 00:00:00 2001 From: MrGazdag <44264503+MrGazdag@users.noreply.github.com> Date: Tue, 20 Jul 2021 13:46:57 +0200 Subject: [PATCH 3/5] Format and comment code makes the code look nicer --- .../java/demo/commands/GamemodeCommand.java | 60 +++++++++++++++++-- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/src/test/java/demo/commands/GamemodeCommand.java b/src/test/java/demo/commands/GamemodeCommand.java index 584c35d79..41847e332 100644 --- a/src/test/java/demo/commands/GamemodeCommand.java +++ b/src/test/java/demo/commands/GamemodeCommand.java @@ -19,12 +19,15 @@ import java.util.Locale; /** * Command that make a player change gamemode, made in * the style of the vanilla /gamemode command. + * + * @see https://minecraft.fandom.com/wiki/Commands/gamemode */ public class GamemodeCommand extends Command { public GamemodeCommand() { super("gamemode", "gm"); + //GameMode parameter ArgumentEnum gamemode = ArgumentType.Enum("gamemode", GameMode.class).setFormat(ArgumentEnum.Format.LOWER_CASED); gamemode.setCallback((sender, exception) -> { sender.sendMessage( @@ -33,57 +36,102 @@ public class GamemodeCommand extends Command { .append(Component.text("!")), MessageType.SYSTEM); }); - + //Targets parameter, can accept multiple players ArgumentEntity player = ArgumentType.Entity("targets").onlyPlayers(true); + //Upon invalid usage, print the correct usage of the command to the sender setDefaultExecutor((sender, context) -> { - sender.sendMessage(Component.text("Usage: /" + context.getCommandName() + " [targets]", NamedTextColor.RED), MessageType.SYSTEM); + //The used alias + String commandName = context.getCommandName(); + + sender.sendMessage(Component.text("Usage: /" + commandName + " [targets]", NamedTextColor.RED), MessageType.SYSTEM); }); + //Command Syntax for /gamemode addSyntax((sender, context) -> { + //Limit execution to players only if (!sender.isPlayer()) { sender.sendMessage(Component.text("Please run this command in-game.", NamedTextColor.RED)); return; } + //Check permission, this could be replaced with hasPermission if (sender.asPlayer().getPermissionLevel() < 2) { sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); return; } + + //Arguments GameMode mode = context.get(gamemode); + + //Set the gamemode for the sender executeSelf(sender.asPlayer(), mode); }, gamemode); + //Command Syntax for /gamemode [targets] addSyntax((sender, context) -> { + //Check permission for players only + //This allows the console to use this syntax too if (sender.isPlayer() && sender.asPlayer().getPermissionLevel() < 2) { sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); return; } + + //Arguments EntityFinder finder = context.get(player); GameMode mode = context.get(gamemode); - executeOthers(sender.asPlayer(), mode, finder.find(sender)); + + //Set the gamemode for the targets + executeOthers(sender, mode, finder.find(sender)); }, gamemode, player); } + /** + * Sets the gamemode for the specified entities, and + * notifies them (and the sender) in the chat. + */ private void executeOthers(CommandSender sender, GameMode mode, List entities) { if (entities.size() == 0) { + //If there are no players that could be modified, display an error message if (sender.isPlayer()) sender.sendMessage(Component.translatable("argument.entity.notfound.player", NamedTextColor.RED), MessageType.SYSTEM); else sender.sendMessage(Component.text("No player was found", NamedTextColor.RED), MessageType.SYSTEM); } else for (Entity entity : entities) { if (entity instanceof Player) { Player p = (Player) entity; if (p == sender) { + //If the player is the same as the sender, call + //executeSelf to display one message instead of two executeSelf(sender.asPlayer(), mode); } else { p.setGameMode(mode); - p.sendMessage(Component.translatable("gameMode.changed").args(Component.translatable("gameMode." + mode.name().toLowerCase(Locale.ROOT))), MessageType.SYSTEM); - sender.sendMessage(Component.translatable("commands.gamemode.success.other").args(p.getDisplayName() == null ? p.getName() : p.getDisplayName(), Component.translatable("gameMode." + mode.name().toLowerCase(Locale.ROOT))), MessageType.SYSTEM); + + //Create necessary components + String gamemodeString = "gameMode." + mode.name().toLowerCase(Locale.ROOT); + Component gamemodeComponent = Component.translatable(gamemodeString); + Component playerName = p.getDisplayName() == null ? p.getName() : p.getDisplayName(); + + //Send a message to the changed player + p.sendMessage(Component.translatable("gameMode.changed", gamemodeComponent), MessageType.SYSTEM); + + //Send a message to the sender + sender.sendMessage(Component.translatable("commands.gamemode.success.other", playername, gamemodeComponent), MessageType.SYSTEM); } } } } + /** + * Sets the gamemode for the executing Player, and + * notifies them in the chat. + */ private void executeSelf(Player sender, GameMode mode) { sender.setGameMode(mode); - sender.sendMessage(Component.translatable("commands.gamemode.success.self").args(Component.translatable("gameMode." + mode.name().toLowerCase(Locale.ROOT))), MessageType.SYSTEM); + + //The translation keys 'gameMode.survival', 'gameMode.creative', etc. + //correspond to the translated game mode names. + String gamemodeString = "gameMode." + mode.name().toLowerCase(Locale.ROOT); + Component gamemodeComponent = Component.translatable(gamemodeString); + + //Send the translated message to the player. + sender.sendMessage(Component.translatable("commands.gamemode.success.self", gamemodeComponent), MessageType.SYSTEM); } } From 471838a77f8cd41f73d6458e957958460fbf31c9 Mon Sep 17 00:00:00 2001 From: MrGazdag <44264503+MrGazdag@users.noreply.github.com> Date: Tue, 20 Jul 2021 13:52:04 +0200 Subject: [PATCH 4/5] capitalize a single N i missed that lmao --- src/test/java/demo/commands/GamemodeCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/demo/commands/GamemodeCommand.java b/src/test/java/demo/commands/GamemodeCommand.java index 41847e332..8ddba72b2 100644 --- a/src/test/java/demo/commands/GamemodeCommand.java +++ b/src/test/java/demo/commands/GamemodeCommand.java @@ -113,7 +113,7 @@ public class GamemodeCommand extends Command { p.sendMessage(Component.translatable("gameMode.changed", gamemodeComponent), MessageType.SYSTEM); //Send a message to the sender - sender.sendMessage(Component.translatable("commands.gamemode.success.other", playername, gamemodeComponent), MessageType.SYSTEM); + sender.sendMessage(Component.translatable("commands.gamemode.success.other", playerName, gamemodeComponent), MessageType.SYSTEM); } } } From 4348ce50cf8793d702a326ed34ddcfe6cdf7d725 Mon Sep 17 00:00:00 2001 From: MrGazdag <44264503+MrGazdag@users.noreply.github.com> Date: Tue, 20 Jul 2021 17:01:30 +0200 Subject: [PATCH 5/5] further polish --- src/test/java/demo/commands/GamemodeCommand.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/test/java/demo/commands/GamemodeCommand.java b/src/test/java/demo/commands/GamemodeCommand.java index 8ddba72b2..d2b952508 100644 --- a/src/test/java/demo/commands/GamemodeCommand.java +++ b/src/test/java/demo/commands/GamemodeCommand.java @@ -36,12 +36,10 @@ public class GamemodeCommand extends Command { .append(Component.text("!")), MessageType.SYSTEM); }); - //Targets parameter, can accept multiple players ArgumentEntity player = ArgumentType.Entity("targets").onlyPlayers(true); //Upon invalid usage, print the correct usage of the command to the sender setDefaultExecutor((sender, context) -> { - //The used alias String commandName = context.getCommandName(); sender.sendMessage(Component.text("Usage: /" + commandName + " [targets]", NamedTextColor.RED), MessageType.SYSTEM); @@ -54,13 +52,13 @@ public class GamemodeCommand extends Command { sender.sendMessage(Component.text("Please run this command in-game.", NamedTextColor.RED)); return; } + //Check permission, this could be replaced with hasPermission if (sender.asPlayer().getPermissionLevel() < 2) { sender.sendMessage(Component.text("You don't have permission to use this command.", NamedTextColor.RED)); return; } - //Arguments GameMode mode = context.get(gamemode); //Set the gamemode for the sender @@ -76,7 +74,6 @@ public class GamemodeCommand extends Command { return; } - //Arguments EntityFinder finder = context.get(player); GameMode mode = context.get(gamemode); @@ -104,15 +101,12 @@ public class GamemodeCommand extends Command { } else { p.setGameMode(mode); - //Create necessary components String gamemodeString = "gameMode." + mode.name().toLowerCase(Locale.ROOT); Component gamemodeComponent = Component.translatable(gamemodeString); Component playerName = p.getDisplayName() == null ? p.getName() : p.getDisplayName(); - //Send a message to the changed player + //Send a message to the changed player and the sender p.sendMessage(Component.translatable("gameMode.changed", gamemodeComponent), MessageType.SYSTEM); - - //Send a message to the sender sender.sendMessage(Component.translatable("commands.gamemode.success.other", playerName, gamemodeComponent), MessageType.SYSTEM); } }