mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-01 05:58:00 +01:00
Added dynamic arguments for Command (allow for server tab completion)
This commit is contained in:
parent
baccc36ed7
commit
aecf0f427a
@ -1,6 +1,5 @@
|
||||
package fr.themode.demo.commands;
|
||||
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.command.builder.Arguments;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
@ -8,49 +7,32 @@ import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentType;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class TestCommand extends Command {
|
||||
|
||||
public TestCommand() {
|
||||
super("msg");
|
||||
super("testcmd");
|
||||
setDefaultExecutor(this::usage);
|
||||
|
||||
Argument player = ArgumentType.Word("player");
|
||||
Argument message = ArgumentType.StringArray("array");
|
||||
Argument dynamicWord = ArgumentType.DynamicWord("test");
|
||||
|
||||
addSyntax(this::execute, player, message);
|
||||
addSyntax(this::execute, dynamicWord);
|
||||
}
|
||||
|
||||
private void usage(CommandSender sender, Arguments arguments) {
|
||||
sender.sendMessage("Usage: /whisper <player> <message>");
|
||||
sender.sendMessage("Incorrect usage");
|
||||
}
|
||||
|
||||
private void execute(CommandSender sender, Arguments arguments) {
|
||||
Player player = (Player) sender;
|
||||
String targetName = arguments.getWord("player");
|
||||
String[] Message = arguments.getStringArray("array");
|
||||
Optional<Player> target = player.getInstance().getPlayers().stream().filter(p -> p.getUsername().equalsIgnoreCase(targetName)).findFirst();
|
||||
if (target.isPresent()) {
|
||||
if (target.get() == player) {
|
||||
player.sendMessage("You cannot message yourself");
|
||||
} else {
|
||||
String message = "";
|
||||
for (int i = 0; i < Message.length; i++) {
|
||||
if (i != 0) {
|
||||
message = message + " ";
|
||||
}
|
||||
message = message + Message[i];
|
||||
}
|
||||
player.sendMessage("You -> " + targetName + ": " + message);
|
||||
target.get().sendMessage(player.getUsername() + " -> You: " + message);
|
||||
}
|
||||
} else {
|
||||
player.sendMessage(ColoredText.ofFormat("{@argument.player.unknown}"));
|
||||
}
|
||||
final String word = arguments.getWord("test");
|
||||
sender.sendMessage("word: " + word);
|
||||
}
|
||||
|
||||
private boolean isAllowed(Player player) {
|
||||
return true; // TODO: permissions
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] onDynamicWrite(String text) {
|
||||
return new String[]{"test1", "test2"};
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,16 @@ public class CommandManager {
|
||||
this.dispatcher.register(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command register by {@link #register(Command)}
|
||||
*
|
||||
* @param commandName the command name
|
||||
* @return the command associated with the name, null if not any
|
||||
*/
|
||||
public Command getCommand(String commandName) {
|
||||
return dispatcher.findCommand(commandName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a simple command without auto-completion
|
||||
*
|
||||
@ -353,12 +363,12 @@ public class CommandManager {
|
||||
}*/
|
||||
|
||||
if (argument instanceof ArgumentBoolean) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
|
||||
argumentNode.parser = "brigadier:bool";
|
||||
argumentNode.properties = packetWriter -> packetWriter.writeByte((byte) 0);
|
||||
} else if (argument instanceof ArgumentDouble) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
|
||||
ArgumentDouble argumentDouble = (ArgumentDouble) argument;
|
||||
argumentNode.parser = "brigadier:double";
|
||||
@ -370,7 +380,7 @@ public class CommandManager {
|
||||
packetWriter.writeDouble(argumentDouble.getMax());
|
||||
};
|
||||
} else if (argument instanceof ArgumentFloat) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
|
||||
ArgumentFloat argumentFloat = (ArgumentFloat) argument;
|
||||
argumentNode.parser = "brigadier:float";
|
||||
@ -382,7 +392,7 @@ public class CommandManager {
|
||||
packetWriter.writeFloat(argumentFloat.getMax());
|
||||
};
|
||||
} else if (argument instanceof ArgumentInteger) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
|
||||
ArgumentInteger argumentInteger = (ArgumentInteger) argument;
|
||||
argumentNode.parser = "brigadier:integer";
|
||||
@ -418,50 +428,67 @@ public class CommandManager {
|
||||
}
|
||||
} else {
|
||||
// Can be any word, add only one argument node
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
wordConsumer.accept(argumentNode);
|
||||
}
|
||||
} else if (argument instanceof ArgumentDynamicWord) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, true);
|
||||
|
||||
argumentNode.parser = "brigadier:string";
|
||||
argumentNode.properties = packetWriter -> {
|
||||
packetWriter.writeVarInt(0); // Single word
|
||||
};
|
||||
argumentNode.suggestionsType = "minecraft:ask_server";
|
||||
|
||||
} else if (argument instanceof ArgumentString) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
|
||||
argumentNode.parser = "brigadier:string";
|
||||
argumentNode.properties = packetWriter -> {
|
||||
packetWriter.writeVarInt(1); // Quotable phrase
|
||||
};
|
||||
} else if (argument instanceof ArgumentStringArray) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
|
||||
argumentNode.parser = "brigadier:string";
|
||||
argumentNode.properties = packetWriter -> {
|
||||
packetWriter.writeVarInt(2); // Greedy phrase
|
||||
};
|
||||
} else if (argument instanceof ArgumentDynamicStringArray) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, true);
|
||||
|
||||
argumentNode.parser = "brigadier:string";
|
||||
argumentNode.properties = packetWriter -> {
|
||||
packetWriter.writeVarInt(2); // Greedy phrase
|
||||
};
|
||||
argumentNode.suggestionsType = "minecraft:ask_server";
|
||||
} else if (argument instanceof ArgumentColor) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:color";
|
||||
} else if (argument instanceof ArgumentTime) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:time";
|
||||
} else if (argument instanceof ArgumentEnchantment) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:item_enchantment";
|
||||
} else if (argument instanceof ArgumentParticle) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:particle";
|
||||
} else if (argument instanceof ArgumentPotion) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:mob_effect";
|
||||
} else if (argument instanceof ArgumentEntityType) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:entity_summon";
|
||||
} else if (argument instanceof ArgumentIntRange) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:int_range";
|
||||
} else if (argument instanceof ArgumentFloatRange) {
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:float_range";
|
||||
} else if (argument instanceof ArgumentEntities) {
|
||||
ArgumentEntities argumentEntities = (ArgumentEntities) argument;
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable);
|
||||
DeclareCommandsPacket.Node argumentNode = simpleArgumentNode(nodes, argument, executable, false);
|
||||
argumentNode.parser = "minecraft:entity";
|
||||
argumentNode.properties = packetWriter -> {
|
||||
byte mask = 0;
|
||||
@ -496,11 +523,11 @@ public class CommandManager {
|
||||
* @return the created {@link DeclareCommandsPacket.Node}
|
||||
*/
|
||||
private DeclareCommandsPacket.Node simpleArgumentNode(List<DeclareCommandsPacket.Node> nodes,
|
||||
Argument<?> argument, boolean executable) {
|
||||
Argument<?> argument, boolean executable, boolean suggestion) {
|
||||
DeclareCommandsPacket.Node argumentNode = new DeclareCommandsPacket.Node();
|
||||
nodes.add(argumentNode);
|
||||
|
||||
argumentNode.flags = getFlag(NodeType.ARGUMENT, executable, false, false);
|
||||
argumentNode.flags = getFlag(NodeType.ARGUMENT, executable, false, suggestion);
|
||||
argumentNode.name = argument.getId();
|
||||
|
||||
return argumentNode;
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.minestom.server.command.builder;
|
||||
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentDynamicStringArray;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentDynamicWord;
|
||||
import net.minestom.server.command.builder.condition.CommandCondition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -123,4 +125,16 @@ public class Command {
|
||||
public Collection<CommandSyntax> getSyntaxes() {
|
||||
return syntaxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow for tab auto completion, this is called everytime the player press a key in the chat
|
||||
* when in a dynamic argument ({@link ArgumentDynamicWord} & {@link ArgumentDynamicStringArray})
|
||||
*
|
||||
* @param text the whole player text
|
||||
* @return the array containing all the suggestion for the current arg (split " ")
|
||||
*/
|
||||
public String[] onDynamicWrite(String text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ public class CommandDispatcher {
|
||||
private Set<Command> commands = new HashSet<>();
|
||||
|
||||
public void register(Command command) {
|
||||
this.commandMap.put(command.getName(), command);
|
||||
this.commandMap.put(command.getName().toLowerCase(), command);
|
||||
for (String alias : command.getAliases()) {
|
||||
this.commandMap.put(alias, command);
|
||||
this.commandMap.put(alias.toLowerCase(), command);
|
||||
}
|
||||
this.commands.add(command);
|
||||
}
|
||||
@ -54,7 +54,14 @@ public class CommandDispatcher {
|
||||
return Collections.unmodifiableSet(commands);
|
||||
}
|
||||
|
||||
private Command findCommand(String commandName) {
|
||||
/**
|
||||
* Get the command class associated with its name
|
||||
*
|
||||
* @param commandName the command name
|
||||
* @return the {@link Command} associated with the name, null if not any
|
||||
*/
|
||||
public Command findCommand(String commandName) {
|
||||
commandName = commandName.toLowerCase();
|
||||
return commandMap.containsKey(commandName) ? commandMap.get(commandName) : null;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,25 @@
|
||||
package net.minestom.server.command.builder.arguments;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ArgumentDynamicStringArray extends Argument<String[]> {
|
||||
|
||||
public ArgumentDynamicStringArray(String id) {
|
||||
super(id, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCorrectionResult(String value) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] parse(String value) {
|
||||
return value.split(Pattern.quote(" "));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConditionResult(String[] value) {
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package net.minestom.server.command.builder.arguments;
|
||||
|
||||
public class ArgumentDynamicWord extends Argument<String> {
|
||||
|
||||
public ArgumentDynamicWord(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCorrectionResult(String value) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parse(String value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConditionResult(String value) {
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
@ -43,10 +43,18 @@ public class ArgumentType {
|
||||
return new ArgumentWord(id);
|
||||
}
|
||||
|
||||
public static ArgumentDynamicWord DynamicWord(String id) {
|
||||
return new ArgumentDynamicWord(id);
|
||||
}
|
||||
|
||||
public static ArgumentStringArray StringArray(String id) {
|
||||
return new ArgumentStringArray(id);
|
||||
}
|
||||
|
||||
public static ArgumentDynamicStringArray DynamicStringArray(String id) {
|
||||
return new ArgumentDynamicStringArray(id);
|
||||
}
|
||||
|
||||
// Minecraft specific
|
||||
|
||||
public static ArgumentColor Color(String id) {
|
||||
|
@ -21,7 +21,7 @@ public class ArgumentWord extends Argument<String> {
|
||||
if (value.contains(" "))
|
||||
return SPACE_ERROR;
|
||||
|
||||
return Argument.SUCCESS;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -37,7 +37,7 @@ public class ArgumentWord extends Argument<String> {
|
||||
if (restrictions != null && restrictions.length > 0) {
|
||||
for (String r : restrictions) {
|
||||
if (value.equalsIgnoreCase(r))
|
||||
return Argument.SUCCESS;
|
||||
return SUCCESS;
|
||||
}
|
||||
if (!findRestriction)
|
||||
return RESTRICTION_ERROR;
|
||||
|
@ -3,6 +3,7 @@ package net.minestom.server.listener;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
import net.minestom.server.command.CommandProcessor;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.packet.client.play.ClientTabCompletePacket;
|
||||
import net.minestom.server.network.packet.server.play.TabCompletePacket;
|
||||
@ -23,42 +24,55 @@ public class TabCompleteListener {
|
||||
// Tab complete for CommandProcessor
|
||||
final CommandProcessor commandProcessor = COMMAND_MANAGER.getCommandProcessor(commandName);
|
||||
if (commandProcessor != null) {
|
||||
final boolean endSpace = text.endsWith(" ");
|
||||
|
||||
int start;
|
||||
|
||||
if (endSpace) {
|
||||
start = text.length();
|
||||
} else {
|
||||
final String lastArg = split[split.length - 1];
|
||||
start = text.indexOf(lastArg);
|
||||
}
|
||||
|
||||
final int start = findStart(text, split);
|
||||
final String[] matches = commandProcessor.onWrite(text);
|
||||
|
||||
if (matches != null && matches.length > 0) {
|
||||
TabCompletePacket tabCompletePacket = new TabCompletePacket();
|
||||
tabCompletePacket.transactionId = packet.transactionId;
|
||||
tabCompletePacket.start = start;
|
||||
tabCompletePacket.length = 20;
|
||||
|
||||
TabCompletePacket.Match[] matchesArray = new TabCompletePacket.Match[matches.length];
|
||||
for (int i = 0; i < matchesArray.length; i++) {
|
||||
TabCompletePacket.Match match = new TabCompletePacket.Match();
|
||||
match.match = matches[i];
|
||||
matchesArray[i] = match;
|
||||
sendTabCompletePacket(packet.transactionId, start, matches, player);
|
||||
}
|
||||
} else {
|
||||
// Tab complete for Command
|
||||
final Command command = COMMAND_MANAGER.getCommand(commandName);
|
||||
if (command != null) {
|
||||
final int start = findStart(text, split);
|
||||
final String[] matches = command.onDynamicWrite(text);
|
||||
if (matches != null && matches.length > 0) {
|
||||
sendTabCompletePacket(packet.transactionId, start, matches, player);
|
||||
}
|
||||
|
||||
tabCompletePacket.matches = matchesArray;
|
||||
|
||||
player.getPlayerConnection().sendPacket(tabCompletePacket);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO tab complete for Command (TabArgument)
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static int findStart(String text, String[] split) {
|
||||
final boolean endSpace = text.endsWith(" ");
|
||||
int start;
|
||||
if (endSpace) {
|
||||
start = text.length();
|
||||
} else {
|
||||
final String lastArg = split[split.length - 1];
|
||||
start = text.lastIndexOf(lastArg);
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
private static void sendTabCompletePacket(int transactionId, int start, String[] matches, Player player) {
|
||||
TabCompletePacket tabCompletePacket = new TabCompletePacket();
|
||||
tabCompletePacket.transactionId = transactionId;
|
||||
tabCompletePacket.start = start;
|
||||
tabCompletePacket.length = 20;
|
||||
|
||||
TabCompletePacket.Match[] matchesArray = new TabCompletePacket.Match[matches.length];
|
||||
for (int i = 0; i < matchesArray.length; i++) {
|
||||
TabCompletePacket.Match match = new TabCompletePacket.Match();
|
||||
match.match = matches[i];
|
||||
matchesArray[i] = match;
|
||||
}
|
||||
|
||||
tabCompletePacket.matches = matchesArray;
|
||||
|
||||
player.getPlayerConnection().sendPacket(tabCompletePacket);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user