From 94abb2365555e0adbf3ae69e2bf86877bc7bb0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=A2=E5=85=B9=E6=B0=A7?= Date: Sat, 21 Jun 2025 21:13:29 +0800 Subject: [PATCH] Add tag management functionality, including command implementations for adding, removing, checking, and fetching tags --- .../fakeplayer/api/spi/NMSServerPlayer.java | 28 ++++++ .../core/command/CommandRegistry.java | 9 +- .../core/command/CommandSupports.java | 38 +++++--- .../core/command/impl/TagCommand.java | 91 +++++++++++++++++++ .../core/command/impl/TagCommandProvider.java | 15 +++ .../core/manager/FakeplayerManager.java | 22 +++++ .../v1_21_5/spi/NMSServerPlayerImpl.java | 20 ++++ 7 files changed, 209 insertions(+), 14 deletions(-) create mode 100644 fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/impl/TagCommand.java create mode 100644 fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/impl/TagCommandProvider.java diff --git a/fakeplayer-api/src/main/java/io/github/hello09x/fakeplayer/api/spi/NMSServerPlayer.java b/fakeplayer-api/src/main/java/io/github/hello09x/fakeplayer/api/spi/NMSServerPlayer.java index 960c258..57621b5 100644 --- a/fakeplayer-api/src/main/java/io/github/hello09x/fakeplayer/api/spi/NMSServerPlayer.java +++ b/fakeplayer-api/src/main/java/io/github/hello09x/fakeplayer/api/spi/NMSServerPlayer.java @@ -221,4 +221,32 @@ public interface NMSServerPlayer { */ void swapItemWithOffhand(); + /** + * 添加标签 + * @param tag 标签 + * @return 是否添加成功 + */ + boolean addTag(@NotNull String tag); + + /** + * 移除标签 + * @param tag 标签 + * @return 是否移除成功 + */ + boolean removeTag(@NotNull String tag); + + /** + * 是否拥有标签 + * @param tag 标签 + * @return 是否拥有 + */ + boolean hasTag(@NotNull String tag); + + /** + * 获取所有标签 + * @return 标签集合 + */ + @NotNull + java.util.Set getTags(); + } diff --git a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/CommandRegistry.java b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/CommandRegistry.java index db8c01e..24744d3 100644 --- a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/CommandRegistry.java +++ b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/CommandRegistry.java @@ -79,6 +79,8 @@ public class CommandRegistry { private DebugCommand debugCommand; @Inject private StopCommand stopCommand; + @Inject + private TagCommand tagCommand; @Inject private FakeplayerConfig config; @@ -457,8 +459,11 @@ public class CommandRegistry { text("message") ) .executes(debugCommand::sendPluginMessage) - ) - + ), + command("tag") + .withPermission(Permission.basic) + .withShortDescription("管理假人标签") + .executesPlayer((player, args) -> tagCommand.getCommand().execute(player, args)) ); HelpCommand.generateHelpCommand(root, true); root.register(); diff --git a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/CommandSupports.java b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/CommandSupports.java index 57a7161..19d768e 100644 --- a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/CommandSupports.java +++ b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/CommandSupports.java @@ -66,9 +66,20 @@ public abstract class CommandSupports { public static @NotNull Argument fakeplayer(@NotNull String nodeName, @Nullable Predicate predicate) { return new CustomArgument<>(new StringArgument(nodeName), info -> { var sender = info.sender(); - var target = sender.isOp() - ? manager.get(info.currentInput()) - : manager.get(sender, info.currentInput()); + var input = info.currentInput(); + Player target = null; + if (input.startsWith("*")) { + // 标签选择,返回第一个匹配的假人 + var tag = input.substring(1); + var list = manager.getByTag(sender, tag); + if (!list.isEmpty()) { + target = list.get(0).getPlayer(); + } + } else { + target = sender.isOp() + ? manager.get(input) + : manager.get(sender, input); + } if (predicate != null && target != null && !predicate.test(target)) { target = null; } @@ -76,16 +87,17 @@ public abstract class CommandSupports { }).replaceSuggestions(ArgumentSuggestions.strings(info -> { var sender = info.sender(); var arg = info.currentArg(); - var targets = sender.isOp() ? manager.getAll(predicate) : manager.getAll(sender, predicate); - var names = targets.stream().map(Player::getName); + // 标签补全 + var tagNames = manager.getByTag(sender, arg.startsWith("*") ? arg.substring(1) : arg) + .stream().map(fp -> "*" + arg).distinct(); + names = Stream.concat(names, tagNames); if (!arg.isEmpty()) { names = names.filter(n -> n.toLowerCase().contains(arg)); } - return names.toArray(String[]::new); })); } @@ -99,29 +111,31 @@ public abstract class CommandSupports { return new CustomArgument, String>(new StringArgument(nodeName), info -> { var sender = info.sender(); var arg = info.currentInput(); - if (arg.equals("-a")) { return manager.getAll(sender); } - + if (arg.startsWith("*")) { + var tag = arg.substring(1); + return manager.getByTag(sender, tag).stream().map(Fakeplayer::getPlayer).toList(); + } var target = sender.isOp() ? manager.get(arg) : manager.get(sender, arg); - return target == null ? Collections.emptyList() : Collections.singletonList(target); }).replaceSuggestions(ArgumentSuggestions.strings(info -> { var sender = info.sender(); var arg = info.currentArg().toLowerCase(); - var fakes = sender.isOp() ? manager.getAll() : manager.getAll(sender); - var names = Stream.concat(fakes.stream().map(Player::getName), Stream.of("-a")); + // 标签补全 + var tagNames = manager.getByTag(sender, arg.startsWith("*") ? arg.substring(1) : arg) + .stream().map(fp -> "*" + arg).distinct(); + names = Stream.concat(names, tagNames); if (!arg.isEmpty()) { names = names.filter(n -> n.toLowerCase().contains(arg)); } - return names.toArray(String[]::new); })); } diff --git a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/impl/TagCommand.java b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/impl/TagCommand.java new file mode 100644 index 0000000..21b05f1 --- /dev/null +++ b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/impl/TagCommand.java @@ -0,0 +1,91 @@ +package io.github.hello09x.fakeplayer.core.command.impl; + +import dev.jorel.commandapi.CommandAPICommand; +import dev.jorel.commandapi.CommandPermission; +import dev.jorel.commandapi.arguments.StringArgument; +import io.github.hello09x.fakeplayer.core.entity.Fakeplayer; +import io.github.hello09x.fakeplayer.core.manager.FakeplayerManager; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; +import java.util.stream.Collectors; + +import static net.kyori.adventure.text.Component.text; +import static net.kyori.adventure.text.format.NamedTextColor.*; + +public class TagCommand { + private final FakeplayerManager manager; + + public TagCommand(FakeplayerManager manager) { + this.manager = manager; + } + + public CommandAPICommand getCommand() { + return new CommandAPICommand("tag") + .withPermission(CommandPermission.fromString("fakeplayer.command.tag")) + .withSubcommand(new CommandAPICommand("add") + .withArguments(new StringArgument("tag")) + .withOptionalArguments(new StringArgument("--all").setOptional(true)) + .executesPlayer((player, args) -> { + String tag = (String) args.get(0); + boolean all = args.size() > 1 && "--all".equals(args.get(1)); + if (all) { + var list = manager.getAll(player); + int success = 0, exist = 0; + for (var p : list) { + var fake = manager.getByOwner(p); + if (fake != null) { + if (fake.getHandle().addTag(tag)) success++; + else exist++; + } + } + player.sendMessage(text("批量添加标签: " + tag + ",成功 " + success + " 个,已存在 " + exist + " 个", GREEN)); + } else { + Fakeplayer fake = getSelfFakeplayer(player); + if (fake == null) return; + if (fake.getHandle().addTag(tag)) { + player.sendMessage(text("已添加标签: " + tag, GREEN)); + } else { + player.sendMessage(text("标签已存在: " + tag, YELLOW)); + } + } + }) + ) + .withSubcommand(new CommandAPICommand("remove") + .withArguments(new StringArgument("tag")) + .executesPlayer((player, args) -> { + Fakeplayer fake = getSelfFakeplayer(player); + if (fake == null) return; + String tag = (String) args.get(0); + if (fake.getHandle().removeTag(tag)) { + player.sendMessage(text("已移除标签: " + tag, GREEN)); + } else { + player.sendMessage(text("标签不存在: " + tag, YELLOW)); + } + }) + ) + .withSubcommand(new CommandAPICommand("list") + .executesPlayer((player, args) -> { + Fakeplayer fake = getSelfFakeplayer(player); + if (fake == null) return; + Set tags = fake.getHandle().getTags(); + if (tags.isEmpty()) { + player.sendMessage(text("当前没有标签", GRAY)); + } else { + player.sendMessage(text("标签: " + String.join(", ", tags), AQUA)); + } + }) + ); + } + + private Fakeplayer getSelfFakeplayer(@NotNull Player player) { + Fakeplayer fake = manager.getByOwner(player); + if (fake == null) { + player.sendMessage(text("你没有可操作的假人", RED)); + return null; + } + return fake; + } +} diff --git a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/impl/TagCommandProvider.java b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/impl/TagCommandProvider.java new file mode 100644 index 0000000..60a28d8 --- /dev/null +++ b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/command/impl/TagCommandProvider.java @@ -0,0 +1,15 @@ +package io.github.hello09x.fakeplayer.core.command.impl; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import io.github.hello09x.fakeplayer.core.manager.FakeplayerManager; + +public class TagCommandProvider implements Provider { + @Inject + private FakeplayerManager manager; + + @Override + public TagCommand get() { + return new TagCommand(manager); + } +} diff --git a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/manager/FakeplayerManager.java b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/manager/FakeplayerManager.java index e33b1d8..1ebe880 100644 --- a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/manager/FakeplayerManager.java +++ b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/manager/FakeplayerManager.java @@ -490,4 +490,26 @@ public class FakeplayerManager { Exceptions.suppress(Main.getInstance(), this.lagMonitor::shutdownNow); } + /** + * 获取玩家当前选中的假人(如果没有则取第一个自己创建的假人) + */ + public Fakeplayer getByOwner(Player player) { + Player selected = getSelection(player); + if (selected != null) { + return this.playerList.getByUUID(selected.getUniqueId()); + } + // 没有选中则取第一个自己创建的 + List list = this.playerList.getByCreator(player.getName()); + return list.isEmpty() ? null : list.get(0); + } + + /** + * 获取玩家自己创建且带指定标签的所有假人 + */ + public List getByTag(@NotNull CommandSender owner, @NotNull String tag) { + return this.playerList.getByCreator(owner.getName()) + .stream() + .filter(fp -> fp.getHandle().hasTag(tag)) + .toList(); + } } diff --git a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerPlayerImpl.java b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerPlayerImpl.java index 007352e..210da13 100644 --- a/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerPlayerImpl.java +++ b/fakeplayer-v1_21_5/src/main/java/io/github/hello09x/fakeplayer/v1_21_5/spi/NMSServerPlayerImpl.java @@ -251,4 +251,24 @@ public class NMSServerPlayerImpl implements NMSServerPlayer { )); } + @Override + public boolean addTag(@NotNull String tag) { + return handle.addTag(tag); + } + + @Override + public boolean removeTag(@NotNull String tag) { + return handle.removeTag(tag); + } + + @Override + public boolean hasTag(@NotNull String tag) { + return handle.getTags().contains(tag); + } + + @Override + public @NotNull java.util.Set getTags() { + return handle.getTags(); + } + }