变量引擎
变量是物品级的动态值:随机数值、品质词、星级、动态文本等。类似 MMOItems 的占位符 / RNG 属性。
1. 变量能干什么
- 武器每件随机滚一个伤害值。
- 品质前缀 / 后缀文本随物品变化。
- Lore 里插入动态数字、品质名、描述。
- 配合星级、强化等级显示。
2. 声明变量
在物品(或碎片)的 variables: 段声明,键是变量名,值是范围或静态字符串:
yaml
random_blade:
material: iron_sword
display_name: "<gold>{tier_name} 之刃</gold>"
lore:
- "基础伤害:{min_damage} - {max_damage}"
- "暴击几率:{crit_pct}%"
variables:
min_damage: "10 - 15" # 范围 → 每件随机滚
max_damage: "25 - 35" # 范围
crit_pct: "5 - 15" # 范围
tier_name: "传说" # 静态字符串范围语法
最小值 - 最大值(空格-连字符-空格,正则 ^-?\d+(\.\d+)?\s*-\s*-?\d+(\.\d+)?$):
| 写法 | 行为 |
|---|---|
15 - 25 | 在 [15,25) 滚一个值,整数则输出 20 |
1.5 - 2.5 | 在 [1.5,2.5) 滚,输出带 .0 的浮点 |
-10 - 10 | 允许负数 |
若 min >= max,直接返回 min(不滚)。
3. 占位符语法
用 {变量名} 在文本里引用变量。合法字符:字母数字、下划线、连字符([a-zA-Z0-9_\-],不含空格)。
yaml
display_name: "<gold>{name}</gold>"
lore:
- "伤害:<red>{damage}</red>"
- "类型:{type}"
- "{description}"- 找不到的变量原样保留(
{missing}→{missing}),不报错。 - 可用于:
lore、display_name、动作的lore、action_lore值。
4. 滚 → 解析 → 渲染 → 冲突 管线
变量经过四个阶段:
| 阶段 | 类 | 干什么 |
|---|---|---|
| Roll(滚) | VariableRoller | 物品创建时,把范围滚成具体值,存进实例数据 values |
| Resolve(解析) | VariableResolver + ConflictResolver | 多源合并出最终值 |
| Render(渲染) | VariableRenderer | 把 {变量} 替换进文本 |
| Trace(溯源) | VariableTrace | 记录每个变量的来源历史,调试用 |
解析的四个来源与优先级
| 来源 | 优先级 | 内容 |
|---|---|---|
| TEMPLATE | 10 | definition.variables(模板声明) |
| INSTANCE | 20 | 实例 values(创建时滚出的值) |
| LAYER | 30 | 层补丁里的变量 |
| RUNTIME_OVERRIDE | 40 | 实例 overrides(API 运行时设置) |
优先级高的胜出(RUNTIME > LAYER > INSTANCE > TEMPLATE)。不同 owner 冲突时会记录一条 VariableConflict。
5. 变量的合并(碎片 / 覆盖)
变量按以下顺序叠加(后者覆盖前者):
- 碎片(按
fragments:列表顺序) override.variables段- 根级
variables段(最高优先级) - 自动注入:若设了
tier,则variables["tier"] = <小写tier>
yaml
dragon_plate:
fragments:
- armor_base # 碎片里 armor_type=Light
override:
variables:
armor_type: "Heavy" # 覆盖碎片
variables:
base_defense: "15" # 最高优先级
lore:
- "类型:{armor_type}" # → Heavy
- "防御:{base_defense}" # → 156. 保留 / 自动变量
| 变量 | 来源 |
|---|---|
tier | 自动从 tier: 字段注入(小写) |
star | 星级,渲染名尾 [+N](部分类型) |
soulbound.owner | 灵魂绑定时设置,见 灵魂绑定 |
soulbound.level | 绑定等级 |
7. 开发者 API
通过门面 QinhItemsAPI.variables()(详见 API 参考):
kotlin
val api = QinhItemsAPI.variables()
api.get(item): Map<String,String> // 取解析后的变量
api.explain(item): Map<String, VariableTrace.Entry> // 溯源(调试)
api.set(item, key, value, owner): Pair<ItemStack?, InstanceWriteResult>
api.setAll(item, values, owner): Pair<ItemStack?, InstanceWriteResult>
api.lock(item, key, owner): Boolean // 锁定变量,防他人改
api.unlock(item, key, owner): Boolean
api.refresh(item): ItemStack? // 重渲染显示写入结果 InstanceWriteResult:OK / NOT_QINH_ITEM / LOCKED_BY_OTHER / DOMAIN_VIOLATION。
溯源示例
kotlin
val trace = QinhItemsAPI.variables().explain(item)
trace["damage"]?.let {
it.value // 最终值
it.source // TEMPLATE / INSTANCE / LAYER / RUNTIME_OVERRIDE
it.owner // 谁写的
it.formatHistory() // "template=5 → instance=10 → runtime=15"
}锁定
kotlin
QinhItemsAPI.variables().lock(item, "damage", owner = "my_plugin")
// 之后别的 owner 调 set 会得到 InstanceWriteResult.LOCKED_BY_OTHER8. 存储格式
变量实例数据以 YAML 串存在物品 NBT(键 qinhitems:instance):
yaml
values:
damage: "20"
tier_name: "传说"
overrides:
damage: "30"
override_owners:
damage: "my_plugin"
locks:
damage: "my_plugin"
seed: 12345678种子(seed)保证可复现:相同 seed 滚出相同随机值。