物品装配系统
装配系统用于把多个模块写入的物品状态合并成最终显示。它是装备成长线的核心基础设施之一。
为什么需要装配系统
在 RPG 服务器中,同一件装备可能同时拥有:
- EmakiItem 写入的基础名称、基础 Lore、套装、技能。
- EmakiForge 写入的品质、锻造材料、额外属性。
- EmakiStrengthen 写入的星级、强化加成、失败标记。
- EmakiGem 写入的插槽、宝石、宝石等级。
- EmakiAttribute 写入或读取的属性 payload。
如果每个模块都直接改最终 Lore,就会产生覆盖、重复、顺序混乱和残留。装配系统的做法是:各模块写入自己的结构化 layer,CoreLib 再统一渲染最终展示。
核心概念
| 概念 | 说明 |
|---|---|
| namespace layer | 每个模块在物品上的数据层,包含该模块写入的所有状态。 |
| order | 层的排序权重,决定最终 Lore 中各模块展示的先后顺序。 |
| snapshot | 层数据的快照,用于编解码和持久化。 |
| contribution | 层对最终展示的贡献,包括 Lore section、名称修饰和属性统计。 |
| renderer | 渲染器,负责把所有 contribution 合并成最终 ItemMeta。 |
namespace layer
| Namespace | Order | 说明 |
|---|---|---|
forge | 100 | 锻造层。包含品质、材料贡献、锻造配方信息。 |
strengthen | 200 | 强化层。包含星级、锻印、保护状态、强化属性。 |
gem | 300 | 宝石层。包含插槽、宝石、等级、宝石属性。 |
cooking | 10000 | 烹饪展示层或特殊展示。 |
order 越小越靠前。这样可以控制最终 Lore 中各模块展示顺序。
装配流程
text
1. 业务模块完成操作(如强化成功、宝石镶嵌)
↓
2. 模块把真实状态写入 PDC(layer snapshot)
↓
3. 模块通过 ItemOperationLedger 执行 name_actions/lore_actions
↓
4. Ledger 记录操作到 PDC(emaki:item.operations),支持后续精确回退
↓
5. 返回更新后的 ItemStack当需要回退操作时(如宝石提取、强化降级):
text
1. 模块调用 Ledger.revert(operationId) 或 Ledger.revertAll(sourceNamespace)
↓
2. Reverter 根据账本记录精确撤销对应的名称/Lore 修改
↓
3. 不影响其他模块的操作结果关键服务
| 服务 | 说明 |
|---|---|
EmakiItemAssemblyService | 物品装配入口,负责接收重建请求并协调各 layer。 |
ItemOperationLedger | 统一 Name/Lore 操作账本,支持精确回退。 |
ItemOperationExecutor | 执行 name_actions/lore_actions 并记录变更。 |
ItemOperationReverter | 根据账本记录精确回退操作。 |
EmakiNamespaceRegistry | namespace 注册和顺序管理,维护所有已注册 layer 的 order。 |
EmakiItemLayerCodecRegistry | layer 数据编码、解码和兼容,处理版本迁移。 |
Lore 操作账本(ItemOperationLedger)
每次模块对物品执行 name_actions 或 lore_actions 时,Ledger 会生成一条带 operationId 的记录存入物品 PDC(emaki:item.operations)。
每条记录包含:
| 字段 | 说明 |
|---|---|
operationId | 操作唯一标识。 |
sourceNamespace | 来源模块标识(如 gem、strengthen、forge)。 |
timestamp | 操作时间戳。 |
nameRecords | 名称修改记录(用于回退)。 |
loreRecords | Lore 修改记录(用于回退)。 |
核心 API:
| 方法 | 说明 |
|---|---|
apply(itemStack, operationId, sourceNamespace, nameActions, loreActions, variables) | 执行操作并记录到 PDC。 |
revert(itemStack, operationId) | 精确撤销指定操作。 |
revertAll(itemStack, sourceNamespace) | 清空某命名空间的所有操作。 |
名称修饰(Name Contribution)
除了 Lore,layer 还可以修饰物品名称。例如:
- 强化层在名称前添加
+10。 - 锻造层在名称后添加品质标签
[史诗]。 - 宝石层不修改名称。
名称修饰支持位置控制:
| 位置 | 说明 |
|---|---|
PREFIX | 添加到名称前面。 |
POSTFIX | 添加到名称后面。 |
多个 layer 的名称修饰按 order 排序拼接。
注意:位置枚举值为
PREFIX和POSTFIX,不是SUFFIX。
配置者能做什么
配置者通常不直接操作装配服务,但会影响装配结果:
调整 Lore 模板
各模块通常在自己的配置中提供 Lore 模板:
yaml
# EmakiStrengthen 配置示例
lore:
template:
- '<gray>强化等级:<yellow>+%star%'
- '<gray>强化加成:<green>+%bonus_attack% 攻击'调整属性展示格式
在 EmakiAttribute 的 lore_formats/ 中定义属性如何显示:
yaml
# lore_formats/default_flat.yml
format: '<gray>%display_name%:<white>+%value%'控制展示开关
部分模块允许配置是否显示某些状态:
yaml
display:
show_quality: true
show_material_info: false
show_star_level: true
show_gem_slots: true使用模块命令刷新装备
当配置变更后,已有装备的展示不会自动更新。需要使用模块提供的刷新命令:
- 手动刷新单件装备。
- 批量刷新在线玩家装备。
- 玩家登录时自动刷新(如果模块支持)。
设计装备展示的建议
- 把"真实数值"交给 PDC / 属性 payload,不要只写 Lore。Lore 是展示层,PDC 是数据层。
- Lore 中只展示玩家需要看到的信息。不要把内部调试数据写进 Lore。
- 每个模块的 Lore 区块保持边界清晰。例如锻造区、强化区、宝石区各自独立,不要交叉。
- 不要让多个模块写同一行含义相同的属性。例如攻击力只在一个地方展示,避免玩家误解。
- 对旧装备升级时,先在测试服抽样刷新。确认新模板不会破坏旧数据的展示。
- 名称修饰保持简洁。
+10 烈焰剑 [史诗]比[+10][史诗][锻造][宝石x3] 烈焰剑更易读。
装配触发时机
以下操作会触发物品重建:
| 操作 | 触发模块 |
|---|---|
| 强化成功/失败 | EmakiStrengthen |
| 锻造完成 | EmakiForge |
| 宝石镶嵌/提取/升级 | EmakiGem |
| 物品自动更新 | EmakiItem |
| 手动刷新命令 | 各模块 |
| 属性同步 | EmakiAttribute |
Lore 操作的锚点行为
当 lore_actions 中使用 insert_below 或 insert_above 操作时,如果 anchor 为空或未匹配到任何行:
| 操作 | anchor 为空时的默认位置 |
|---|---|
insert_below | 插入到 Lore 末尾。 |
insert_above | 插入到 Lore 开头。 |
Namespace ID 规范化
注册 namespace 时,ID 会被自动规范化:
- 去除首尾空格。
- 转为小写。
- 空格替换为下划线。
- 空字符串变为
unknown。