数据包同步
基本信息
| 属性 | 值 |
|---|---|
| 包类 | ca.wescook.nutrition.network.SPacketNutrients$Message |
| 通道名 | nutrition(NetworkRegistry.INSTANCE.newSimpleChannel("nutrition")) |
| 注册方向 | Side.CLIENT(S2C) |
| 消息 ID | MESSAGE_S2C_SYNC_NUTRIENTS = 0 |
| 触发点 | EventPlayerJoinWorld.entityJoinWorldEvent 主动 send(player) |
功能
服务端把玩家全部 Nutrient 值打包成 S2C 包发给客户端,客户端用按 name 反查 NutrientList.getByName(identifier) 重建 Map<Nutrient, Float>,保证客户端 GUI 显示与服务端一致。
发送(toBytes)
@Override
public void toBytes(ByteBuf buf) {
for (Map.Entry<Nutrient, Float> entry : this.values.entrySet()) {
ByteBufUtils.writeUTF8String(buf, entry.getKey().name);
buf.writeFloat(entry.getValue());
}
}
格式:循环写入 <utf8 nutrientName> <float value> 对,直到 Map 遍历完毕。
接收(fromBytes)
@Override
public void fromBytes(ByteBuf buf) {
this.values = new HashMap<>();
while (buf.isReadable()) {
String identifier = ByteBufUtils.readUTF8String(buf);
Float value = buf.readFloat();
this.values.put(NutrientList.getByName(identifier), value);
}
}
反查 Nutrient 对象;若客户端 NutrientList 中找不到该 name(mod 加载顺序或配置不一致),返回 null,最终被 NutritionManager.setAll 忽略。
客户端处理
@SideOnly(Side.CLIENT)
private void handle(final Message message) {
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
NutritionManager.instance().setAll(player, message.values);
// If Nutrition GUI is open, update GUI
GuiScreen currentScreen = Minecraft.getMinecraft().currentScreen;
if (currentScreen instanceof NutritionGui) {
((NutritionGui) currentScreen).redrawLabels();
}
}
若当前正打开 NutritionGui,强制 redrawLabels() 立即重绘,无需等下个 110 ticks 的 potionTicking 循环。
主动发送时机
| 时机 | 调用 |
|---|---|
| 玩家首次加入世界 | EventPlayerJoinWorld.entityJoinWorldEvent |
| 死亡后重生 | 同上(PlayerEvent.Clone 触发 wasDeath=true 后必然进入 EntityJoinWorldEvent) |
/nutrition reload 重载配置 |
DataImporter.updatePlayerCapabilitiesOnServer 重写 Map 后由下一次 EntityJoinWorldEvent 同步(注意 reload 不会主动 push,需玩家重连或触发 EntityJoin) |
WitcheryEventHandler 每 tick 修改吸血鬼玩家营养 |
通过 setAll → 内部会发包(NutritionManager.setAll 默认 sync=true) |
跳过同步的调用
PlayerDataHandler.initializeForPlayer 显式调用 setAll(player, values, false) —— 此时客户端尚未 ready,注释明确写:
“Do not sync here since the client is not yet ready to receive it. It will be synced later in EventPlayerJoinWorld.”
相关条目
- 玩家数据持久化 - 显式
sync=false的具体场景 - Witchery 吸血鬼兼容 - 每 tick 高频同步