From ac6cd5c1b55c95b39ef7e53fa241db4f9e19598f Mon Sep 17 00:00:00 2001 From: Ap_Tx <3045929398@qq.com> Date: Tue, 6 Oct 2026 19:34:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=A6=9C=E5=8D=95=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=EF=BC=88=E6=8E=A5=E6=94=B6=E5=8C=85+/slsboard?= =?UTF-8?q?=E5=91=BD=E4=BB=A4+=E5=8F=B3=E4=BE=A7HUD=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BoardClient注册客户端入口:接收BoardSyncPayload、/slsboard deaths/mined/off切换显示、HudElementRegistry注册右侧HUD。各玩家本地状态独立,不同步。 --- .../carpetslsaddition/client/BoardClient.java | 69 ++++++++++++++++++ .../client/BoardClientState.java | 58 +++++++++++++++ .../client/BoardHudElement.java | 70 +++++++++++++++++++ src/main/resources/fabric.mod.json | 3 + 4 files changed, 200 insertions(+) create mode 100644 src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClient.java create mode 100644 src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClientState.java create mode 100644 src/main/java/com/github/zly2006/carpetslsaddition/client/BoardHudElement.java diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClient.java b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClient.java new file mode 100644 index 0000000..12a70bb --- /dev/null +++ b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClient.java @@ -0,0 +1,69 @@ +package com.github.zly2006.carpetslsaddition.client; + +import com.github.zly2006.carpetslsaddition.net.BoardSyncPayload; +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; + +import java.util.ArrayList; +import java.util.List; + +/** + * 客户端入口:接收榜单数据、注册 /slsboard 命令、注册 HUD 渲染。 + * + *

纯客户端功能:显示哪个榜由本地状态决定,各玩家可不同步。 + */ +@Environment(EnvType.CLIENT) +public class BoardClient implements ClientModInitializer { + + public static final Identifier HUD_ID = Identifier.fromNamespaceAndPath("slsa", "board_hud"); + + @Override + public void onInitializeClient() { + // 1) 接收服务端下发的榜单数据 + ClientPlayNetworking.registerGlobalReceiver(BoardSyncPayload.TYPE, (payload, context) -> { + List entries = new ArrayList<>(); + for (BoardSyncPayload.Entry e : payload.entries()) { + entries.add(new BoardClientState.Entry(e.name(), e.score())); + } + context.client().execute(() -> BoardClientState.setBoard(payload.board(), entries)); + }); + + // 2) /slsboard 命令(纯客户端,非 OP 也能用) + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { + dispatcher.register( + net.minecraft.commands.Commands.literal("slsboard") + .then(net.minecraft.commands.Commands.literal("deaths") + .executes(c -> { BoardClientState.toggle("deaths"); feedback(c.getSource()); return 1; })) + .then(net.minecraft.commands.Commands.literal("mined") + .executes(c -> { BoardClientState.toggle("mined"); feedback(c.getSource()); return 1; })) + .then(net.minecraft.commands.Commands.literal("off") + .executes(c -> { BoardClientState.set(""); feedback(c.getSource()); return 1; })) + .then(net.minecraft.commands.Commands.argument("board", StringArgumentType.word()) + .suggests((c, b) -> net.minecraft.commands.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; + })) + ); + }); + + // 3) HUD 渲染 + HudElementRegistry.addLast(HUD_ID, new BoardHudElement()); + } + + private static void feedback(FabricClientCommandSource source) { + String d = BoardClientState.displaying; + source.sendFeedback(Component.literal("[SLSA] 榜单显示:" + (d.isEmpty() ? "关闭" : d))); + } +} \ 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 new file mode 100644 index 0000000..9c11532 --- /dev/null +++ b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardClientState.java @@ -0,0 +1,58 @@ +package com.github.zly2006.carpetslsaddition.client; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 客户端榜单状态(纯客户端,各玩家独立,不同步)。 + * + *

+ */ +public final class BoardClientState { + + private BoardClientState() {} + + /** 当前显示的榜:"" / "deaths" / "mined"。 */ + public static volatile String displaying = ""; + + private static volatile List deaths = Collections.emptyList(); + private static volatile List mined = Collections.emptyList(); + + public record Entry(String name, int score) {} + + public static void setBoard(String board, List entries) { + if ("deaths".equals(board)) { + deaths = entries; + } else if ("mined".equals(board)) { + mined = entries; + } + } + + public static List current() { + return switch (displaying) { + case "deaths" -> deaths; + case "mined" -> mined; + default -> Collections.emptyList(); + }; + } + + public static void toggle(String board) { + displaying = displaying.equals(board) ? "" : board; + } + + public static void set(String board) { + displaying = board; + } + + public static String currentTitle() { + return switch (displaying) { + case "deaths" -> "死亡榜"; + case "mined" -> "挖掘榜"; + default -> ""; + }; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardHudElement.java b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardHudElement.java new file mode 100644 index 0000000..eb586c4 --- /dev/null +++ b/src/main/java/com/github/zly2006/carpetslsaddition/client/BoardHudElement.java @@ -0,0 +1,70 @@ +package com.github.zly2006.carpetslsaddition.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElement; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.network.chat.Component; + +import java.util.List; + +/** + * 右侧排行榜 HUD:显示死亡榜/挖掘榜的 Top N。 + * + *

纯客户端渲染,内容来自 {@link BoardClientState}(服务端同步而来)。 + */ +@Environment(EnvType.CLIENT) +public class BoardHudElement implements HudElement { + + private static final int LINE_H = 10; + private static final int PAD = 4; + private static final int BG = 0x80000000; // 半透明黑 + private static final int TITLE_COLOR = 0xFFFF55; // 黄 + private static final int TEXT_COLOR = 0xFFFFFF; // 白 + + @Override + public void extractRenderState(GuiGraphicsExtractor g, DeltaTracker delta) { + String board = BoardClientState.displaying; + if (board == null || board.isEmpty()) { + return; + } + Minecraft mc = Minecraft.getInstance(); + if (mc.player == null || mc.options.hideGui) { + return; + } + List list = BoardClientState.current(); + Font font = mc.font; + + String title = BoardClientState.currentTitle(); + int maxW = font.width(title); + for (BoardClientState.Entry e : list) { + maxW = Math.max(maxW, font.width(line(e))); + } + + int screenW = g.guiWidth(); + int x = screenW - maxW - PAD * 2 - 2; + int y = 4; + + // 背景 + int h = PAD * 2 + LINE_H * (list.size() + 1); + g.fill(x, y, x + maxW + PAD * 2, y + h, BG); + + int ty = y + PAD; + g.text(font, Component.literal(title), x + PAD, ty, TITLE_COLOR); + ty += LINE_H; + for (int i = 0; i < list.size(); i++) { + BoardClientState.Entry e = list.get(i); + g.text(font, Component.literal(line(e)), x + PAD, ty, TEXT_COLOR); + ty += LINE_H; + } + } + + private static String line(BoardClientState.Entry e) { + String name = e.name(); + if (name.length() > 12) name = name.substring(0, 12); + return name + " " + e.score(); + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 4101bd8..f23a221 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -19,6 +19,9 @@ "entrypoints": { "main": [ "com.github.zly2006.carpetslsaddition.ServerMain" + ], + "client": [ + "com.github.zly2006.carpetslsaddition.client.BoardClient" ] }, "accessWidener": "slsa.accesswidener",