diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/SLSCarpetSettings.java b/src/main/java/com/github/zly2006/carpetslsaddition/SLSCarpetSettings.java index b530ef9..1216023 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/SLSCarpetSettings.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/SLSCarpetSettings.java @@ -80,4 +80,7 @@ public class SLSCarpetSettings { @Rule(categories = {SLSA, RuleCategory.FEATURE}) public static boolean stackableVehicles = false; + + @Rule(categories = {SLSA, RuleCategory.FEATURE}) + public static boolean slsBoardEnabled = false; } diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java b/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java index 1d6ddf7..a92c863 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/ServerMain.java @@ -44,6 +44,7 @@ public class ServerMain implements ModInitializer, CarpetExtension { INSTANCE = this; CarpetServer.manageExtension(this); com.github.zly2006.carpetslsaddition.net.BoardSyncPayload.register(); + com.github.zly2006.carpetslsaddition.net.BoardTogglePayload.register(); // 玩家加入时同步榜单 net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents.JOIN.register( (handler, sender, srv) -> @@ -60,6 +61,25 @@ public class ServerMain implements ModInitializer, CarpetExtension { ServerMain.server = server; com.github.zly2006.carpetslsaddition.util.BotListManager.load(); com.github.zly2006.carpetslsaddition.util.BoardSyncManager.syncToAll(server); + startBoardWatcher(server); + } + + /** 每秒检测 slsBoardEnabled 规则变化并同步给客户端。 */ + private void startBoardWatcher(MinecraftServer server) { + Thread t = new Thread(() -> { + while (!Thread.currentThread().isInterrupted()) { + try { + com.github.zly2006.carpetslsaddition.util.BoardSyncManager.tick(server); + Thread.sleep(1000L); + } catch (InterruptedException e) { + return; + } catch (Throwable ex) { + LOGGER.debug("[SLSA] board watcher error: {}", ex.toString()); + } + } + }, "SLSA-BoardWatcher"); + t.setDaemon(true); + t.start(); } @Override diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClient.java b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClient.java index 4e76793..bf9d553 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClient.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClient.java @@ -1,6 +1,7 @@ package com.github.zly2006.carpetslsaddition.client; import com.github.zly2006.carpetslsaddition.net.BoardSyncPayload; +import com.github.zly2006.carpetslsaddition.net.BoardTogglePayload; import com.mojang.brigadier.arguments.StringArgumentType; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; @@ -38,24 +39,27 @@ public class BoardClient implements ClientModInitializer { context.client().execute(() -> BoardClientState.setBoard(payload.board(), entries)); }); + // 接收开关状态 + ClientPlayNetworking.registerGlobalReceiver(BoardTogglePayload.TYPE, (payload, context) -> { + context.client().execute(() -> BoardClientState.enabled = payload.enabled()); + }); + // 2) /slsboard 命令(纯客户端,非 OP 也能用) ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { dispatcher.register( ClientCommands.literal("slsboard") .then(ClientCommands.literal("deaths") - .executes(c -> { BoardClientState.toggle("deaths"); feedback(c.getSource()); return 1; })) + .executes(c -> run(c.getSource(), () -> BoardClientState.toggle("deaths")))) .then(ClientCommands.literal("mined") - .executes(c -> { BoardClientState.toggle("mined"); feedback(c.getSource()); return 1; })) + .executes(c -> run(c.getSource(), () -> BoardClientState.toggle("mined")))) .then(ClientCommands.literal("off") - .executes(c -> { BoardClientState.set(""); feedback(c.getSource()); return 1; })) + .executes(c -> run(c.getSource(), () -> BoardClientState.set("")))) .then(ClientCommands.argument("board", StringArgumentType.word()) .suggests((c, b) -> SharedSuggestionProvider.suggest( new String[]{"deaths", "mined", "off"}, b)) .executes(c -> { String v = StringArgumentType.getString(c, "board"); - BoardClientState.set("off".equals(v) ? "" : v); - feedback(c.getSource()); - return 1; + return run(c.getSource(), () -> BoardClientState.set("off".equals(v) ? "" : v)); })) ); }); @@ -64,8 +68,15 @@ public class BoardClient implements ClientModInitializer { HudElementRegistry.addLast(HUD_ID, new BoardHudElement()); } - private static void feedback(FabricClientCommandSource source) { + /** 统一的命令入口:先检查服务端开关,再执行动作。 */ + private static int run(FabricClientCommandSource source, Runnable action) { + if (!BoardClientState.enabled) { + source.sendError(Component.literal("[SLSA] 榜单功能未开启(服务端 /carpet slsBoardEnabled true)")); + return 0; + } + action.run(); String d = BoardClientState.displaying; source.sendFeedback(Component.literal("[SLSA] 榜单显示:" + (d.isEmpty() ? "关闭" : d))); + return 1; } } \ No newline at end of file diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClientState.java b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClientState.java index 9c11532..30b6610 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClientState.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClientState.java @@ -19,6 +19,9 @@ public final class BoardClientState { /** 当前显示的榜:"" / "deaths" / "mined"。 */ public static volatile String displaying = ""; + /** 服务端 Carpet 规则 slsBoardEnabled 的状态(未开启则禁止使用)。 */ + public static volatile boolean enabled = false; + private static volatile List deaths = Collections.emptyList(); private static volatile List mined = Collections.emptyList(); diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/net/BoardTogglePayload.java b/src/main/java/com/github/zly2006/carpetslsaddition/net/BoardTogglePayload.java new file mode 100644 index 0000000..a3a1dab --- /dev/null +++ b/src/main/java/com/github/zly2006/carpetslsaddition/net/BoardTogglePayload.java @@ -0,0 +1,31 @@ +package com.github.zly2006.carpetslsaddition.net; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; + +/** + * 服务端 → 客户端:榜单功能总开关状态(对应 Carpet 规则 {@code slsBoardEnabled})。 + * + *

规则变化时下发;客户端收到后决定 {@code /slsboard} 是否可用。 + */ +public record BoardTogglePayload(boolean enabled) implements CustomPacketPayload { + + public static final CustomPacketPayload.Type TYPE = + CustomPacketPayload.createType("slsa:board_toggle"); + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.BOOL, BoardTogglePayload::enabled, + BoardTogglePayload::new + ); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } + + public static void register() { + net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry.clientboundPlay().register(TYPE, CODEC); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/util/BoardSyncManager.java b/src/main/java/com/github/zly2006/carpetslsaddition/util/BoardSyncManager.java index 1c09faa..58277d5 100644 --- a/src/main/java/com/github/zly2006/carpetslsaddition/util/BoardSyncManager.java +++ b/src/main/java/com/github/zly2006/carpetslsaddition/util/BoardSyncManager.java @@ -61,12 +61,18 @@ public final class BoardSyncManager { return list; } - /** 把两个榜单都同步给某玩家。 */ + /** 把两个榜单 + 开关状态同步给某玩家。 */ public static void syncTo(ServerPlayer player) { MinecraftServer server = ServerMain.server; if (server == null) { return; } + boolean enabled = com.github.zly2006.carpetslsaddition.SLSCarpetSettings.slsBoardEnabled; + // 先发开关状态 + ServerPlayNetworking.send(player, new com.github.zly2006.carpetslsaddition.net.BoardTogglePayload(enabled)); + if (!enabled) { + return; + } ServerPlayNetworking.send(player, new BoardSyncPayload(BOARD_DEATHS, buildBoard(server, BOARD_DEATHS))); ServerPlayNetworking.send(player, new BoardSyncPayload(BOARD_MINED, buildBoard(server, BOARD_MINED))); } @@ -77,4 +83,15 @@ public final class BoardSyncManager { syncTo(player); } } + + private static volatile Boolean lastEnabled = null; + + /** 由轮询线程每秒调用:规则值变化时同步给所有玩家。 */ + public static void tick(MinecraftServer server) { + boolean now = com.github.zly2006.carpetslsaddition.SLSCarpetSettings.slsBoardEnabled; + if (lastEnabled == null || lastEnabled != now) { + lastEnabled = now; + syncToAll(server); + } + } } diff --git a/src/main/resources/assets/slsaddition/lang/en_us.json b/src/main/resources/assets/slsaddition/lang/en_us.json index 478dd5b..d31ac8c 100644 --- a/src/main/resources/assets/slsaddition/lang/en_us.json +++ b/src/main/resources/assets/slsaddition/lang/en_us.json @@ -74,5 +74,7 @@ "carpet.slsa.block.deep_slate_core": "Deepslate Core", "carpet.rule.stackableVehicles.name": "Stackable vehicles", - "carpet.rule.stackableVehicles.desc": "Minecarts and boats can stack up to 64, auto-merging on pickup" + "carpet.rule.stackableVehicles.desc": "Minecarts and boats can stack up to 64, auto-merging on pickup", + "carpet.rule.slsBoardEnabled.name": "Enable boards", + "carpet.rule.slsBoardEnabled.desc": "Allow players to use /slsboard to show death/mining leaderboards" } diff --git a/src/main/resources/assets/slsaddition/lang/zh_cn.json b/src/main/resources/assets/slsaddition/lang/zh_cn.json index 2c33784..d1c1e56 100644 --- a/src/main/resources/assets/slsaddition/lang/zh_cn.json +++ b/src/main/resources/assets/slsaddition/lang/zh_cn.json @@ -74,5 +74,7 @@ "carpet.slsa.block.deep_slate_core": "深板岩核心", "carpet.rule.stackableVehicles.name": "载具可堆叠", - "carpet.rule.stackableVehicles.desc": "矿车和船的物品可以堆叠到64,拾取时自动合并" + "carpet.rule.stackableVehicles.desc": "矿车和船的物品可以堆叠到64,拾取时自动合并", + "carpet.rule.slsBoardEnabled.name": "启用榜单", + "carpet.rule.slsBoardEnabled.desc": "允许玩家用 /slsboard 显示死亡榜/挖掘榜" }