feat: /slsboard改发请求包,服务端给该玩家单独发display包(per-player显示)

客户端本地setDisplayObjective会被服务端覆盖,改用C2S请求包,服务端单独发ClientboundSetDisplayObjectivePacket给请求者。
This commit is contained in:
AxTps committed 2026-10-06 21:22:42 +08:00
1 parent d3bd73f7c5
commit 5001b2f5a2
4 files changed
+69 -31

No files matched your search

@@ -1,5 +1,6 @@
package com.github.zly2006.carpetslsaddition.client;
import com.github.zly2006.carpetslsaddition.net.BoardRequestPayload;
import com.mojang.brigadier.arguments.StringArgumentType;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType;
@@ -7,15 +8,14 @@ import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.command.v2.ClientCommands;
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.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.network.chat.Component;
import net.minecraft.world.scores.DisplaySlot;
import net.minecraft.world.scores.Objective;
/**
* 客户端入口:/slsboard 命令,控制本地计分板侧边栏显示哪个榜。
* 客户端入口:/slsboard 命令,请求服务端给自己显示某个榜单。
*
* <p>利用原版计分板侧边栏渲染(可靠),各玩家本地切换、互不影响。
* <p>服务端收到请求后,给该玩家单独发 display 包,实现各玩家各自显示、互不影响。
* 数据由服务端从 stats 同步到 scoreboard objective(见 BoardManager)。
*/
@Environment(EnvType.CLIENT)
@@ -26,42 +26,24 @@ public class BoardClient implements ClientModInitializer {
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
dispatcher.register(
ClientCommands.literal("slsboard")
.then(ClientCommands.literal("deaths").executes(c -> show(c.getSource(), "sls_deaths")))
.then(ClientCommands.literal("mined").executes(c -> show(c.getSource(), "sls_mined")))
.then(ClientCommands.literal("off").executes(c -> { clear(c.getSource()); return 1; }))
.then(ClientCommands.literal("deaths").executes(c -> request(c.getSource(), "sls_deaths")))
.then(ClientCommands.literal("mined").executes(c -> request(c.getSource(), "sls_mined")))
.then(ClientCommands.literal("off").executes(c -> request(c.getSource(), "")))
.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");
if ("off".equals(v)) { clear(c.getSource()); return 1; }
return show(c.getSource(), "sls_" + v);
return request(c.getSource(), "off".equals(v) ? "" : "sls_" + v);
}))
);
});
}
private static int show(FabricClientCommandSource source, String objectiveName) {
var mc = source.getClient();
var level = mc.level;
if (level == null) {
return 0;
}
Objective obj = level.getScoreboard().getObjective(objectiveName);
if (obj == null) {
source.sendError(Component.literal("[SLSA] 找不到计分板 " + objectiveName + "(服务端规则未开启?)"));
return 0;
}
level.getScoreboard().setDisplayObjective(DisplaySlot.SIDEBAR, obj);
source.sendFeedback(Component.literal("[SLSA] 榜单显示:" + objectiveName));
private static int request(FabricClientCommandSource source, String objectiveName) {
ClientPlayNetworking.send(new BoardRequestPayload(objectiveName));
source.sendFeedback(Component.literal(
objectiveName.isEmpty() ? "[SLSA] 榜单已关闭" : "[SLSA] 请求显示:" + objectiveName));
return 1;
}
private static void clear(FabricClientCommandSource source) {
var level = source.getClient().level;
if (level != null) {
level.getScoreboard().setDisplayObjective(DisplaySlot.SIDEBAR, null);
}
source.sendFeedback(Component.literal("[SLSA] 榜单已关闭"));
}
}