Skip to content

PDC

PDC 是 Bukkit PersistentDataContainer 的简称,用于把自定义数据保存到物品、实体、方块状态或玩家等对象上。CoreLib 使用 PDC 保存模块状态,业务模块通过自己的 namespace 写入数据,避免互相覆盖。

PDC 解决什么问题

如果只把状态写进 Lore,会出现很多问题:

  • 玩家或其他插件可能修改 Lore。
  • 多模块同时修改 Lore 时容易互相覆盖。
  • 解析文本很慢,而且容易受颜色和语言影响。
  • 无法可靠区分"展示文本"和"真实数据"。
  • 物品更新或刷新时,文本可能丢失或格式变化。

PDC 则适合保存真实状态,数据以二进制或结构化形式存储在物品的 NBT 中,不受显示层影响。

各模块写入的数据

模块写入内容说明
EmakiItem物品 ID、套装 ID、基础属性、技能绑定、版本号物品的身份标识和基础配置数据。
EmakiForge锻造层、品质、材料贡献、配方 ID锻造结果的结构化记录。
EmakiStrengthen强化星级、锻印状态、保护状态、强化属性、里程碑强化进度和惩罚状态。
EmakiGem插槽列表、宝石 ID、宝石等级、升级状态宝石系统的完整状态。
EmakiAttribute属性 payload、属性来源标记装备提供的属性数值。
EmakiSkills玩家技能槽、技能等级、触发器绑定通常保存在玩家数据文件而非物品 PDC。
EmakiCooking世界工位状态通常落盘到 data/stations/ 文件,而不是物品 PDC。

namespace 原则

每个模块都应该写入自己的命名空间,不要直接覆盖其他模块数据。CoreLib 使用 NamespacedKey 区分不同模块的数据:

text
emakiitem:item_id
emakiforge:forge_layer
emakistrengthen:star_level
emakigem:gem_slots
emakiattribute:attribute_payload

这种设计确保:

  • 强化模块不会意外覆盖宝石数据。
  • 锻造模块不会破坏物品基础 ID。
  • 各模块可以独立读写自己的数据。
  • 清理某个模块状态时不影响其他模块。

PDC 与 Assembly 的关系

PDC 保存真实数据,Assembly 负责把这些数据渲染成最终展示。流程:

text
模块写入 PDC → CoreLib 读取所有 layer → Assembly 渲染 → 最终 Lore/名称/属性

这意味着:

  • Lore 是"输出",不是"输入"。不要从 Lore 反推数据。
  • 修改 Lore 不会改变真实状态。
  • 刷新物品时,CoreLib 会重新从 PDC 读取并重建展示。

配置者需要知道什么

大多数时候你不需要手动编辑 PDC。你需要知道的是:

  • 不要用其他插件随意清理 Emaki 物品的 PDC。例如某些"物品清理"插件可能会移除自定义 NBT 数据。
  • 不要把有 PDC 的装备通过不兼容插件重写成全新物品。例如某些物品编辑插件会创建新 ItemStack 而丢失原有 PDC。
  • 调试装备时,应使用 inspect / dump 类命令查看真实状态。不要只看 Lore 判断装备是否正常。
  • 如果要清除某个模块状态,优先使用模块提供的 clear / reset 命令。手动删除 PDC key 可能导致数据不一致。
  • 备份重要装备。在做破坏性测试前,确保有备份。

开发者需要注意什么

如果你要写扩展模块或接入 CoreLib:

使用独立 namespace

java
NamespacedKey key = new NamespacedKey(yourPlugin, "your_data_key");

不要使用其他模块的 namespace 写入数据。

控制数据大小

不要把大型对象直接无边界写入 PDC。物品 PDC 数据会随物品在网络中传输,过大的数据会影响性能。建议:

  • 只保存必要的标识和数值。
  • 复杂数据保存到外部文件,PDC 中只存引用 ID。
  • 列表数据设置合理上限。

版本号和迁移

保存结构化数据时要考虑版本号:

java
container.set(versionKey, PersistentDataType.INTEGER, 2);

当数据格式变化时,通过版本号判断是否需要迁移。CoreLib 的 SnapshotCodec 提供了编解码和版本兼容支持。

展示由 Assembly 统一生成

对外展示应由 Assembly / Renderer 统一生成,而不是直接拼 Lore。这样可以:

  • 保证多模块展示顺序一致。
  • 避免重复或遗漏。
  • 支持模板化和国际化。

读取其他模块数据

优先使用公开 API 或 bridge,不要依赖内部 key:

java
// 推荐:通过 API 获取
EmakiAttributeBridge bridge = ...;
double attack = bridge.getAttributeValue(player, "physical_attack");

// 不推荐:直接读取内部 PDC key
NamespacedKey internalKey = new NamespacedKey(attributePlugin, "internal_key");

内部 key 可能在版本更新时变化,API 则保持稳定。

数据生命周期

事件PDC 行为
物品创建模块写入初始 PDC 数据。
物品操作(强化/锻造/镶嵌)对应模块更新自己的 PDC 数据。
物品刷新CoreLib 读取 PDC,重建展示层。
物品丢弃/存箱PDC 数据随物品保存。
服务器重启PDC 数据随物品持久化,不会丢失。
物品被其他插件复制取决于复制方式,ItemStack.clone() 会保留 PDC。
物品被 NBT 编辑器修改可能破坏数据结构,不建议手动修改。