From 42b30b93d8f170816606de35b3d4a5b6e7f5a874 Mon Sep 17 00:00:00 2001 From: CoolLoong <1542536763@qq.com> Date: Wed, 25 Jan 2023 21:02:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BAJS=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=91=BD=E4=BB=A4=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20(#962)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 增强JS插件注册命令的功能 1.JS插件现新增了完整的新建CommandParameter和CommandEnum的方法 2.JS插件注册命令后可以获取到命令对象 * refactor: 优化了之前的Message类型参数解析 * revert: 移除错误上传的运行配置 * 修订 --- .run/PNX.run.xml | 10 -- .../cn/nukkit/command/data/CommandEnum.java | 19 ++- .../nukkit/command/data/CommandParameter.java | 116 ++++++------------ .../command/defaults/EffectCommand.java | 14 +-- .../nukkit/command/defaults/GiveCommand.java | 108 ++++++++-------- .../nukkit/command/defaults/KickCommand.java | 14 +-- .../cn/nukkit/command/defaults/MeCommand.java | 22 +--- .../command/defaults/ReplaceItemCommand.java | 14 +-- .../nukkit/command/defaults/SayCommand.java | 22 +--- .../nukkit/command/defaults/TellCommand.java | 14 +-- .../nukkit/command/defaults/TitleCommand.java | 4 +- .../cn/nukkit/command/tree/ParamTree.java | 5 +- .../nukkit/command/tree/node/CommandNode.java | 9 +- .../command/tree/node/MessageStringNode.java | 62 ++++++++++ .../command/tree/node/PositionNode.java | 2 + .../command/tree/node/RemainStringNode.java | 21 +--- src/main/java/cn/nukkit/item/StringItem.java | 4 - .../cn/nukkit/plugin/js/JSEventManager.java | 81 +++++++----- src/main/js/inner-module/powernukkitx.js | 9 +- 19 files changed, 256 insertions(+), 294 deletions(-) delete mode 100644 .run/PNX.run.xml create mode 100644 src/main/java/cn/nukkit/command/tree/node/MessageStringNode.java diff --git a/.run/PNX.run.xml b/.run/PNX.run.xml deleted file mode 100644 index fff8696143..0000000000 --- a/.run/PNX.run.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/main/java/cn/nukkit/command/data/CommandEnum.java b/src/main/java/cn/nukkit/command/data/CommandEnum.java index 1219c9cebd..6f03587d71 100644 --- a/src/main/java/cn/nukkit/command/data/CommandEnum.java +++ b/src/main/java/cn/nukkit/command/data/CommandEnum.java @@ -4,18 +4,21 @@ import cn.nukkit.api.PowerNukkitXOnly; import cn.nukkit.api.Since; import cn.nukkit.network.protocol.UpdateSoftEnumPacket; +import cn.nukkit.potion.Effect; import com.google.common.collect.ImmutableList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.*; import java.util.function.Supplier; /** * @author CreeperFace */ public class CommandEnum { + @PowerNukkitXOnly + @Since("1.19.50-r4") + public static final CommandEnum ENUM_EFFECT; @PowerNukkitXOnly @Since("1.19.50-r4") public static final CommandEnum FUNCTION_FILE = new CommandEnum("filepath", () -> Server.getInstance().getFunctionManager().getFunctions().keySet(), true); @@ -54,6 +57,14 @@ public class CommandEnum { )*/ Collections.emptyList()); ENUM_ENTITY = new CommandEnum("Entity", Collections.emptyList()); + + List effects = new ArrayList<>(); + for (Field field : Effect.class.getDeclaredFields()) { + if (field.getType() == int.class && field.getModifiers() == (Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL)) { + effects.add(field.getName().toLowerCase()); + } + } + ENUM_EFFECT = new CommandEnum("Effect", effects, false); } private final String name; diff --git a/src/main/java/cn/nukkit/command/data/CommandParameter.java b/src/main/java/cn/nukkit/command/data/CommandParameter.java index 72a6f599df..64994f7835 100644 --- a/src/main/java/cn/nukkit/command/data/CommandParameter.java +++ b/src/main/java/cn/nukkit/command/data/CommandParameter.java @@ -11,7 +11,7 @@ import java.util.ArrayList; import java.util.List; -public class CommandParameter implements Cloneable { +public class CommandParameter { @PowerNukkitOnly @Since("1.4.0.0-PN") @@ -141,9 +141,9 @@ public static CommandParameter newType(String name, CommandParamType type) { /** - * optional = false + * optional = false,CommandParamOption=[] * - * @see #newType(String, boolean, CommandParamType, IParamNode) + * @see #newType(String, boolean, CommandParamType, IParamNode, CommandParamOption...) */ @PowerNukkitXOnly @Since("1.19.50-r3") @@ -153,31 +153,24 @@ public static CommandParameter newType(String name, CommandParamType type, IPara /** - * 创建一个命令参数,参数解析节点{@link IParamNode}依据参数类型{@link CommandParamType}自动选取 + * paramNode = null , CommandParamOption=[] * - * @param name 参数名 - * @param optional 该参数是否为可选参数 - * @param type 类型{@link CommandParamType} - * @return the command parameter + * @see #newType(String, boolean, CommandParamType, IParamNode, CommandParamOption...) */ @Since("1.4.0.0-PN") public static CommandParameter newType(String name, boolean optional, CommandParamType type) { - return new CommandParameter(name, optional, type, null, null); + return newType(name, optional, type, null, new CommandParamOption[]{}); } /** - * 创建一个命令参数,参数解析节点{@link IParamNode}依据参数类型{@link CommandParamType}自动选取 + * paramNode = null * - * @param name 参数名 - * @param optional 该参数是否为可选参数 - * @param type 类型{@link CommandParamType} - * @return the command parameter + * @see #newType(String, boolean, CommandParamType, IParamNode, CommandParamOption...) */ + @PowerNukkitXOnly @Since("1.19.50-r4") public static CommandParameter newType(String name, boolean optional, CommandParamType type, CommandParamOption... options) { - var result = new CommandParameter(name, optional, type, null, null); - result.paramOptions = Lists.newArrayList(options); - return result; + return newType(name, optional, type, null, options); } /** @@ -187,12 +180,17 @@ public static CommandParameter newType(String name, boolean optional, CommandPar * @param optional 该参数是否为可选参数 * @param type 类型{@link CommandParamType} * @param paramNode 用于解析该参数的参数节点 + * @param options the options * @return the command parameter */ @PowerNukkitXOnly - @Since("1.19.50-r3") - public static CommandParameter newType(String name, boolean optional, CommandParamType type, IParamNode paramNode) { - return new CommandParameter(name, optional, type, null, null, paramNode); + @Since("1.19.50-r4") + public static CommandParameter newType(String name, boolean optional, CommandParamType type, IParamNode paramNode, CommandParamOption... options) { + var result = new CommandParameter(name, optional, type, null, null, paramNode); + if (options.length != 0) { + result.paramOptions = Lists.newArrayList(options); + } + return result; } /** @@ -219,7 +217,7 @@ public static CommandParameter newEnum(String name, boolean optional, String[] v /** * optional = false * - * @see #newEnum(String name, boolean optional, String type) + * @see #newEnum(String, boolean, CommandEnum, IParamNode, CommandParamOption...) */ @Since("1.4.0.0-PN") public static CommandParameter newEnum(String name, String type) { @@ -227,9 +225,9 @@ public static CommandParameter newEnum(String name, String type) { } /** - * isSoft = false + * optional = false * - * @see #newEnum(String name, boolean optional, String type, boolean isSoft) + * @see #newEnum(String, boolean, CommandEnum, IParamNode, CommandParamOption...) */ @Since("1.4.0.0-PN") public static CommandParameter newEnum(String name, boolean optional, String type) { @@ -238,13 +236,9 @@ public static CommandParameter newEnum(String name, boolean optional, String typ /** - * 创建一个枚举参数,其枚举数据{@link CommandEnum#getValues()}为空列表 + * optional = false * - * @param name 参数名(不会显示到命令中,仅作为标识) - * @param optional 该枚举参数是否可选 - * @param type 枚举参数名(会显示到参数中) - * @param isSoft 当为False时,客户端显示枚举参数会带上枚举名称{@link CommandEnum#getName()} - * @return the command parameter + * @see #newEnum(String, boolean, CommandEnum, IParamNode, CommandParamOption...) */ @PowerNukkitXOnly @Since("1.6.0.0-PNX") @@ -263,12 +257,9 @@ public static CommandParameter newEnum(String name, CommandEnum data) { } /** - * 创建一个枚举参数 + * optional = false * - * @param name 参数名(不会显示到命令中,仅作为标识) - * @param optional 改参数是否可选 - * @param data 枚举数据{@link CommandEnum},其中的{@link CommandEnum#getName()}才是真正的枚举参数名 - * @return the command parameter + * @see #newEnum(String, boolean, CommandEnum, IParamNode, CommandParamOption...) */ @Since("1.4.0.0-PN") public static CommandParameter newEnum(String name, boolean optional, CommandEnum data) { @@ -276,45 +267,35 @@ public static CommandParameter newEnum(String name, boolean optional, CommandEnu } /** - * 创建一个枚举参数 + * optional = false * - * @param name 参数名称 - * @param optional 改参数是否可选 - * @param data 枚举数据{@link CommandEnum},其中的{@link CommandEnum#getName()}才是真正的枚举参数名 - * @param options the options - * @return the command parameter + * @see #newEnum(String, boolean, CommandEnum, IParamNode, CommandParamOption...) */ @PowerNukkitXOnly @Since("1.19.50-r4") public static CommandParameter newEnum(String name, boolean optional, CommandEnum data, CommandParamOption... options) { - var result = new CommandParameter(name, optional, null, data, null); - result.paramOptions = Lists.newArrayList(options); - return result; + return newEnum(name, optional, data, null, options); } /** - * New enum command parameter. + * optional = false * - * @param name the name - * @param optional the optional - * @param data the data - * @param paramNode the enum node - * @return the command parameter + * @see #newEnum(String, boolean, CommandEnum, IParamNode, CommandParamOption...) */ @PowerNukkitXOnly @Since("1.19.50-r4") public static CommandParameter newEnum(String name, boolean optional, CommandEnum data, IParamNode paramNode) { - return new CommandParameter(name, optional, null, data, null, paramNode); + return newEnum(name, optional, data, paramNode, new CommandParamOption[]{}); } /** - * New enum command parameter. + * 创建一个枚举参数 * - * @param name the name - * @param optional the optional - * @param data the data - * @param paramNode the enum node + * @param name 参数名称 + * @param optional 改参数是否可选 + * @param data 枚举数据{@link CommandEnum},其中的{@link CommandEnum#getName()}才是真正的枚举参数名 + * @param paramNode 该参数对应的{@link IParamNode} * @param options the options * @return the command parameter */ @@ -322,12 +303,14 @@ public static CommandParameter newEnum(String name, boolean optional, CommandEnu @Since("1.19.50-r4") public static CommandParameter newEnum(String name, boolean optional, CommandEnum data, IParamNode paramNode, CommandParamOption... options) { var result = new CommandParameter(name, optional, null, data, null, paramNode); - result.paramOptions = Lists.newArrayList(options); + if (options.length != 0) { + result.paramOptions = Lists.newArrayList(options); + } return result; } //此方法使用不当会崩溃客户端,请谨慎使用! - //todo 注释掉创建Postfix的方法知道能够稳定运行 + //todo 注释掉创建Postfix的方法直到能够稳定运行 /*@Since("1.4.0.0-PN") public static CommandParameter newPostfix(String name, String postfix) { return newPostfix(name, false, postfix); @@ -356,25 +339,6 @@ protected static CommandParamType fromString(String param) { return CommandParamType.RAWTEXT; } - @PowerNukkitXOnly - @Since("1.19.50-r4") - @Override - public CommandParameter clone() throws CloneNotSupportedException { - try { - CommandParameter commandParameter = (CommandParameter) super.clone(); - commandParameter.type = this.type; - commandParameter.name = this.name; - commandParameter.enumData = this.enumData; - commandParameter.optional = this.optional; - commandParameter.paramOptions = this.paramOptions; - commandParameter.postFix = this.postFix; - commandParameter.paramNode = this.paramNode; - return commandParameter; - } catch (CloneNotSupportedException e) { - return null; - } - } - @Deprecated @DeprecationDetails(since = "1.4.0.0-PN", reason = "Removed from Cloudburst Nukkit") @PowerNukkitOnly("Re-added for backward compatibility") diff --git a/src/main/java/cn/nukkit/command/defaults/EffectCommand.java b/src/main/java/cn/nukkit/command/defaults/EffectCommand.java index 971dc6f64c..ba8161fc48 100644 --- a/src/main/java/cn/nukkit/command/defaults/EffectCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/EffectCommand.java @@ -7,16 +7,12 @@ import cn.nukkit.command.data.CommandParamType; import cn.nukkit.command.data.CommandParameter; import cn.nukkit.command.tree.ParamList; -import cn.nukkit.command.tree.ParamTree; import cn.nukkit.command.utils.CommandLogger; import cn.nukkit.entity.Entity; import cn.nukkit.entity.item.EntityItem; import cn.nukkit.potion.Effect; import cn.nukkit.potion.InstantEffect; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -29,17 +25,9 @@ public EffectCommand(String name) { super(name, "commands.effect.description", "nukkit.command.effect.usage"); this.setPermission("nukkit.command.effect"); this.commandParameters.clear(); - - List effects = new ArrayList<>(); - for (Field field : Effect.class.getDeclaredFields()) { - if (field.getType() == int.class && field.getModifiers() == (Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL)) { - effects.add(field.getName().toLowerCase()); - } - } - this.commandParameters.put("default", new CommandParameter[]{ CommandParameter.newType("player", CommandParamType.TARGET), - CommandParameter.newEnum("effect", new CommandEnum("Effect", effects)), + CommandParameter.newEnum("effect", CommandEnum.ENUM_EFFECT), CommandParameter.newType("seconds", true, CommandParamType.INT), CommandParameter.newType("amplifier", true, CommandParamType.INT), CommandParameter.newEnum("hideParticle", true, CommandEnum.ENUM_BOOLEAN) diff --git a/src/main/java/cn/nukkit/command/defaults/GiveCommand.java b/src/main/java/cn/nukkit/command/defaults/GiveCommand.java index 9440be2871..4e7f09d550 100644 --- a/src/main/java/cn/nukkit/command/defaults/GiveCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/GiveCommand.java @@ -6,7 +6,6 @@ import cn.nukkit.command.data.CommandParamType; import cn.nukkit.command.data.CommandParameter; import cn.nukkit.command.tree.ParamList; -import cn.nukkit.command.tree.ParamTree; import cn.nukkit.command.tree.node.PlayersNode; import cn.nukkit.command.tree.node.RemainStringNode; import cn.nukkit.command.utils.CommandLogger; @@ -14,7 +13,6 @@ import cn.nukkit.item.ItemBlock; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -40,67 +38,67 @@ public GiveCommand(String name) { @Override public int execute(CommandSender sender, String commandLabel, Map.Entry result, CommandLogger log) { - var list = result.getValue(); + var list = result.getValue(); - Item item = list.getResult(1); - if (item.isNull() && item.getId() != 0) { - log.addError("commands.give.item.notFound", item.getName()).output(); + Item item = list.getResult(1); + if (item.isNull() && item.getId() != 0) { + log.addError("commands.give.item.notFound", item.getName()).output(); + return 0; + } + if (item instanceof ItemBlock && item.getBlock() instanceof BlockUnknown) { + log.addError("commands.give.block.notFound", item.getName()).output(); + return 0; + } + int count; + if (list.hasResult(2)) { + count = list.getResult(2); + if (count <= 0) { + log.addNumTooSmall(2, 1).output(); return 0; } - if (item instanceof ItemBlock && item.getBlock() instanceof BlockUnknown) { - log.addError("commands.give.block.notFound", item.getName()).output(); - return 0; - } - int count; - if (list.hasResult(2)) { - count = list.getResult(2); - if (count <= 0) { - log.addNumTooSmall(2, 1).output(); - return 0; - } - item.setCount(count); - } - if (list.hasResult(3)) { - int damage = list.getResult(3); - item.setDamage(damage); - } - if (list.hasResult(4)) { - String[] args = list.getResult(4); - Item.ItemJsonComponents components = Item.ItemJsonComponents.fromJson(String.join("", Arrays.copyOfRange(args, 0, args.length))); - item.readItemJsonComponents(components); - } + item.setCount(count); + } + if (list.hasResult(3)) { + int damage = list.getResult(3); + item.setDamage(damage); + } + if (list.hasResult(4)) { + String json = list.getResult(4); + Item.ItemJsonComponents components = Item.ItemJsonComponents.fromJson(json); + item.readItemJsonComponents(components); + } - List players = list.getResult(0); - for (Player player : players) { - Item[] returns = player.getInventory().addItem(item.clone()); - List drops = new ArrayList<>(); - for (Item returned : returns) { - int maxStackSize = returned.getMaxStackSize(); - if (returned.getCount() <= maxStackSize) { + List players = list.getResult(0); + for (Player player : players) { + Item[] returns = player.getInventory().addItem(item.clone()); + List drops = new ArrayList<>(); + for (Item returned : returns) { + int maxStackSize = returned.getMaxStackSize(); + if (returned.getCount() <= maxStackSize) { + drops.add(returned); + } else { + while (returned.getCount() > maxStackSize) { + Item drop = returned.clone(); + int toDrop = Math.min(returned.getCount(), maxStackSize); + drop.setCount(toDrop); + returned.setCount(returned.getCount() - toDrop); + drops.add(drop); + } + if (!returned.isNull()) { drops.add(returned); - } else { - while (returned.getCount() > maxStackSize) { - Item drop = returned.clone(); - int toDrop = Math.min(returned.getCount(), maxStackSize); - drop.setCount(toDrop); - returned.setCount(returned.getCount() - toDrop); - drops.add(drop); - } - if (!returned.isNull()) { - drops.add(returned); - } } } + } - for (Item drop : drops) { - player.dropItem(drop); - } - log.outputObjectWhisper(player, "commands.give.successRecipient", item.getName() + " (" + item.getNamespaceId() + (item.getDamage() != 0 ? ":" + item.getDamage() : "") + ")", - String.valueOf(item.getCount())); + for (Item drop : drops) { + player.dropItem(drop); } - log.addSuccess("commands.give.success", item.getName() + " (" + item.getNamespaceId() + (item.getDamage() != 0 ? ":" + item.getDamage() : "") + ")", - String.valueOf(item.getCount()), - players.stream().map(Player::getName).collect(Collectors.joining(","))).successCount(players.size()).output(true, true); - return players.size(); + log.outputObjectWhisper(player, "commands.give.successRecipient", item.getName() + " (" + item.getNamespaceId() + (item.getDamage() != 0 ? ":" + item.getDamage() : "") + ")", + String.valueOf(item.getCount())); + } + log.addSuccess("commands.give.success", item.getName() + " (" + item.getNamespaceId() + (item.getDamage() != 0 ? ":" + item.getDamage() : "") + ")", + String.valueOf(item.getCount()), + players.stream().map(Player::getName).collect(Collectors.joining(","))).successCount(players.size()).output(true, true); + return players.size(); } } diff --git a/src/main/java/cn/nukkit/command/defaults/KickCommand.java b/src/main/java/cn/nukkit/command/defaults/KickCommand.java index 9d4351ed81..553b2ed2bb 100644 --- a/src/main/java/cn/nukkit/command/defaults/KickCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/KickCommand.java @@ -6,7 +6,6 @@ import cn.nukkit.command.data.CommandParamType; import cn.nukkit.command.data.CommandParameter; import cn.nukkit.command.tree.ParamList; -import cn.nukkit.command.tree.ParamTree; import cn.nukkit.command.tree.node.PlayersNode; import cn.nukkit.command.utils.CommandLogger; import cn.nukkit.event.player.PlayerKickEvent; @@ -36,20 +35,13 @@ public KickCommand(String name) { public int execute(CommandSender sender, String commandLabel, Map.Entry result, CommandLogger log) { var list = result.getValue(); List players = list.getResult(0); - StringBuilder reason = new StringBuilder(); + String reason = ""; if (list.hasResult(1)) { - String[] args = list.getResult(1); - for (int i = 1; i < args.length; i++) { - reason.append(args[i]).append(" "); - } - } - - if (reason.length() > 0) { - reason = new StringBuilder(reason.substring(0, reason.length() - 1)); + reason = list.getResult(1); } for (Player player : players) { - player.kick(PlayerKickEvent.Reason.KICKED_BY_ADMIN, reason.toString()); + player.kick(PlayerKickEvent.Reason.KICKED_BY_ADMIN, reason); if (reason.length() >= 1) { log.addSuccess("commands.kick.success.reason", player.getName(), reason.toString()); } else { diff --git a/src/main/java/cn/nukkit/command/defaults/MeCommand.java b/src/main/java/cn/nukkit/command/defaults/MeCommand.java index 0aa9d597a2..6a757e6f5d 100644 --- a/src/main/java/cn/nukkit/command/defaults/MeCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/MeCommand.java @@ -5,10 +5,7 @@ import cn.nukkit.command.data.CommandParamType; import cn.nukkit.command.data.CommandParameter; import cn.nukkit.command.tree.ParamList; -import cn.nukkit.command.tree.ParamTree; import cn.nukkit.command.utils.CommandLogger; -import cn.nukkit.command.utils.EntitySelector; -import cn.nukkit.entity.Entity; import cn.nukkit.lang.TranslationContainer; import cn.nukkit.utils.TextFormat; @@ -35,25 +32,12 @@ public MeCommand(String name) { @Override public int execute(CommandSender sender, String commandLabel, Map.Entry result, CommandLogger log) { String name = sender.getName(); - String[] args; + String message = ""; if (result.getKey().equals("message")) { - args = result.getValue().getResult(0); - } else args = new String[]{""}; - StringBuilder msg = new StringBuilder(); - for (String arg : args) { - if (EntitySelector.hasArguments(arg)) { - for (Entity entity : EntitySelector.matchEntities(sender, arg)) { - msg.append(entity.getName()).append(" "); - } - } else { - msg.append(arg).append(" "); - } + message = result.getValue().getResult(0); } - if (msg.length() > 0) { - msg = new StringBuilder(msg.substring(0, msg.length() - 1)); - } - broadcastCommandMessage(sender, new TranslationContainer("chat.type.emote", name, TextFormat.WHITE + msg.toString()), true); + broadcastCommandMessage(sender, new TranslationContainer("chat.type.emote", name, TextFormat.WHITE + message), true); return 1; } } diff --git a/src/main/java/cn/nukkit/command/defaults/ReplaceItemCommand.java b/src/main/java/cn/nukkit/command/defaults/ReplaceItemCommand.java index 8dd5313c86..00f3169acd 100644 --- a/src/main/java/cn/nukkit/command/defaults/ReplaceItemCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/ReplaceItemCommand.java @@ -10,7 +10,6 @@ import cn.nukkit.command.data.CommandParamType; import cn.nukkit.command.data.CommandParameter; import cn.nukkit.command.tree.ParamList; -import cn.nukkit.command.tree.ParamTree; import cn.nukkit.command.utils.CommandLogger; import cn.nukkit.entity.Entity; import cn.nukkit.inventory.EntityInventoryHolder; @@ -20,7 +19,6 @@ import java.util.List; import java.util.Map; -import java.util.StringJoiner; @PowerNukkitXOnly @Since("1.6.0.0-PNX") @@ -133,10 +131,8 @@ public int execute(CommandSender sender, String commandLabel, Map.Entry result, CommandLogger log) { String senderString = sender.getName(); - String[] message = result.getValue().getResult(0); - StringBuilder msg = new StringBuilder(); - for (String arg : message) { - if (EntitySelector.hasArguments(arg)) { - List entities = EntitySelector.matchEntities(sender, arg); - for (Entity entity : entities) { - msg.append(entity.getName()).append(" "); - } - } else { - msg.append(arg).append(" "); - } - } - if (msg.length() > 0) { - msg = new StringBuilder(msg.substring(0, msg.length() - 1)); - } - sender.getServer().broadcastMessage(new TranslationContainer("%chat.type.announcement", senderString, msg.toString())); + String message = result.getValue().getResult(0); + sender.getServer().broadcastMessage(new TranslationContainer("%chat.type.announcement", senderString, message)); return 1; } } diff --git a/src/main/java/cn/nukkit/command/defaults/TellCommand.java b/src/main/java/cn/nukkit/command/defaults/TellCommand.java index 0de8a3d170..7bec181ab6 100644 --- a/src/main/java/cn/nukkit/command/defaults/TellCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/TellCommand.java @@ -6,7 +6,6 @@ import cn.nukkit.command.data.CommandParamType; import cn.nukkit.command.data.CommandParameter; import cn.nukkit.command.tree.ParamList; -import cn.nukkit.command.tree.ParamTree; import cn.nukkit.command.tree.node.PlayersNode; import cn.nukkit.command.utils.CommandLogger; import cn.nukkit.lang.TranslationContainer; @@ -36,18 +35,11 @@ public TellCommand(String name) { public int execute(CommandSender sender, String commandLabel, Map.Entry result, CommandLogger log) { var list = result.getValue(); List players = list.getResult(0); - StringBuilder msg = new StringBuilder(); - String[] args = list.getResult(1); - for (int i = 0; i < args.length; i++) { - msg.append(args[i]).append(" "); - } - if (msg.length() > 0) { - msg = new StringBuilder(msg.substring(0, msg.length() - 1)); - } + String msg = list.getResult(1); for (Player player : players) { if (player == sender) continue; - log.addSuccess("commands.message.display.outgoing", player.getName(), msg.toString()); - player.sendMessage(new TranslationContainer("commands.message.display.incoming", sender.getName(), msg.toString())); + log.addSuccess("commands.message.display.outgoing", player.getName(), msg); + player.sendMessage(new TranslationContainer("commands.message.display.incoming", sender.getName(), msg)); } log.output(); return 1; diff --git a/src/main/java/cn/nukkit/command/defaults/TitleCommand.java b/src/main/java/cn/nukkit/command/defaults/TitleCommand.java index 5c8ee2f16d..7e301f8b86 100644 --- a/src/main/java/cn/nukkit/command/defaults/TitleCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/TitleCommand.java @@ -7,7 +7,6 @@ import cn.nukkit.command.data.CommandParamType; import cn.nukkit.command.data.CommandParameter; import cn.nukkit.command.tree.ParamList; -import cn.nukkit.command.tree.ParamTree; import cn.nukkit.command.tree.node.PlayersNode; import cn.nukkit.command.utils.CommandLogger; import cn.nukkit.utils.TextFormat; @@ -71,8 +70,7 @@ public int execute(CommandSender sender, String commandLabel, Map.Entry { String titleLocation = list.getResult(1); - String[] message = list.getResult(2); - var titleText = String.join(" ", message); + String titleText = list.getResult(2); switch (titleLocation) { case "title" -> { for (Player player : players) { diff --git a/src/main/java/cn/nukkit/command/tree/ParamTree.java b/src/main/java/cn/nukkit/command/tree/ParamTree.java index 463e6c65fc..1f439cb658 100644 --- a/src/main/java/cn/nukkit/command/tree/ParamTree.java +++ b/src/main/java/cn/nukkit/command/tree/ParamTree.java @@ -96,7 +96,10 @@ public ParamTree(Command command) { case COMPARE_OPERATOR -> { node = new CompareOperatorStringNode(); } - case MESSAGE, JSON -> { + case MESSAGE -> { + node = new MessageStringNode(); + } + case JSON -> { node = new RemainStringNode(); } case RAWTEXT -> { diff --git a/src/main/java/cn/nukkit/command/tree/node/CommandNode.java b/src/main/java/cn/nukkit/command/tree/node/CommandNode.java index 0f8a20b3af..7a50935596 100644 --- a/src/main/java/cn/nukkit/command/tree/node/CommandNode.java +++ b/src/main/java/cn/nukkit/command/tree/node/CommandNode.java @@ -3,7 +3,10 @@ import cn.nukkit.api.PowerNukkitXOnly; import cn.nukkit.api.Since; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * 将全部剩余的参数以空格为分隔符合并,解析为{@link String}值 @@ -30,9 +33,7 @@ public void fill(String arg) { TMP.add(arg); } else { TMP.add(arg); - var join = new StringJoiner(" "); - TMP.forEach(join::add); - this.value = join.toString(); + this.value = String.join(" ", TMP); first = true; } } diff --git a/src/main/java/cn/nukkit/command/tree/node/MessageStringNode.java b/src/main/java/cn/nukkit/command/tree/node/MessageStringNode.java new file mode 100644 index 0000000000..403d8206a0 --- /dev/null +++ b/src/main/java/cn/nukkit/command/tree/node/MessageStringNode.java @@ -0,0 +1,62 @@ +package cn.nukkit.command.tree.node; + +import cn.nukkit.api.PowerNukkitXOnly; +import cn.nukkit.api.Since; +import cn.nukkit.command.utils.EntitySelector; +import cn.nukkit.entity.Entity; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; +import java.util.regex.Pattern; + +/** + * 解析全部剩余参数拼接为{@code String}值 + *

+ * 所有命令参数类型为{@link cn.nukkit.command.data.CommandParamType#MESSAGE MESSAGE} + * 如果没有手动指定{@link IParamNode},则会默认使用这个解析 + */ +@PowerNukkitXOnly +@Since("1.19.50-r4") +public class MessageStringNode extends ParamNode { + private final Pattern target = Pattern.compile("@([aeprs]|initiator)"); + + private final List TMP = new ArrayList<>(); + + @Override + public void fill(String arg) { + if (this.parent.getIndex() != this.parent.parent.getArgs().length) TMP.add(arg); + else { + TMP.add(arg); + + var str = String.join(" ", TMP); + var match = target.matcher(str); + this.value = match.replaceAll(r -> { + var start = Math.max(0, match.start() - 1); + var end = Math.min(str.length(), match.end()); + if (start != 0) { + char before = str.charAt(start); + if (before == '”' || before == '\'' || before == '\\' || before == ';') return match.group(); + } + if (end != str.length()) { + char after = str.charAt(end); + if (after == '”' || after == '\'' || after == '\\' || after == ';') return match.group(); + } + var m = match.group(); + if (EntitySelector.hasArguments(m)) { + StringJoiner join = new StringJoiner(", "); + for (Entity entity : EntitySelector.matchEntities(this.parent.parent.getSender(), m)) { + join.add(entity.getName()); + } + return join.toString(); + } else return m; + }); + } + } + + @Override + public void reset() { + super.reset(); + TMP.clear(); + } +} diff --git a/src/main/java/cn/nukkit/command/tree/node/PositionNode.java b/src/main/java/cn/nukkit/command/tree/node/PositionNode.java index ddc3f05c99..a1dacf8a23 100644 --- a/src/main/java/cn/nukkit/command/tree/node/PositionNode.java +++ b/src/main/java/cn/nukkit/command/tree/node/PositionNode.java @@ -50,6 +50,7 @@ public E get(Position basePos) { @Override public void fill(String arg) { TMP.clear(); + //check var matcher = pattern.matcher(arg); while (matcher.find()) { TMP.add(matcher.group()); @@ -57,6 +58,7 @@ public void fill(String arg) { var str = TMP.stream().reduce((s1, s2) -> s1 + s2); if (str.isEmpty()) this.error(); else if (str.get().length() != arg.length()) this.error(); + //parse else { try { Location loc = this.parent.parent.getSender().getLocation(); diff --git a/src/main/java/cn/nukkit/command/tree/node/RemainStringNode.java b/src/main/java/cn/nukkit/command/tree/node/RemainStringNode.java index 1762b1bc48..fb61b90fcc 100644 --- a/src/main/java/cn/nukkit/command/tree/node/RemainStringNode.java +++ b/src/main/java/cn/nukkit/command/tree/node/RemainStringNode.java @@ -7,24 +7,14 @@ import java.util.List; /** - * 解析全部剩余参数为{@code String[]}值 + * 解析全部剩余参数拼接为{@code String}值 *

- * 所有命令参数类型为{@link cn.nukkit.command.data.CommandParamType#MESSAGE MESSAGE} , {@link cn.nukkit.command.data.CommandParamType#JSON JSON}的 + * 所有命令参数类型为{@link cn.nukkit.command.data.CommandParamType#JSON JSON}的 * 如果没有手动指定{@link IParamNode},则会默认使用这个解析 */ @PowerNukkitXOnly @Since("1.19.50-r4") -public class RemainStringNode extends ParamNode { - private final String defaultStr; - - public RemainStringNode() { - defaultStr = null; - } - - public RemainStringNode(String defaultStr) { - this.defaultStr = defaultStr; - } - +public class RemainStringNode extends ParamNode { private final List TMP = new ArrayList<>(); @Override @@ -32,14 +22,13 @@ public void fill(String arg) { if (this.parent.getIndex() != this.parent.parent.getArgs().length) TMP.add(arg); else { TMP.add(arg); - this.value = TMP.toArray(new String[]{}); + this.value = String.join("", TMP); } } @Override public void reset() { - if (defaultStr != null) this.value = new String[]{defaultStr}; - else super.reset(); + super.reset(); TMP.clear(); } } diff --git a/src/main/java/cn/nukkit/item/StringItem.java b/src/main/java/cn/nukkit/item/StringItem.java index ff940edc4c..cc61022166 100644 --- a/src/main/java/cn/nukkit/item/StringItem.java +++ b/src/main/java/cn/nukkit/item/StringItem.java @@ -14,7 +14,6 @@ * @since 2021-06-12 */ @PowerNukkitOnly -@Since("FUTURE") public class StringItem extends Item { private final String id; @@ -27,7 +26,6 @@ private static String notEmpty(String value) { } @PowerNukkitOnly - @Since("FUTURE") public StringItem(@Nonnull String id, @Nullable String name) { super(STRING_IDENTIFIED_ITEM, 0, 1, notEmpty(name)); Preconditions.checkNotNull(id, "id can't be null"); @@ -41,14 +39,12 @@ public boolean hasCompoundTag() { return true; } - @Since("FUTURE") @PowerNukkitOnly @Override public boolean hasCustomCompoundTag() { return customCompound != null && customCompound.length > 0; } - @Since("FUTURE") @PowerNukkitOnly @Override public byte[] getCustomCompoundTag() { diff --git a/src/main/java/cn/nukkit/plugin/js/JSEventManager.java b/src/main/java/cn/nukkit/plugin/js/JSEventManager.java index c1fc666f3c..3e27a1aae0 100644 --- a/src/main/java/cn/nukkit/plugin/js/JSEventManager.java +++ b/src/main/java/cn/nukkit/plugin/js/JSEventManager.java @@ -1,11 +1,16 @@ package cn.nukkit.plugin.js; import cn.nukkit.Server; +import cn.nukkit.api.Since; import cn.nukkit.command.Command; import cn.nukkit.command.CommandSender; import cn.nukkit.command.data.CommandEnum; +import cn.nukkit.command.data.CommandParamOption; import cn.nukkit.command.data.CommandParamType; import cn.nukkit.command.data.CommandParameter; +import cn.nukkit.command.tree.ParamList; +import cn.nukkit.command.tree.node.IParamNode; +import cn.nukkit.command.utils.CommandLogger; import cn.nukkit.event.Event; import cn.nukkit.event.EventPriority; import cn.nukkit.plugin.CommonJSPlugin; @@ -51,17 +56,17 @@ public CommandBuilder commandBuilder() { public static final class CommandBuilder { private final CommonJSPlugin jsPlugin; + private Command command; private String commandName; private String description; private String usageMessage; private String[] alias; private String permission; private String permissionMessage; - private Map commandParameters; private Value callback; - private String currentCommandPatternId; - private List currentCommandParameterList; + private final List currentCommandParameterList = new ArrayList<>(3); + private final Map commandParameters = new HashMap<>(2); public CommandBuilder(CommonJSPlugin jsPlugin) { this.jsPlugin = jsPlugin; @@ -140,7 +145,8 @@ public Map getCommandParameters() { } public CommandBuilder setCommandParameters(Map commandParameters) { - this.commandParameters = commandParameters; + this.commandParameters.clear(); + this.commandParameters.putAll(commandParameters); return this; } @@ -153,27 +159,27 @@ public CommandBuilder setCallback(Value callback) { return this; } + public CommandBuilder createDefaultPattern() { + return createCommandPattern("default"); + } + public CommandBuilder createCommandPattern(String patternName) { - if (currentCommandPatternId != null && currentCommandParameterList != null && currentCommandParameterList.size() != 0) { - if (commandParameters == null) { - commandParameters = new HashMap<>(2); - } - commandParameters.put(currentCommandPatternId, currentCommandParameterList.toArray(CommandParameter.EMPTY_ARRAY)); - } currentCommandPatternId = patternName; - currentCommandParameterList = new ArrayList<>(3); + commandParameters.put(patternName, currentCommandParameterList.toArray(CommandParameter.EMPTY_ARRAY)); + currentCommandParameterList.clear(); return this; } - public CommandBuilder createDefaultPattern() { - return createCommandPattern("default"); - } - public CommandBuilder addTypeParameter(String name, boolean optional, CommandParamType commandParamType) { currentCommandParameterList.add(CommandParameter.newType(name, optional, commandParamType)); return this; } + public CommandBuilder addCustomTypeParameter(String name, boolean optional, CommandParamType type, IParamNode paramNode, CommandParamOption... options) { + currentCommandParameterList.add(CommandParameter.newType(name, optional, type, paramNode, options)); + return this; + } + public CommandBuilder addIntParameter(String name, boolean optional) { return addTypeParameter(name, optional, CommandParamType.INT); } @@ -239,6 +245,11 @@ public CommandBuilder addEnumParameter(String name, boolean optional, String... return this; } + public CommandBuilder addCustomEnumParameter(String name, boolean optional, CommandEnum data, IParamNode paramNode, CommandParamOption... options) { + currentCommandParameterList.add(CommandParameter.newEnum(name, optional, data, paramNode, options)); + return this; + } + public CommandBuilder addEnumBlockParameter(String name, boolean optional) { currentCommandParameterList.add(CommandParameter.newEnum(name, optional, CommandEnum.ENUM_BLOCK)); return this; @@ -265,13 +276,11 @@ public CommandBuilder addEnumGameModeParameter(String name, boolean optional) { } public boolean register() { - if (currentCommandPatternId != null && currentCommandParameterList != null && currentCommandParameterList.size() != 0) { - if (commandParameters == null) { - commandParameters = new HashMap<>(2); - } + if (currentCommandPatternId != null && currentCommandParameterList.size() != 0) { commandParameters.put(currentCommandPatternId, currentCommandParameterList.toArray(CommandParameter.EMPTY_ARRAY)); } - if (commandName.toLowerCase().equals(commandName)) { + if (commandParameters.isEmpty()) commandParameters.put("default", CommandParameter.EMPTY_ARRAY); + if (commandName.toLowerCase().equals(commandName)) {//强制命令名小写 if (!callback.canExecute()) { return false; } @@ -281,32 +290,36 @@ public boolean register() { if (alias == null) { alias = new String[0]; } - var cmd = new Command(commandName, description, - usageMessage, alias) { + command = new Command(commandName, description, usageMessage, alias) { + @Since("1.19.50-r4") @Override - public boolean execute(CommandSender sender, String commandLabel, String... args) { + public int execute(CommandSender sender, String commandLabel, Map.Entry result, CommandLogger log) { synchronized (jsPlugin.getJsContext()) { - var result = callback.execute(sender, args); - if (result.isBoolean()) { - return result.asBoolean(); - } else return !result.isNull(); + var r = callback.execute(sender, result, log); + if (r.isBoolean()) { + return r.asBoolean() ? 1 : 0; + } else if (r.isNumber()) { + return r.asInt(); + } else return r.isNull() ? 0 : 1; } } }; if (permission != null) { - cmd.setPermission(permission); + command.setPermission(permission); } if (permissionMessage != null) { - cmd.setPermissionMessage(permissionMessage); - } - if (commandParameters != null) { - cmd.setCommandParameters(commandParameters); + command.setPermissionMessage(permissionMessage); } - Server.getInstance().getCommandMap().register(jsPlugin.getName(), cmd); + command.setCommandParameters(commandParameters); + command.enableParamTree(); + Server.getInstance().getCommandMap().register(jsPlugin.getName(), command); return true; } return false; } - } + public Command getBuildCommand() { + return command; + } + } } diff --git a/src/main/js/inner-module/powernukkitx.js b/src/main/js/inner-module/powernukkitx.js index b898e6aad7..66e64a2f16 100644 --- a/src/main/js/inner-module/powernukkitx.js +++ b/src/main/js/inner-module/powernukkitx.js @@ -59,11 +59,12 @@ export const PowerNukkitX = { * setPermissionMessage: (string) => this, * getCommandParameters: () => Map, * setCommandParameters: (parameterJavaMap: Map) => this, - * getCallback: () => (sender, string[]) => void, - * setCallback: (callback: (sender, string[]) => void) => this, + * getCallback: () => (sender: Object, result: Object, log: Object) => void, + * setCallback: (callback: (sender: Object, result: Object, log: Object) => void) => this, * createCommandPattern: (string) => this, * createDefaultPattern: () => this, * addTypeParameter: (name: string, optional: boolean, commandParamType: Object) => this, + * addCustomTypeParameter: (name: string, optional: boolean, commandParamType: Object,paramNode : Object,options: Object) => this, * addIntParameter: (name: string, optional: boolean) => this, * addFloatParameter: (name: string, optional: boolean) => this, * addValueParameter: (name: string, optional: boolean) => this, @@ -80,12 +81,14 @@ export const PowerNukkitX = { * addFilePathParameter: (name: string, optional: boolean) => this, * addOperatorParameter: (name: string, optional: boolean) => this, * addEnumParameter: (name: string, optional: boolean, ...string) => this, + * addCustomEnumParameter: (name: string, optional: boolean, data: Object, paramNode: Object, options: Object[]) => this, * addEnumBlockParameter: (name: string, optional: boolean) => this, * addEnumEntityParameter: (name: string, optional: boolean) => this, * addEnumItemParameter: (name: string, optional: boolean) => this, * addEnumBooleanParameter: (name: string, optional: boolean) => this, * addEnumGameModeParameter: (name: string, optional: boolean) => this, - * register: () => boolean + * register: () => boolean, + * getBuildCommand: () => Object * }} */ commandBuilder: () => eventManager.commandBuilder()