feat: 加slsBoardEnabled规则作榜单总开关(服务端规则控制客户端命令)
BoardTogglePayload同步开关状态;客户端/slsboard检查enabled,未开启则拒绝。ServerMain加轮询线程检测规则变化。
This commit is contained in:
1 parent
7366a8b244
commit
3fde7e2c1b
8 files changed
+99
-10
No files matched your search
@@ -80,4 +80,7 @@ public class SLSCarpetSettings {
|
|||||||
|
|
||||||
@Rule(categories = {SLSA, RuleCategory.FEATURE})
|
@Rule(categories = {SLSA, RuleCategory.FEATURE})
|
||||||
public static boolean stackableVehicles = false;
|
public static boolean stackableVehicles = false;
|
||||||
|
|
||||||
|
@Rule(categories = {SLSA, RuleCategory.FEATURE})
|
||||||
|
public static boolean slsBoardEnabled = false;
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,7 @@ public class ServerMain implements ModInitializer, CarpetExtension {
|
|||||||
INSTANCE = this;
|
INSTANCE = this;
|
||||||
CarpetServer.manageExtension(this);
|
CarpetServer.manageExtension(this);
|
||||||
com.github.zly2006.carpetslsaddition.net.BoardSyncPayload.register();
|
com.github.zly2006.carpetslsaddition.net.BoardSyncPayload.register();
|
||||||
|
com.github.zly2006.carpetslsaddition.net.BoardTogglePayload.register();
|
||||||
// 玩家加入时同步榜单
|
// 玩家加入时同步榜单
|
||||||
net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents.JOIN.register(
|
net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents.JOIN.register(
|
||||||
(handler, sender, srv) ->
|
(handler, sender, srv) ->
|
||||||
@@ -60,6 +61,25 @@ public class ServerMain implements ModInitializer, CarpetExtension {
|
|||||||
ServerMain.server = server;
|
ServerMain.server = server;
|
||||||
com.github.zly2006.carpetslsaddition.util.BotListManager.load();
|
com.github.zly2006.carpetslsaddition.util.BotListManager.load();
|
||||||
com.github.zly2006.carpetslsaddition.util.BoardSyncManager.syncToAll(server);
|
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
|
@Override
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.github.zly2006.carpetslsaddition.client;
|
package com.github.zly2006.carpetslsaddition.client;
|
||||||
|
|
||||||
import com.github.zly2006.carpetslsaddition.net.BoardSyncPayload;
|
import com.github.zly2006.carpetslsaddition.net.BoardSyncPayload;
|
||||||
|
import com.github.zly2006.carpetslsaddition.net.BoardTogglePayload;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
@@ -38,24 +39,27 @@ public class BoardClient implements ClientModInitializer {
|
|||||||
context.client().execute(() -> BoardClientState.setBoard(payload.board(), entries));
|
context.client().execute(() -> BoardClientState.setBoard(payload.board(), entries));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 接收开关状态
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(BoardTogglePayload.TYPE, (payload, context) -> {
|
||||||
|
context.client().execute(() -> BoardClientState.enabled = payload.enabled());
|
||||||
|
});
|
||||||
|
|
||||||
// 2) /slsboard 命令(纯客户端,非 OP 也能用)
|
// 2) /slsboard 命令(纯客户端,非 OP 也能用)
|
||||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
||||||
dispatcher.register(
|
dispatcher.register(
|
||||||
ClientCommands.literal("slsboard")
|
ClientCommands.literal("slsboard")
|
||||||
.then(ClientCommands.literal("deaths")
|
.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")
|
.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")
|
.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())
|
.then(ClientCommands.argument("board", StringArgumentType.word())
|
||||||
.suggests((c, b) -> SharedSuggestionProvider.suggest(
|
.suggests((c, b) -> SharedSuggestionProvider.suggest(
|
||||||
new String[]{"deaths", "mined", "off"}, b))
|
new String[]{"deaths", "mined", "off"}, b))
|
||||||
.executes(c -> {
|
.executes(c -> {
|
||||||
String v = StringArgumentType.getString(c, "board");
|
String v = StringArgumentType.getString(c, "board");
|
||||||
BoardClientState.set("off".equals(v) ? "" : v);
|
return run(c.getSource(), () -> BoardClientState.set("off".equals(v) ? "" : v));
|
||||||
feedback(c.getSource());
|
|
||||||
return 1;
|
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -64,8 +68,15 @@ public class BoardClient implements ClientModInitializer {
|
|||||||
HudElementRegistry.addLast(HUD_ID, new BoardHudElement());
|
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;
|
String d = BoardClientState.displaying;
|
||||||
source.sendFeedback(Component.literal("[SLSA] 榜单显示:" + (d.isEmpty() ? "关闭" : d)));
|
source.sendFeedback(Component.literal("[SLSA] 榜单显示:" + (d.isEmpty() ? "关闭" : d)));
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,9 @@ public final class BoardClientState {
|
|||||||
/** 当前显示的榜:"" / "deaths" / "mined"。 */
|
/** 当前显示的榜:"" / "deaths" / "mined"。 */
|
||||||
public static volatile String displaying = "";
|
public static volatile String displaying = "";
|
||||||
|
|
||||||
|
/** 服务端 Carpet 规则 slsBoardEnabled 的状态(未开启则禁止使用)。 */
|
||||||
|
public static volatile boolean enabled = false;
|
||||||
|
|
||||||
private static volatile List<Entry> deaths = Collections.emptyList();
|
private static volatile List<Entry> deaths = Collections.emptyList();
|
||||||
private static volatile List<Entry> mined = Collections.emptyList();
|
private static volatile List<Entry> mined = Collections.emptyList();
|
||||||
|
|
||||||
|
|||||||
@@ -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})。
|
||||||
|
*
|
||||||
|
* <p>规则变化时下发;客户端收到后决定 {@code /slsboard} 是否可用。
|
||||||
|
*/
|
||||||
|
public record BoardTogglePayload(boolean enabled) implements CustomPacketPayload {
|
||||||
|
|
||||||
|
public static final CustomPacketPayload.Type<BoardTogglePayload> TYPE =
|
||||||
|
CustomPacketPayload.createType("slsa:board_toggle");
|
||||||
|
|
||||||
|
public static final StreamCodec<RegistryFriendlyByteBuf, BoardTogglePayload> CODEC = StreamCodec.composite(
|
||||||
|
ByteBufCodecs.BOOL, BoardTogglePayload::enabled,
|
||||||
|
BoardTogglePayload::new
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CustomPacketPayload.Type<? extends CustomPacketPayload> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry.clientboundPlay().register(TYPE, CODEC);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,12 +61,18 @@ public final class BoardSyncManager {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 把两个榜单都同步给某玩家。 */
|
/** 把两个榜单 + 开关状态同步给某玩家。 */
|
||||||
public static void syncTo(ServerPlayer player) {
|
public static void syncTo(ServerPlayer player) {
|
||||||
MinecraftServer server = ServerMain.server;
|
MinecraftServer server = ServerMain.server;
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
return;
|
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_DEATHS, buildBoard(server, BOARD_DEATHS)));
|
||||||
ServerPlayNetworking.send(player, new BoardSyncPayload(BOARD_MINED, buildBoard(server, BOARD_MINED)));
|
ServerPlayNetworking.send(player, new BoardSyncPayload(BOARD_MINED, buildBoard(server, BOARD_MINED)));
|
||||||
}
|
}
|
||||||
@@ -77,4 +83,15 @@ public final class BoardSyncManager {
|
|||||||
syncTo(player);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -74,5 +74,7 @@
|
|||||||
|
|
||||||
"carpet.slsa.block.deep_slate_core": "Deepslate Core",
|
"carpet.slsa.block.deep_slate_core": "Deepslate Core",
|
||||||
"carpet.rule.stackableVehicles.name": "Stackable vehicles",
|
"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"
|
||||||
}
|
}
|
||||||
@@ -74,5 +74,7 @@
|
|||||||
|
|
||||||
"carpet.slsa.block.deep_slate_core": "深板岩核心",
|
"carpet.slsa.block.deep_slate_core": "深板岩核心",
|
||||||
"carpet.rule.stackableVehicles.name": "载具可堆叠",
|
"carpet.rule.stackableVehicles.name": "载具可堆叠",
|
||||||
"carpet.rule.stackableVehicles.desc": "矿车和船的物品可以堆叠到64,拾取时自动合并"
|
"carpet.rule.stackableVehicles.desc": "矿车和船的物品可以堆叠到64,拾取时自动合并",
|
||||||
|
"carpet.rule.slsBoardEnabled.name": "启用榜单",
|
||||||
|
"carpet.rule.slsBoardEnabled.desc": "允许玩家用 /slsboard 显示死亡榜/挖掘榜"
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user