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 编辑器修改 | 可能破坏数据结构,不建议手动修改。 |