cn.nukkit.command.tree.ParamTree Maven / Gradle / Ivy
package cn.nukkit.command.tree;
import cn.nukkit.api.PowerNukkitXOnly;
import cn.nukkit.api.Since;
import cn.nukkit.command.Command;
import cn.nukkit.command.CommandSender;
import cn.nukkit.command.PluginCommand;
import cn.nukkit.command.data.CommandEnum;
import cn.nukkit.command.data.CommandParamType;
import cn.nukkit.command.data.CommandParameter;
import cn.nukkit.command.tree.node.*;
import cn.nukkit.command.utils.CommandLogger;
import cn.nukkit.lang.CommandOutputContainer;
import cn.nukkit.plugin.InternalPlugin;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
@PowerNukkitXOnly
@Since("1.19.60-r1")
public class ParamTree {
private final Map root;
private final Command command;
private CommandSender sender;
private String[] args;
/**
* 从给定的命令中初始化命令节点树,其中每个参数类型{@link cn.nukkit.command.data.CommandParamType CommandParamType}会对应一个默认的参数节点,或者使用
* {@link CommandParameter#newType(String, CommandParamType, IParamNode)}
* {@link CommandParameter#newEnum(String, boolean, CommandEnum, IParamNode)}
* 初始化指定的命令节点。
* 应该在命令构造函数中commandParameters初始化完毕后调用Command::enableParamTree(),形如
*
* public TestCommand(String name) {
* super(name, description, usage, aliases);
* this.setPermission("nukkit.command.test");
* this.commandParameters.clear();
* this.commandParameters.put("pos", new CommandParameter[]{
* CommandParameter.newType("destination", CommandParamType.POSITION)
* });
* this.enableParamTree();
* }
*
*
* @param command the command
*/
//todo 优化建树和遍历
@SuppressWarnings("RedundantLabeledSwitchRuleCodeBlock")
public ParamTree(Command command) {
this.command = command;
final var root = new HashMap();
for (Map.Entry entry : command.getCommandParameters().entrySet()) {
final var paramList = new ParamList(this);
for (CommandParameter parameter : entry.getValue()) {
IParamNode> node;
if (parameter.paramNode != null) {
node = parameter.paramNode;
} else if (parameter.enumData == null) {
switch (parameter.type) {
case INT -> {
node = new IntNode();
}
case WILDCARD_INT -> {
node = new WildcardIntNode();
}
case FLOAT -> {
node = new FloatNode();
}
case VALUE -> {
node = new DoubleNode();
}
case POSITION -> {//(?<=\s|^)([~^]?-?\d+\.?\d*(?=\s|$))
node = new FloatPositionNode();
}
case BLOCK_POSITION -> {
node = new IntPositionNode();
}
case TARGET -> {
node = new EntitiesNode();
}
case WILDCARD_TARGET -> {
node = new WildcardTargetStringNode();
}
case STRING, TEXT, FILE_PATH -> {
node = new StringNode();
}
case COMMAND -> {
node = new CommandNode();
}
case OPERATOR -> {
node = new OperatorStringNode();
}
case COMPARE_OPERATOR -> {
node = new CompareOperatorStringNode();
}
case MESSAGE -> {
node = new MessageStringNode();
}
case JSON -> {
node = new RemainStringNode();
}
case RAWTEXT -> {
node = new RawTextNode();
}
default -> node = new VoidNode();
}
} else {
if (parameter.enumData.equals(CommandEnum.ENUM_BOOLEAN)) {
node = new BooleanNode();
} else if (parameter.enumData.equals(CommandEnum.ENUM_ITEM)) {
node = new ItemNode();
} else if (parameter.enumData.equals(CommandEnum.ENUM_BLOCK)) {
node = new BlockNode();
} else if (parameter.enumData.equals(CommandEnum.ENUM_ENTITY)) {
node = new StringNode();
} else node = new EnumNode();
}
paramList.add(node.init(paramList, parameter.name, parameter.optional, parameter.type, parameter.enumData, parameter.postFix));
}
root.put(entry.getKey(), paramList);
}
this.root = root;
}
public ParamTree(Command command, Map root) {
this.root = root;
this.command = command;
}
/**
* 从给定输入参数匹配该命令节点树对应命令的命令重载,并且解析对应参数。
* 返回值是一个{@link Map.Entry},它是成功匹配的命令重载,对应{@link Command#getCommandParameters()} commandParameters}。
* 其Key对应commandParameters中的Key,值是一个{@link ParamList} 其中每个节点与commandParameters的Value一一对应,并且是解析之后的结果。
*
* @param sender 命令发送者
* @param args 命令的参数
*/
@Nullable
public Map.Entry matchAndParse(CommandSender sender, String commandLabel, String[] args) {
this.args = args;
this.sender = sender;
Map.Entry result = null;
final var error = new ArrayList();
for (final var entry : this.root.entrySet()) {
final var list = entry.getValue();
list.reset();
f2:
for (var node : list) {
while (!node.hasResult()) {
if (list.getIndex() >= args.length) {//参数用完
if (node.isOptional()) break f2;
list.getIndexAndIncrement();
node.error();
break f2;
}
node.fill(args[list.getIndexAndIncrement()]);
if (list.getError() != Integer.MIN_VALUE) {
break f2;
}
}
}
if (list.getError() == Integer.MIN_VALUE) {
if (entry.getValue().getIndex() < args.length) {//没用完参数
entry.getValue().getIndexAndIncrement();
entry.getValue().error();
error.add(entry.getValue());
} else {
result = Map.entry(entry.getKey(), list);//成功条件 命令链与参数长度相等 命令链必选参数全部有结果
break;
}
} else {
error.add(list);
}
}
if (result == null) {//全部不成功
final var list = error.stream().max(Comparator.comparingInt(ParamList::getError)).orElseGet(() -> {
var defaultList = new ParamList(this);
defaultList.error();
return defaultList;
});
final CommandLogger log = new CommandLogger(this.command, sender, commandLabel, args, new CommandOutputContainer(),
command instanceof PluginCommand> pluginCommand ? pluginCommand.getPlugin() : InternalPlugin.INSTANCE);
if (!list.getMessageContainer().getMessages().isEmpty()) {
for (var message : list.getMessageContainer().getMessages()) {
log.addMessage(message.getMessageId(), message.getParameters());
}
} else {
log.addSyntaxErrors(list.getError());
}
log.output();
return null;
} else {
return result;
}
}
public CommandSender getSender() {
return sender;
}
public String[] getArgs() {
return args;
}
public Command getCommand() {
return command;
}
public Map getRoot() {
return root;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy