层(Layer)与装配管线
层是物品创建后追加的补丁(打孔 / 镶嵌 / 强化 / 附加词缀),装配管线是把模板 + 实例 + 层合成 ItemStack 的过程。本章是这套核心机制的开发者参考。
1. 层是什么
层(QinhLayerPatchPack)是叠在编译后定义之上的补丁,无需重编译模板即可改物品:
kotlin
data class QinhLayerPatchPack(
val id: String,
val priority: Int = 0, // 排序(小者先应用)
val owner: String, // 写域归属(gem/enchant/forge…)
val variables: Map<String,String> = emptyMap(), // 变量补丁
val lockRequests: Map<String,String> = emptyMap(), // 变量锁
val meta: Map<String,String> = emptyMap(),
) {
fun sanitized(): QinhLayerPatchPack // 过滤受保护键
}层类型与顺序
kotlin
enum class QinhItemLayerType(val namespace: String, val order: Int) {
BASE("base", 10),
VARIABLES("variables", 20),
SECTION("section", 35),
AFFIX("affix", 36),
EXTERNAL("external", 100),
}层按 order 升序叠加。
2. 语义守卫(LayerSemanticGuard)
层补丁不能改动战斗关键键(防破坏平衡)。拒绝列表包括 attack_damage / crit / defense / health / mana / skill / strength / attack_speed / lifesteal 等及含 *attack* 等可疑模式的键。sanitized() 会过滤掉这些键并警告。
要改属性,走 Provider 而非层补丁。
3. 写域策略(WriteDomainPolicy)
层 / 实例 / 运行时三个域,限制谁能改:
| 域 | 默认 owner | 默认前缀 | 用途 |
|---|---|---|---|
| INSTANCE | qi_core / give / init / template | — | 核心物品数据 |
| LAYER | strengthen / forge / gem / enchant / socket / refine / embed / upgrade | sys_ / layer_ | 持久化改造 |
| RUNTIME | qi_admin / qi_ui / admin | buff_ / temp_ / ui_ | 临时覆盖 / UI |
kotlin
WriteDomainPolicy.validateLayerWrite(owner, layerId): Verdict
WriteDomainPolicy.validateRuntimeWrite(owner): Verdict配置见 config.yml → write-domains。越权写入在 strict: true 时报错。
LayerWriteResult:OK / NOT_QINH_ITEM / DOMAIN_VIOLATION / PROVIDER_PATCH_FORBIDDEN。
4. 层 API
kotlin
// 写补丁(自动校验写域)
val (item, result) = QinhItemsAPI.assembly().applyLayerPatch(stack, QinhLayerPatchPack(
id = "gem_1",
owner = "gem",
priority = 50,
variables = mapOf("gem_slot_1" to "amethyst"),
lockRequests = mapOf("gem_slot_1" to "gem"),
))
// 读
QinhItemsAPI.assembly().readLayerPack(stack, "gem_1"): QinhLayerPatchPack?
QinhItemsAPI.assembly().layerStack(stack): List<QinhLayerPatchPack>
// 删
QinhItemsAPI.assembly().removeLayer(stack, "gem_1")
// 类型安全读层值
QinhItemsAPI.layers().read(stack, "gem_1"): QinhLayerState?
QinhItemsAPI.layers().int(stack, "gem_1", "level"): Int?NBT 序列化由 LayerPatchCodec 完成(存为 YAML 串),栈管理由 LayerStack。
5. 装配管线(QinhItemAssemblyService)
入口:
kotlin
build(definition, amount = 1, player = null, templateInstance = null): ItemStack? // 全新
rebuild(item): ItemStack? // 重建
applyLayerPatch(item, pack): Pair<ItemStack?, LayerWriteResult>
removeLayer(item, layerId): ItemStack装配序列
assemble(definition, amount, player, freshGenerate, instance?, layerStack?)
├─ 建 QinhItemAssemblyContext(freshGenerate 时按 InstanceSeedPolicy 分配种子)
├─ 事件 QinhItemGenerateEvent(freshGenerate 时,pre)
├─ 事件 QinhItemAssembleEvent(pre)
├─ 逐个层贡献者执行:
│ BaseLayerContributor(10) 建基础 ItemStack
│ VariablesLayerContributor(20) 解析变量、渲染、加锁、抛 QinhItemCompiledEvent
│ SectionLayerContributor(35) 注入段
│ AffixLayerContributor(36) 注入词缀
│ External(100) 第三方
│ (各贡献者返回 QinhItemLayerSnapshot,并入 compiledState)
├─ 加 layer.summary.* 汇总变量
├─ QinhItemTags.stamp(stack, id, version, hash)
├─ 写实例数据到 NBT
├─ 事件 QinhItemAssembleEvent(post)
└─ 返回 ItemStack- 全新生成才分配随机种子;重建保留种子 / 实例,只重渲染。
- 变量由
QinhVariableEngine.resolveWithTrace()解析,结果存CompiledState。
自定义层贡献者
kotlin
interface QinhItemLayerContributor {
val namespace: String
val order: Int
fun contribute(context: QinhItemAssemblyContext): QinhItemLayerSnapshot?
}
QinhIntegrationRegistry.registerLayerContributor(myContributor)6. 模板系统
TemplateCompiler 把 YAML 编译成 QinhItemDefinition:合并碎片 → override → 根字段,注入 tier 变量,迁移旧 effects,编译基础值进 ap,读 actionLore / 宝石孔 / 段 / 词缀 / 附魔 / 资源包。合并规则见 碎片与模板。
7. 编译追踪
kotlin
data class CompiledState(
val variableTrace: Map<String, VariableTrace.Entry>,
val conflicts: List<VariableConflict>,
val resolvedVariables: Map<String, String>,
val layerSnapshots: List<QinhItemLayerSnapshot>,
val compileEpoch: Long,
)CompileEpoch.next():每次装配自增的单调计数。CompileSessionStore:编译结果 LRU 缓存(最多 4096,按物品指纹)。
8. 库清单
kotlin
data class LibraryManifest(
val id: String, val displayName: String, val version: String,
val description: String, val category: String,
val types: List<String>, val capabilities: Set<TypeCapability>,
val dependencies: List<String>, val author: String,
)
LibraryManifestRegistry.get(id) / all() / reload()服主向说明见 碎片与模板 → 库清单。