From ccbf442413a371ca03c2de9352ecf94bfeba83ab Mon Sep 17 00:00:00 2001 From: Ap_Tx <3045929398@qq.com> Date: Mon, 5 Oct 2026 10:57:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E/botlist=E5=81=87?= =?UTF-8?q?=E4=BA=BA=E5=90=8D=E5=8D=95=E7=AE=A1=E7=90=86=EF=BC=8C/botall?= =?UTF-8?q?=E6=8C=89=E5=90=8D=E5=8D=95=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 名单持久化到config/slsa-bot-list.json。名单非空时/botall只操作名单内假人,为空时操作所有。支持add/remove/clear/show/addall。 --- .../zly2006/carpetslsaddition/ServerMain.java | 4 +- .../command/BotAllCommand.java | 7 +- .../command/BotListCommand.java | 100 +++++++++++++++++ .../util/BotListManager.java | 101 ++++++++++++++++++ 4 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/github/zly2006/carpetslsaddition/command/BotListCommand.java create mode 100644 src/main/java/com/github/zly2006/carpetslsaddition/util/BotListManager.java diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java b/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java index 8999949..f2a2c6a 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java @@ -4,6 +4,7 @@ import carpet.CarpetExtension; import carpet.CarpetServer; import com.github.zly2006.carpetslsaddition.command.BotAllCommand; import com.github.zly2006.carpetslsaddition.command.BotCommand; +import com.github.zly2006.carpetslsaddition.command.BotListCommand; import com.github.zly2006.carpetslsaddition.command.HatCommand; import com.github.zly2006.carpetslsaddition.command.SitCommand; import com.google.common.collect.Maps; @@ -83,9 +84,10 @@ public class ServerMain implements ModInitializer, CarpetExtension { SitCommand.register(dispatcher); BotCommand.register(dispatcher); BotAllCommand.register(dispatcher); + BotListCommand.register(dispatcher); LOGGER.info("[SLSA] commands registered: hat/sit/bot"); } catch (Throwable t) { LOGGER.error("[SLSA] failed to register commands", t); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/command/BotAllCommand.java b/src/main/java/com/github/zly2006/carpetslsaddition/command/BotAllCommand.java index 9b6d0a7..4a3e76b 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/command/BotAllCommand.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/command/BotAllCommand.java @@ -112,18 +112,21 @@ public class BotAllCommand { return c -> batchAp(c, action); } - /** 收集所有本模组生成的假人。 */ + /** 收集所有本模组生成的假人(受名单限制:名单非空时只取名单内的)。 */ private static List collectBots(CommandSourceStack source) { MinecraftServer server = source.getServer(); List bots = new ArrayList<>(); + boolean filterByList = !com.github.zly2006.carpetslsaddition.util.BotListManager.isEmpty(); for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player instanceof EntityPlayerMPFake && ((SLSBotAccessor) player).carpet_SLS_Addition$isBot()) { + if (filterByList && !com.github.zly2006.carpetslsaddition.util.BotListManager.contains(player.getScoreboardName())) { + continue; + } bots.add(player); } } return bots; } - private static int sitAll(CommandContext context) { if (!SLSCarpetSettings.canUseSitCommand) { context.getSource().sendSuccess(() -> net.minecraft.network.chat.Component.literal( diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/command/BotListCommand.java b/src/main/java/com/github/zly2006/carpetslsaddition/command/BotListCommand.java new file mode 100644 index 0000000..b62b554 --- /dev/null +++ b/src/main/java/com/github/zly2006/carpetslsaddition/command/BotListCommand.java @@ -0,0 +1,100 @@ +package com.github.zly2006.carpetslsaddition.command; + +import carpet.patches.EntityPlayerMPFake; +import com.github.zly2006.carpetslsaddition.util.BotListManager; +import com.github.zly2006.carpetslsaddition.util.access.SLSBotAccessor; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; + +import java.util.Set; + +import static net.minecraft.commands.Commands.argument; +import static net.minecraft.commands.Commands.literal; + +/** + * /botlist —— 维护"受控假人名单",供 /botall 限定操作范围。 + * + *

名单持久化在 config/slsa-bot-list.json,重启保留。 + */ +public class BotListCommand { + + public static void register(CommandDispatcher dispatcher) { + LiteralArgumentBuilder command = literal("botlist") + .requires(source -> Commands.LEVEL_OWNERS.check(source.permissions()) + || me.lucko.fabric.api.permissions.v0.Permissions.check(source, "slsaddition.command.bot")) + .then(literal("show").executes(BotListCommand::show)) + .then(literal("clear").executes(c -> { + BotListManager.clear(); + c.getSource().sendSuccess(() -> Component.literal("[SLSA] 已清空假人名单"), false); + return 1; + })) + .then(literal("add") + .then(argument("names", StringArgumentType.greedyString()) + .executes(c -> add(c.getSource(), StringArgumentType.getString(c, "names"))))) + .then(literal("remove") + .then(argument("names", StringArgumentType.greedyString()) + .executes(c -> remove(c.getSource(), StringArgumentType.getString(c, "names"))))) + .then(literal("addall").executes(BotListCommand::addAll)); + dispatcher.register(command); + } + + private static int show(com.mojang.brigadier.context.CommandContext c) { + Set names = BotListManager.getNames(); + if (names.isEmpty()) { + c.getSource().sendSuccess(() -> Component.literal("[SLSA] 假人名单为空(此时 /botall 操作所有假人)"), false); + } else { + c.getSource().sendSuccess(() -> Component.literal( + "[SLSA] 假人名单(" + names.size() + "):" + String.join(", ", names)), false); + } + return names.size(); + } + + private static int add(CommandSourceStack source, String raw) { + String[] parts = raw.trim().split("\\s+"); + int n = 0; + for (String p : parts) { + if (!p.isEmpty() && BotListManager.add(p)) { + n++; + } + } + final int added = n; + source.sendSuccess(() -> Component.literal( + "[SLSA] 已添加 " + added + " 个名字,名单共 " + BotListManager.getNames().size() + " 个"), false); + return n; + } + + private static int remove(CommandSourceStack source, String raw) { + String[] parts = raw.trim().split("\\s+"); + int n = 0; + for (String p : parts) { + if (!p.isEmpty() && BotListManager.remove(p)) { + n++; + } + } + final int removed = n; + source.sendSuccess(() -> Component.literal( + "[SLSA] 已移除 " + removed + " 个名字,名单共 " + BotListManager.getNames().size() + " 个"), false); + return n; + } + + /** 把当前所有在线 SLS 假人加入名单。 */ + private static int addAll(com.mojang.brigadier.context.CommandContext c) { + int n = 0; + for (ServerPlayer player : c.getSource().getServer().getPlayerList().getPlayers()) { + if (player instanceof EntityPlayerMPFake && ((SLSBotAccessor) player).carpet_SLS_Addition$isBot()) { + if (BotListManager.add(player.getScoreboardName())) { + n++; + } + } + } + final int added = n; + c.getSource().sendSuccess(() -> Component.literal( + "[SLSA] 已把 " + added + " 个在线假人加入名单,名单共 " + BotListManager.getNames().size() + " 个"), false); + return n; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/util/BotListManager.java b/src/main/java/com/github/zly2006/carpetslsaddition/util/BotListManager.java new file mode 100644 index 0000000..40c10c2 --- /dev/null +++ b/src/main/java/com/github/zly2006/carpetslsaddition/util/BotListManager.java @@ -0,0 +1,101 @@ +package com.github.zly2006.carpetslsaddition.util; + +import com.github.zly2006.carpetslsaddition.ServerMain; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import net.fabricmc.loader.api.FabricLoader; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * 假人名单管理器:维护一份"受控假人名字"列表,持久化到 config/slsa-bot-list.json。 + * + *

用途:{@code /botlist add cute wazi} 把名字加入名单后,{@code /botall} 的操作范围 + * 就限定为名单内的假人(名单为空时操作所有 SLS 假人)。 + */ +public final class BotListManager { + + private BotListManager() {} + + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + /** 名字列表(保序、去重)。 */ + private static final Set NAMES = new LinkedHashSet<>(); + + private static Path configPath; + + private static Path path() { + if (configPath == null) { + configPath = FabricLoader.getInstance().getConfigDir().resolve("slsa-bot-list.json"); + } + return configPath; + } + + /** 加载名单(服务器启动时调用)。 */ + public static void load() { + NAMES.clear(); + Path p = path(); + if (!Files.exists(p)) { + return; + } + try (Reader r = Files.newBufferedReader(p)) { + Set loaded = GSON.fromJson(r, new TypeToken>() {}.getType()); + if (loaded != null) { + NAMES.addAll(loaded); + } + ServerMain.LOGGER.info("[SLSA] loaded bot list: {} entries", NAMES.size()); + } catch (Exception e) { + ServerMain.LOGGER.error("[SLSA] failed to load bot list", e); + } + } + + /** 保存名单。 */ + public static void save() { + Path p = path(); + try { + Files.createDirectories(p.getParent()); + try (Writer w = Files.newBufferedWriter(p)) { + GSON.toJson(NAMES, w); + } + } catch (IOException e) { + ServerMain.LOGGER.error("[SLSA] failed to save bot list", e); + } + } + + public static boolean add(String name) { + boolean added = NAMES.add(name); + if (added) save(); + return added; + } + + public static boolean remove(String name) { + boolean removed = NAMES.remove(name); + if (removed) save(); + return removed; + } + + public static void clear() { + NAMES.clear(); + save(); + } + + /** 返回名单快照。 */ + public static Set getNames() { + return new LinkedHashSet<>(NAMES); + } + + public static boolean contains(String name) { + return NAMES.contains(name); + } + + public static boolean isEmpty() { + return NAMES.isEmpty(); + } +} \ No newline at end of file