diff --git a/src/main/java/net/minestom/server/command/CommandManager.java b/src/main/java/net/minestom/server/command/CommandManager.java index 502d0cead..45213edd7 100644 --- a/src/main/java/net/minestom/server/command/CommandManager.java +++ b/src/main/java/net/minestom/server/command/CommandManager.java @@ -204,7 +204,7 @@ public final class CommandManager { /** * Gets the {@link DeclareCommandsPacket} for a specific player. *
- * Can be used to update the {@link Player} auto-completion list.
+ * Can be used to update a player auto-completion list.
*
* @param player the player to get the commands packet
* @return the {@link DeclareCommandsPacket} for {@code player}
@@ -234,7 +234,7 @@ public final class CommandManager {
final CommandCondition commandCondition = command.getCondition();
if (commandCondition != null) {
// Do not show command if return false
- if (!commandCondition.apply(player)) {
+ if (!commandCondition.canUse(player, null)) {
continue;
}
}
@@ -247,7 +247,7 @@ public final class CommandManager {
names.add(command.getName());
names.addAll(Arrays.asList(command.getAliases()));
for (String name : names) {
- createCommand(nodes, cmdChildren, name, syntaxes, rootChildren);
+ createCommand(player, nodes, cmdChildren, name, syntaxes, rootChildren);
}
}
@@ -311,13 +311,15 @@ public final class CommandManager {
/**
* Adds the command's syntaxes to the nodes list.
*
+ * @param sender the potential sender of the command
* @param nodes the nodes of the packet
* @param cmdChildren the main root of this command
* @param name the name of the command (or the alias)
* @param syntaxes the syntaxes of the command
* @param rootChildren the children of the main node (all commands name)
*/
- private void createCommand(@NotNull List
- * A syntax is simply a list of arguments
+ * A syntax is simply a list of arguments.
+ *
+ * @param commandCondition the condition to use the syntax
+ * @param executor the executor to call when the syntax is successfully received
+ * @param args all the arguments of the syntax
+ * @return the created {@link CommandSyntax}
+ */
+ public CommandSyntax addSyntax(@Nullable CommandCondition commandCondition,
+ @NotNull CommandExecutor executor,
+ @NotNull Argument>... args) {
+ final CommandSyntax syntax = new CommandSyntax(commandCondition, executor, args);
+ this.syntaxes.add(syntax);
+ return syntax;
+ }
+
+ /**
+ * Adds a new syntax in the command without any condition.
*
* @param executor the executor to call when the syntax is successfully received
* @param args all the arguments of the syntax
* @return the created {@link CommandSyntax}
+ * @see #addSyntax(CommandCondition, CommandExecutor, Argument[])
*/
public CommandSyntax addSyntax(@NotNull CommandExecutor executor, @NotNull Argument>... args) {
- final CommandSyntax syntax = new CommandSyntax(executor, args);
- this.syntaxes.add(syntax);
- return syntax;
+ return addSyntax(null, executor, args);
}
/**
diff --git a/src/main/java/net/minestom/server/command/builder/CommandDispatcher.java b/src/main/java/net/minestom/server/command/builder/CommandDispatcher.java
index 4a3c78c88..fb812291a 100644
--- a/src/main/java/net/minestom/server/command/builder/CommandDispatcher.java
+++ b/src/main/java/net/minestom/server/command/builder/CommandDispatcher.java
@@ -198,6 +198,7 @@ public class CommandDispatcher {
final CommandSyntax finalSyntax = findMostCorrectSyntax(validSyntaxes, syntaxesValues, executorArgs);
if (finalSyntax != null) {
// A fully correct syntax has been found, use it
+ result.syntax = finalSyntax;
result.executor = finalSyntax.getExecutor();
result.arguments = executorArgs;
return result;
@@ -333,6 +334,8 @@ public class CommandDispatcher {
private Command command;
// Command Executor
+ private CommandSyntax syntax;
+
private CommandExecutor executor;
private Arguments arguments;
@@ -353,17 +356,27 @@ public class CommandDispatcher {
public void execute(@NotNull CommandSender source, @NotNull String commandString) {
// Global listener
command.globalListener(source, arguments, commandString);
- // Condition check
+ // Command condition check
final CommandCondition condition = command.getCondition();
if (condition != null) {
- final boolean result = condition.apply(source);
+ final boolean result = condition.canUse(source, commandString);
if (!result)
return;
}
// Condition is respected
if (executor != null) {
// An executor has been found
- executor.apply(source, arguments);
+
+ if (syntax != null) {
+ // The executor is from a syntax
+ final CommandCondition commandCondition = syntax.getCommandCondition();
+ if (commandCondition == null || commandCondition.canUse(source, commandString)) {
+ executor.apply(source, arguments);
+ }
+ } else {
+ // The executor is probably the default one
+ executor.apply(source, arguments);
+ }
} else if (callback != null) {
// No syntax has been validated but the faulty argument with a callback has been found
// Execute the faulty argument callback
diff --git a/src/main/java/net/minestom/server/command/builder/CommandSyntax.java b/src/main/java/net/minestom/server/command/builder/CommandSyntax.java
index 0d518a6a2..803fa9a78 100644
--- a/src/main/java/net/minestom/server/command/builder/CommandSyntax.java
+++ b/src/main/java/net/minestom/server/command/builder/CommandSyntax.java
@@ -1,7 +1,10 @@
package net.minestom.server.command.builder;
import net.minestom.server.command.builder.arguments.Argument;
+import net.minestom.server.command.builder.condition.CommandCondition;
+import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* Represents a syntax in {@link Command}
@@ -9,22 +12,39 @@ import org.jetbrains.annotations.NotNull;
*/
public class CommandSyntax {
- private final Argument>[] args;
+ private CommandCondition commandCondition;
private CommandExecutor executor;
+ private final Argument>[] args;
- protected CommandSyntax(@NotNull CommandExecutor commandExecutor, @NotNull Argument>... args) {
+ protected CommandSyntax(@Nullable CommandCondition commandCondition,
+ @NotNull CommandExecutor commandExecutor,
+ @NotNull Argument>... args) {
+ this.commandCondition = commandCondition;
this.executor = commandExecutor;
this.args = args;
}
/**
- * Gets all the required {@link Argument} for this syntax.
+ * Gets the condition to use this syntax.
*
- * @return the required arguments
+ * @return this command condition, null if none
*/
- @NotNull
- public Argument>[] getArguments() {
- return args;
+ @Nullable
+ public CommandCondition getCommandCondition() {
+ return commandCondition;
+ }
+
+ /**
+ * Changes the command condition of this syntax.
+ *
+ * Be aware that changing the command condition will not automatically update players auto-completion.
+ * You can create a new packet containing the changes with
+ * {@link net.minestom.server.command.CommandManager#createDeclareCommandsPacket(Player)}.
+ *
+ * @param commandCondition the new command condition, null to remove it
+ */
+ public void setCommandCondition(@Nullable CommandCondition commandCondition) {
+ this.commandCondition = commandCondition;
}
/**
@@ -46,4 +66,14 @@ public class CommandSyntax {
this.executor = executor;
}
+ /**
+ * Gets all the required {@link Argument} for this syntax.
+ *
+ * @return the required arguments
+ */
+ @NotNull
+ public Argument>[] getArguments() {
+ return args;
+ }
+
}
diff --git a/src/main/java/net/minestom/server/command/builder/condition/CommandCondition.java b/src/main/java/net/minestom/server/command/builder/condition/CommandCondition.java
index 243872ba9..751e3ef5d 100644
--- a/src/main/java/net/minestom/server/command/builder/condition/CommandCondition.java
+++ b/src/main/java/net/minestom/server/command/builder/condition/CommandCondition.java
@@ -2,10 +2,29 @@ package net.minestom.server.command.builder.condition;
import net.minestom.server.command.CommandSender;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
- * Used to know if the {@link CommandSender} is allowed to run the command.
+ * Used to know if the {@link CommandSender} is allowed to run the command or a specific syntax.
*/
+@FunctionalInterface
public interface CommandCondition {
- boolean apply(@NotNull CommandSender source);
+
+ /**
+ * Called when the sender permission needs to be checked.
+ *
+ * The first time will be during player connection in order to know
+ * if the command/syntax should be displayed as tab-completion suggestion,
+ * {@code commandString} will be null in this case.
+ *
+ * Otherwise, {@code commandString} will never be null
+ * but will instead be the raw command string given by the sender.
+ * You should in this case warn the sender (eg by sending a message) if the condition is unsuccessful.
+ *
+ * @param source the sender of the command
+ * @param commandString the raw command string,
+ * null if the method has been called at player login
+ * @return true if the sender has the right to use the command, false otherwise
+ */
+ boolean canUse(@NotNull CommandSender source, @Nullable String commandString);
}
diff --git a/src/test/java/demo/Main.java b/src/test/java/demo/Main.java
index e49d54cb1..ba8a5f9d5 100644
--- a/src/test/java/demo/Main.java
+++ b/src/test/java/demo/Main.java
@@ -3,7 +3,7 @@ package demo;
import demo.blocks.BurningTorchBlock;
import demo.blocks.StoneBlock;
import demo.blocks.UpdatableBlockDemo;
-import demo.commands.*;
+import demo.commands.TestCommand;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandManager;
import net.minestom.server.instance.block.BlockManager;
@@ -27,14 +27,14 @@ public class Main {
blockManager.registerBlockPlacementRule(new RedstonePlacementRule());
CommandManager commandManager = MinecraftServer.getCommandManager();
- commandManager.register(new EntitySelectorCommand());
commandManager.register(new TestCommand());
+ /*commandManager.register(new EntitySelectorCommand());
commandManager.register(new HealthCommand());
commandManager.register(new SimpleCommand());
commandManager.register(new GamemodeCommand());
commandManager.register(new DimensionCommand());
commandManager.register(new ShutdownCommand());
- commandManager.register(new TeleportCommand());
+ commandManager.register(new TeleportCommand());*/
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage("unknown command"));
diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java
index 31d437949..1c1bd80cb 100644
--- a/src/test/java/demo/PlayerInit.java
+++ b/src/test/java/demo/PlayerInit.java
@@ -172,7 +172,7 @@ public class PlayerInit {
player.addEventCallback(PlayerSpawnEvent.class, event -> {
player.setGameMode(GameMode.SURVIVAL);
- if(event.isFirstSpawn()){
+ if (event.isFirstSpawn()) {
player.teleport(new Position(0, 64f, 0));
}
diff --git a/src/test/java/demo/commands/GamemodeCommand.java b/src/test/java/demo/commands/GamemodeCommand.java
index 8b715a19c..3518a2e10 100644
--- a/src/test/java/demo/commands/GamemodeCommand.java
+++ b/src/test/java/demo/commands/GamemodeCommand.java
@@ -70,7 +70,7 @@ public class GamemodeCommand extends Command {
sender.sendMessage("'" + gamemode + "' is not a valid gamemode!");
}
- private boolean isAllowed(CommandSender sender) {
+ private boolean isAllowed(CommandSender sender, String commandString) {
if (!sender.isPlayer()) {
sender.sendMessage("The command is only available for player");
return false;
diff --git a/src/test/java/demo/commands/HealthCommand.java b/src/test/java/demo/commands/HealthCommand.java
index 93533f89f..5bbbf3668 100644
--- a/src/test/java/demo/commands/HealthCommand.java
+++ b/src/test/java/demo/commands/HealthCommand.java
@@ -28,7 +28,7 @@ public class HealthCommand extends Command {
addSyntax(this::execute, arg0);
}
- private boolean condition(CommandSender sender) {
+ private boolean condition(CommandSender sender, String commandString) {
if (!sender.isPlayer()) {
sender.sendMessage("The command is only available for player");
return false;
diff --git a/src/test/java/demo/commands/TestCommand.java b/src/test/java/demo/commands/TestCommand.java
index 219ddc972..66fdd970c 100644
--- a/src/test/java/demo/commands/TestCommand.java
+++ b/src/test/java/demo/commands/TestCommand.java
@@ -17,8 +17,9 @@ public class TestCommand extends Command {
//addSyntax(this::execute, dynamicWord);
}
- Argument test = ArgumentType.Word("test").from("hey");
- Argument num = ArgumentType.Integer("num");
+ Argument test = ArgumentType.Word("wordT");
+ Argument testt = ArgumentType.Word("wordTt");
+ Argument test2 = ArgumentType.StringArray("array");
setDefaultExecutor((source, args) -> {
System.out.println("DEFAULT");
@@ -31,7 +32,7 @@ public class TestCommand extends Command {
addSyntax((source, args) -> {
System.out.println(2);
- }, test, num);
+ }, test, test2);
}
private void usage(CommandSender sender, Arguments arguments) {