Minestom/src/main/java/net/minestom/server/command/CommandManager.java

310 lines
11 KiB
Java
Raw Normal View History

2020-04-24 03:25:58 +02:00
package net.minestom.server.command;
2020-04-05 10:15:21 +02:00
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.CommandDispatcher;
import net.minestom.server.command.builder.CommandSyntax;
import net.minestom.server.command.builder.arguments.*;
import net.minestom.server.command.builder.arguments.number.ArgumentDouble;
import net.minestom.server.command.builder.arguments.number.ArgumentFloat;
import net.minestom.server.command.builder.arguments.number.ArgumentInteger;
2020-04-24 03:25:58 +02:00
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerCommandEvent;
2020-04-24 03:25:58 +02:00
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
import net.minestom.server.utils.ArrayUtils;
2020-05-23 04:20:01 +02:00
import net.minestom.server.utils.validate.Check;
2020-04-05 10:15:21 +02:00
2020-06-21 14:01:03 +02:00
import java.util.*;
2020-04-05 10:15:21 +02:00
public class CommandManager {
private boolean running;
2020-04-05 10:15:21 +02:00
private String commandPrefix = "/";
2020-06-21 14:01:03 +02:00
private ConsoleSender consoleSender = new ConsoleSender();
private CommandDispatcher<CommandSender> dispatcher = new CommandDispatcher<>();
2020-04-05 10:15:21 +02:00
private Map<String, CommandProcessor> commandProcessorMap = new HashMap<>();
2020-06-21 14:01:03 +02:00
public CommandManager() {
running = true;
2020-06-21 14:01:03 +02:00
// Setup console thread
Thread consoleThread = new Thread(() -> {
2020-06-21 14:01:03 +02:00
Scanner scanner = new Scanner(System.in);
while (running) {
if (scanner.hasNext()) {
String command = scanner.nextLine();
if (!command.startsWith(commandPrefix))
continue;
command = command.replaceFirst(commandPrefix, "");
execute(consoleSender, command);
}
2020-06-21 14:01:03 +02:00
}
}, "ConsoleCommand-Thread");
consoleThread.setDaemon(true);
consoleThread.start();
}
public void stopConsoleThread() {
running = false;
2020-06-21 14:01:03 +02:00
}
public void register(Command<CommandSender> command) {
2020-04-05 10:15:21 +02:00
this.dispatcher.register(command);
}
public void register(CommandProcessor commandProcessor) {
this.commandProcessorMap.put(commandProcessor.getCommandName().toLowerCase(), commandProcessor);
}
2020-06-21 14:01:03 +02:00
public boolean execute(CommandSender sender, String command) {
Check.notNull(sender, "Source cannot be null");
2020-05-23 04:20:01 +02:00
Check.notNull(command, "Command string cannot be null");
2020-04-05 10:15:21 +02:00
2020-06-21 14:01:03 +02:00
if (sender instanceof Player) {
Player player = (Player) sender;
2020-06-21 14:01:03 +02:00
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, command);
player.callEvent(PlayerCommandEvent.class, playerCommandEvent);
2020-06-21 14:01:03 +02:00
if (playerCommandEvent.isCancelled())
return false;
command = playerCommandEvent.getCommand();
}
2020-04-05 10:15:21 +02:00
try {
2020-06-21 14:01:03 +02:00
this.dispatcher.execute(sender, command);
2020-04-05 10:15:21 +02:00
return true;
} catch (NullPointerException e) {
String[] splitted = command.split(" ");
String commandName = splitted[0];
CommandProcessor commandProcessor = commandProcessorMap.get(commandName.toLowerCase());
if (commandProcessor == null)
return false;
String[] args = command.substring(command.indexOf(" ") + 1).split(" ");
2020-06-21 14:01:03 +02:00
return commandProcessor.process(sender, commandName, args);
2020-04-05 10:15:21 +02:00
}
}
public String getCommandPrefix() {
return commandPrefix;
}
public void setCommandPrefix(String commandPrefix) {
this.commandPrefix = commandPrefix;
}
2020-06-21 14:01:03 +02:00
public ConsoleSender getConsoleSender() {
return consoleSender;
}
2020-04-26 06:34:08 +02:00
public DeclareCommandsPacket createDeclareCommandsPacket(Player player) {
return buildPacket2(player);
2020-04-05 10:15:21 +02:00
}
/*private DeclareCommandsPacket buildPacket(Player player) {
2020-04-26 06:34:08 +02:00
DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket();
2020-04-05 17:46:29 +02:00
List<String> commands = new ArrayList<>();
2020-06-21 14:01:03 +02:00
for (Command<CommandSender> command : dispatcher.getCommands()) {
2020-04-26 06:34:08 +02:00
CommandCondition<Player> commandCondition = command.getCondition();
if (commandCondition != null) {
// Do not show command if return false
if (!commandCondition.apply(player)) {
continue;
}
}
2020-04-05 17:46:29 +02:00
commands.add(command.getName());
for (String alias : command.getAliases()) {
commands.add(alias);
}
}
2020-04-26 06:34:08 +02:00
2020-04-05 17:46:29 +02:00
for (CommandProcessor commandProcessor : commandProcessorMap.values()) {
2020-04-26 06:34:08 +02:00
// Do not show command if return false
if (!commandProcessor.hasAccess(player))
continue;
2020-04-05 17:46:29 +02:00
commands.add(commandProcessor.getCommandName());
String[] aliases = commandProcessor.getAliases();
if (aliases == null || aliases.length == 0)
continue;
for (String alias : aliases) {
commands.add(alias);
}
2020-04-05 17:46:29 +02:00
}
List<DeclareCommandsPacket.Node> nodes = new ArrayList<>();
ArrayList<Integer> rootChildren = new ArrayList<>();
DeclareCommandsPacket.Node argNode = new DeclareCommandsPacket.Node();
argNode.flags = 0b10;
argNode.name = "arg";
argNode.parser = "brigadier:string";
argNode.properties = packetWriter -> {
packetWriter.writeVarInt(0);
};
int argOffset = nodes.size();
nodes.add(argNode);
argNode.children = new int[]{argOffset};
for (String commandName : commands) {
DeclareCommandsPacket.Node literalNode = new DeclareCommandsPacket.Node();
literalNode.flags = 0b1;
literalNode.name = commandName;
literalNode.children = new int[]{argOffset};
rootChildren.add(nodes.size());
nodes.add(literalNode);
}
DeclareCommandsPacket.Node rootNode = new DeclareCommandsPacket.Node();
rootNode.flags = 0;
rootNode.children = ArrayUtils.toArray(rootChildren);
nodes.add(rootNode);
declareCommandsPacket.nodes = nodes.toArray(new DeclareCommandsPacket.Node[0]);
2020-04-05 17:46:29 +02:00
declareCommandsPacket.rootIndex = nodes.size() - 1;
2020-04-26 06:34:08 +02:00
return declareCommandsPacket;
}*/
2020-04-05 17:46:29 +02:00
private DeclareCommandsPacket buildPacket2(Player player) {
DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket();
2020-04-05 10:15:21 +02:00
List<DeclareCommandsPacket.Node> nodes = new ArrayList<>();
ArrayList<Integer> rootChildren = new ArrayList<>();
for (Command<CommandSender> command : dispatcher.getCommands()) {
2020-04-05 10:15:21 +02:00
ArrayList<Integer> cmdChildren = new ArrayList<>();
String name = command.getName();
DeclareCommandsPacket.Node literalNode = new DeclareCommandsPacket.Node();
literalNode.flags = 0b1; // literal
2020-04-05 10:15:21 +02:00
literalNode.name = name;
rootChildren.add(nodes.size());
nodes.add(literalNode);
for (CommandSyntax syntax : command.getSyntaxes()) {
ArrayList<Integer> argChildren = cmdChildren;
for (Argument argument : syntax.getArguments()) {
DeclareCommandsPacket.Node argumentNode = toNode(argument);
argChildren.add(nodes.size());
nodes.add(argumentNode);
System.out.println("size: " + argChildren.size());
argumentNode.children = ArrayUtils.toArray(argChildren);
argChildren = new ArrayList<>();
}
}
System.out.println("test " + cmdChildren.size() + " : " + cmdChildren.get(0));
literalNode.children = ArrayUtils.toArray(cmdChildren);
}
DeclareCommandsPacket.Node rootNode = new DeclareCommandsPacket.Node();
rootNode.flags = 0;
rootNode.children = ArrayUtils.toArray(rootChildren);
nodes.add(rootNode);
declareCommandsPacket.nodes = nodes.toArray(new DeclareCommandsPacket.Node[0]);
2020-04-05 10:15:21 +02:00
declareCommandsPacket.rootIndex = nodes.size() - 1;
return declareCommandsPacket;
2020-04-05 10:15:21 +02:00
}
private DeclareCommandsPacket.Node toNode(Argument argument) {
DeclareCommandsPacket.Node argumentNode = new DeclareCommandsPacket.Node();
argumentNode.flags = getFlag(NodeType.ARGUMENT, true, false, false);
2020-04-05 10:15:21 +02:00
argumentNode.name = argument.getId();
if (argument instanceof ArgumentBoolean) {
argumentNode.parser = "brigadier:bool";
argumentNode.properties = packetWriter -> packetWriter.writeByte((byte) 0);
} else if (argument instanceof ArgumentDouble) {
ArgumentDouble argumentDouble = (ArgumentDouble) argument;
argumentNode.parser = "brigadier:double";
argumentNode.properties = packetWriter -> {
packetWriter.writeByte((byte) 0b11);
packetWriter.writeDouble(argumentDouble.min);
packetWriter.writeDouble(argumentDouble.max);
};
} else if (argument instanceof ArgumentFloat) {
ArgumentFloat argumentFloat = (ArgumentFloat) argument;
argumentNode.parser = "brigadier:float";
argumentNode.properties = packetWriter -> {
packetWriter.writeByte((byte) 0b11);
packetWriter.writeFloat(argumentFloat.min);
packetWriter.writeFloat(argumentFloat.max);
};
} else if (argument instanceof ArgumentInteger) {
ArgumentInteger argumentInteger = (ArgumentInteger) argument;
argumentNode.parser = "brigadier:integer";
argumentNode.properties = packetWriter -> {
packetWriter.writeByte((byte) 0b11);
packetWriter.writeInt(argumentInteger.min);
packetWriter.writeInt(argumentInteger.max);
};
} else if (argument instanceof ArgumentWord) {
argumentNode.parser = "brigadier:string";
argumentNode.properties = packetWriter -> {
packetWriter.writeVarInt(0); // Single word
};
} else if (argument instanceof ArgumentString) {
argumentNode.parser = "brigadier:string";
argumentNode.properties = packetWriter -> {
packetWriter.writeVarInt(1); // Quotable phrase
};
} else if (argument instanceof ArgumentStringArray) {
argumentNode.parser = "brigadier:string";
argumentNode.properties = packetWriter -> {
packetWriter.writeVarInt(2); // Greedy phrase
};
}
return argumentNode;
}
private byte getFlag(NodeType type, boolean executable, boolean redirect, boolean suggestionType) {
byte result = (byte) type.mask;
if (executable) {
result |= 0x4;
}
if (redirect) {
result |= 0x8;
}
if (suggestionType) {
result |= 0x1;
}
return result;
}
private enum NodeType {
ROOT(0), LITERAL(0b1), ARGUMENT(0b10), NONE(0x11);
private int mask;
NodeType(int mask) {
this.mask = mask;
}
}
2020-04-05 10:15:21 +02:00
}