玩家数据持久化
基本信息
| 属性 | 值 |
|---|---|
| NBT 标签名 | Nutrients |
| 数据格式 | NBTTagCompound 内嵌一个 NBTTagCompound,key 是 Nutrient name,value 是 float |
| 触发点 | Forge 默认的 Player persistent NBT 序列化(PlayerEvent.SaveToFile / PlayerEvent.LoadFromFile 等的 entityData) |
功能
通过 Forge 默认的玩家持久化机制(Entity.playerData)保存与恢复每个 Nutrient 的值。
写入
public static void saveForPlayer(EntityPlayer player, NBTTagCompound tagCompound) {
NBTTagCompound playerData = new NBTTagCompound();
for (Nutrient nutrient : NutrientList.get()) {
float value = NutritionManager.instance().get(player, nutrient);
playerData.setFloat(nutrient.name, value);
}
tagCompound.setTag(NBT_NUTRIENT_DATA, playerData);
}
只序列化 NutrientList.get() 中存在的 Nutrient。删除 Nutrient 配置后,旧玩家 NBT 中的遗留字段会被忽略。
读取
public static void initializeForPlayer(EntityPlayer player, NBTTagCompound tagCompound) {
if (tagCompound.hasKey(NBT_NUTRIENT_DATA)) {
NBTTagCompound nutrientTag = tagCompound.getCompoundTag(NBT_NUTRIENT_DATA);
Map<Nutrient, Float> values = new HashMap<>();
for (Nutrient nutrient : NutrientList.get()) {
float value;
if (nutrientTag.hasKey(nutrient.name)) {
value = nutrientTag.getFloat(nutrient.name);
} else {
value = (float) NutritionConfig.nutrition.startingNutrition;
}
values.put(nutrient, value);
}
// Do not sync here since the client is not yet ready to receive it.
// It will be synced later in EventPlayerJoinWorld.
NutritionManager.instance().setAll(player, values, false);
}
}
行为
- 玩家 NBT 中没有
Nutrients字段 → 跳过(玩家首次进服) - 某个 Nutrient 在 NBT 里没有记录(mod 更新后新增 Nutrient) → 用
startingNutrition(默认 50)初始化 setAll(player, values, false):第三个参数sync=false显式禁止此刻发包,因为"客户端尚未准备好接收";后续EventPlayerJoinWorld会触发SPacketNutrients.send(player)
相关条目
- 数据包同步 - 真正把数据送到客户端的时机
- /nutrition 命令 -
reset命令 = 把 Nutrient 重置到startingNutrition - 死亡惩罚 - 死亡时数据被 evict 重新写入(不依赖 NBT)