Files
gplan-2/design/gdd/analysis/d2-data-config.md
T
2026-09-14 18:18:49 +08:00

197 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# D2 数据配置与数值表 设计推演
> 状态:concluded(未闭合项见文末「开放问题」)· 本文只装"为什么"——`design/gdd/d2-data-config.md` 只收本文的结论。
> 修订时新增问题节,不删旧节(历史即依据)。
## 问题 1:为什么要有 D2——数值集中一处、schema 先行、单点发放?
### 广度分析
- 候选 A:参数随各系统代码硬编码——收益:少一层间接;代价:调一次难度要改五处代码、战斗无法用固定种子复现、headless 自动化测试无从谈起。
- 候选 B:集中数值表但允许多入口读取——代价:副本绕过校验,热重载换新值时副本不知情,单一事实源名存实亡。
- 候选 C(采纳):数值表单一事实源 + ConfigDB 单点类型化读取 + schema 先行、数值回填。
### 深度分析
schema 先行使 D2 能在设计顺序第 1 位交付而不阻塞下游:结构(自定义 Resource 类,字段带类型/范围/默认/注释)由 D2 定死,数值由 owner 系统 GDD 按设计顺序回填——先有格子、后填数字。本 GDD 只定数据结构、注册表与校验模式,不替任何系统定平衡。
### 综合判断
design 件设计目的、系统范围与规则 1/2/3 即本结论:玩法数值零代码字面量、取数只经 ConfigDB、全部表两件套交付。
## 问题 2:为什么 fail-fast 无软回退、唯一软着陆只给 debug 热重载?
### 广度分析
- 候选 A:软回退(出错用默认值或上一好值带病运行)——代价:错误数值上线比崩溃更伤(P1/P2 信任底线),且放行带病数值会使 CI 冒烟失去意义。
- 候选 B(采纳):加载期与运行期一律致命中止;唯一例外 = debug 热重载校验失败时保留旧表停留 Ready——不杀运行中的调试会话。
- 校验通道候选:单通道(测试侧无法断言致命路径——Godot 无进程内拦截 push_error/push_warning 的 API)vs 校验双通道 collect_only(采纳:游戏通道致命、测试通道收集不升级,诊断收集器承载冒烟断言与四元组去重状态)。
### 深度分析
release 构建的致命表现(引擎默认错误路径的实际行为)尚未验证,显式 deferred 到首次 release 导出 checklist——设计顺序第 1 位时无导出模板可依赖。headless 下走 `--script` 协议独立进程非 0 退出,因为同阶段无主场景可依赖,脚本须 extends SceneTree 以获得 quit(code)、autoload 须由脚本显式实例化。
### 综合判断
规则 6、校验双通道表、状态机 Failed 两路径与 EC16 即本结论;校验严格度不设 knob(fatal 写死)。
## 问题 3:难度行解析为什么 floor + warning、无兜底无外推?
### 广度分析
- 候选 A:default 行兜底——代价:配置缺口被静默吃掉,难度断档不可见。
- 候选 B:clamp / 线性外推——代价:超表成长语义是 C3 owner 公式的职责,D2 越权定义成长。
- 候选 C(采纳):floor 到不超过请求坐标的最近已有行 + 非精确命中记 warning(四元组去重);实体键精确匹配不近似;越域请求由前置守卫致命拦截。
### 深度分析
核心判据:进度坐标可以就近近似,"是哪种敌人"不能近似——身份近似会静默改变遭遇构成、损害 P2 归因。warning 定位是开发期异常信号而非审计工具(防刷屏去重是刻意的);难度审计由离线曲线导出工具承担(headless 导出 resolve(level 1..N × depth 0..M) 矩阵供 diff,C3 期交付——排期倒挂见开放问题 #5)。depth 分量永不 ceil 的保证来自 EC15 锚行校验:防"入口天灾"(入口请求静默 floor 到深行造成难度突刺),写死开、非 knob,重议须走本 GDD 显式修订流程。
### 综合判断
design 件「难度行解析」的 R1 结论与表达式、missing_type 枚举(base_ceil 恒记规则由本分类推导)与 EC4/EC5/EC14/EC15 即本结论。
## 问题 4:流种子派生为什么是纯函数、为什么不用运行时 hash()?
### 广度分析
- 候选 A:运行时 `hash()` 混合流名——代价:Godot 不承诺 hash 跨版本稳定,黄金向量与跨版本复现失去意义。
- 候选 B:scope 自增值直接作种子——代价:同 master_seed 下不同流的同序号 scope 互相碰撞。
- 候选 C(采纳):`( SALT_s XOR wrap64(master_seed + scope × GOLDEN_RATIO) ) AND 0x7FFFFFFFFFFFFFFF`——每流互异奇盐、黄金比例乘数、wrap64 自然回绕、掩码收尾。
### 深度分析
中间积本就越界(乘数 0x9E3779B97F4A7C15 > 2^63,scope=1 即回绕)——这是设计依赖的语义而非缺陷,故禁止 float 中间量(53 位尾数必丢精度)、禁止对中间量用 `%`(带符号取余语义易误用)、禁止"主动修复溢出";三个常量均 ≥2^63,GDScript 十六进制字面量按二补数解析为负,故统一用分段表达式书写。跨 master_seed 的全局单射由鸽笼原理数学排除,不做声明。INT64_MIN 致命而非归一化:abs 在 int64 对 INT64_MIN 恒等回绕,输出掩码抹掉 bit 63 使其与 0 静默别名(实测与 0 在全流种子逐一相等——掩码本身是规约的一部分);负 scope 同理会与 scope+2^63 经掩码别名,故 debug 断言中止。计数器永不重置、不随关卡/图序重置——否则不同关卡的同序号图会得到相同种子;set_master_seed 仅许全流计数器全零时调用——冒险中途重播种会静默清零计数器,击穿同冒险无碰撞前提与 D3 快照语义。
### 综合判断
design 件 R2 结论、公式、实现级规约三行、黄金向量表(AC-3 常量依据,经独立复算验证)即本结论;状态线独立不变式(reload 不触碰 RNG——若按状态机对称性在 reload 时重置 RNG 将击穿 AC-4)同理成立:派生只依赖盐/master_seed/scope,与表数据无关。
## 问题 5:RNG 为什么封闭三流、增流为什么要过 P1 评审?
### 广度分析
- 候选 A:各系统自建 RandomNumberGenerator / `randomize()`——代价:不可复现,回放/审计/自动化测试全废。
- 候选 B:流自由注册——代价:流复用破坏可复现隔离,未知名流静默产生。
- 候选 C(采纳):封闭具名流(board_gen / reward_roll / encounter),增流 = 改代码 + P1 支柱评审(随机须有界、可见或可推理)——有意设卡。
### 深度分析
三流的 scope 事件绑定是各自消费者契约的一部分:board_gen = 每次生成新扫雷图(A1 换图时);reward_roll = 每次 board install 批(格奖励批 + 清图奖励批,B4 AC-1 为契约源);encounter = 每场战斗实例化恰一 scope(begin_battle 实例化期、扫雷开始前——unit_count 区间均匀骰在挖掘决策域之外,P1 合规;C3 遭遇随机化批增流,registry 已登记)。`derive_at` 纯函数不推计数器——预览取数不污染正式序列,杜绝预览类取数的平衡 Heisenbug。同帧多系统请求同一流允许(EC13):Godot 主线程玩法逻辑单线程假设成立,`open_stream` 各自取号按调用顺序串行生效,不引入锁。玩法随机(如结算浮动)D2 不预置——任何系统若需要,自带方案走增流通道并通过 P1 评审(原 R4 显式排除裁决:玩法平衡公式与玩法随机都不在 D2,归 owner 系统 GDD)。
### 综合判断
规则 5、封闭流表、取数入口表与 EC12/EC13 即本结论;combat_var 类玩法随机预置流不设基础设施。
## 问题 6:debug override 链为什么是这五条边界?
### 广度分析
- 覆盖位置候选:各系统自读 override 源——代价:gameplay 可见 override 来源、多点校验漂移;采纳 = 覆盖判定与存储内聚 ConfigDB(规则 2 单点)。
- key 空间候选:任意路径含进度表行寻址(如 `difficulty.(2,0).hp`)——v1 收窄为仅单行全局表字段,行寻址语法登记为后续扩展。
- release 形态候选:运行时碰巧不生效——采纳 = 结构性不存在(不加载、不注册任何 override 源,恒等是结构保证)。
### 深度分析
override 值类型与范围复用 schema 校验逻辑——防止 debug 会话注入越界值污染平衡基线(EC11);未知 key 同样 warning + 忽略。debug 谓词做成可注入形式(`OS.is_debug_build()` 之外引入 feature 标签闸,例 `sim_release`),AC-8 的模拟以此为基础;"release 不加载 override 源"的结构保证验证本身 deferred 到首次 release 导出 checklist(AC-18)。override 仅为运行时状态,永不回写 .tres。
### 综合判断
design 件 R3 结论与边界五条即本结论。
## 问题 7:体验锚点论证——"玩家永远不该注意到的地基"凭什么撑 P1/P2?
### 广度分析
- D2 无专属玩家幻想:P1"我算对了"的掌控感来自 A1/A2 可推理设计,P2 的延迟兑现感来自 B1 可见结算;D2 只提供三种消极保障。
- 手感稳定("改数字不改代码"):全部影响手感的数字集中一处可调 + 热重载即改即验——"测试数据驱动平衡"的开发方式,任何"这轮玩起来不对劲"都能快速修正且不引入新毛刺。
- 公平可信("同决策必同结果"):可复现是开发侧信任底线(回放/审计/自动化测试),不等于玩家侧可推理;玩法随机零预置(走增流通道 + P1 评审)。
- 难度可信(P4,"越下越险由结构保证"):数值表天生带(关卡序号, 节点深度)两维——难度曲线可审计、可回溯,而非散落各处的魔法数字。
### 深度分析
难度第三轴"精英/Boss 修饰"已定稿难度 = f(关卡序号, 节点深度, 精英/Boss 修饰)(game-concept),但修饰语义归 C1/C3——D2 只做 DifficultyTable 的 elite_/boss_ 前缀命名空间预留与 Boss=Dmax 行约定,不定义任何修饰数值、不预写修饰枚举;两键定不了精英性的节点形态(如分支地图同深度并存精英与普通节点)允许改键,按接口漂移修订规则回写(与 MetaTable 同等豁免待遇);A1 OQ6 是 C1 定稿时的强制重审门。DifficultyTable 乘数域 [0.1,10] 已 registry 预登记;越域 clamp+warning 是 registry 登记的显式例外——组合事故非配置事故,非 fail-fast 场景。
### 综合判断
design 件设计目的四条承诺、规则 4 轴归宿表与 DifficultyTable 占位行即本结论。
## 问题 8:已裁决争议与数值锚定论证汇总
### 广度分析
- 单行全局表先例链:ActionEconomyTable 立先例 → HeroTable / RewardConfigTable / SettlementTable 沿用(无成长语义的表允许只放一行);MetaTable 为元进度轴豁免,C4 可改键。
- weaken = −65(值域 [60,85]——B1 F0 裁决,条款 2 锚闭合);defense_up = −30(减伤墙批 C3 投值,叠满两层 −60 帽——B3/registry 同批)。
- HeroTable atk = 6 原型锚(provisional 归 C3);atk = 0 加载拒绝——"0 基线 × 百分比增益恒零"死锁自 schema 层杜绝(基础攻击恒存在,消费面 = 主角战斗段先手攻击)。
- RewardConfigTable 标定:active_p0 = 0.4(供给控制器注入概率初值,首件之后每张新板——E[战斗获取] ≈ 1 标定目标,归 C3);active_decay = 0.5 指数递减 0.4→0.2→0.1→…(加难杠杆候选 0.6 随 C3 OQ7 扫描);p_min = 8(默认根最低刀 power——K≥1 供给闸刀力下界 floor_supply_missing);k_dmg = 0 = F5 断言关闭——刀保底语义由供给控制器战斗首件保证取代,no_damage_row 后闸托底。
### 深度分析
两处溯源缺口在案:EnemyTable MVP 行值(goblin 18HP / 4ATK 等)出自原型 REPORT、出处待查(义务 #5);HeroTable max_hp MVP 值出处待查(义务 #6)。provisional 值在 owner 定稿前不视为平衡事实;定稿后删除调参表清单对应条目,值的事实登记归 owner GDD 与 registry——已定稿占位参考值(标中旗 / 清图奖励 / 状态四行 / 奖励池等)已随各 owner 定稿清退。
### 综合判断
数值事实留 design 调参表与 registry,锚定论证收于本节;胜场成长机制去留(+25% HP / +1 ATK——反雪球问题)仍待 C3 裁决(义务 #7,在案未闭合)。
## 附录 A:评审与审计元数据
- 评审:lean 门禁 systems-designer / qa-lead;full 评审 + 同日 re-review 含 game-designer / creative-director,CD-GDD-ALIGN 终裁 Approved——评审日志 `design/gdd/reviews/d2-data-config-review-log.md`。
- 双向一致性核对明细(与 systems-index 依赖分层表核对一致):A1←A4,D2 · B2←D2 · B4←D2 · B1←A3,B2,B3,B4,D2 · C2←C3,D2 · C4←D3,C2,D2 · C3←D2,B2 · Foundation 含 D2;C2 / B1 / B4 / C4 ← D2 四条边已补入索引依赖分层表;B4←D2 边已按 B4 定稿收窄——A2 事实经 B1 转化零直接接口、B3 为验收锚关系非运行时边。
已闭环对账义务(历史审计,design 不再列):
| 编号 | 内容 | 对侧 | 状态 |
|---|---|---|---|
| 1 | ActionEconomyTable 跨字段校验(任一动作成本 ≤ ap_per_round)条件性夹具登记 | A3 | 已登记(schema 类别承载,随 A3 冒烟) |
| 2 | VariationTable 跨字段校验 hide_numbers⇒safe_nonzero 夹具 variation_mask_constraint | A4 | 已激活 |
| 3 | StatusEffectTable effect_id 悬空引用校验(条件性夹具——首个含引用字段的 owner 回填时补) | B3 / B4 | 已激活(B4 defense_up 首引,夹具 b4_dangling_effect) |
| 12 | 双向一致性四条边补入索引依赖分层表(C2 / B1 / B4 / C4 ← D2) | systems-index | 已完成 |
## 开放问题
| # | 问题 | owner |
|---|---|---|
| 1 | headless 测试载体终稿:MVP 用 `--headless --script` 冒烟(本 GDD 决策);gdUnit4 是否在 Technical Setup 引入并迁移冒烟用例 | Technical Setup 阶段(systems-index 门禁增补记录项) |
| 2 | 编辑器内表文件热重载自动化(当前仅 debug 键触发;低优先) | 未指派 |
| 3 | 数值表显示名的本地化 | D6 |
| 4 | C4 MetaTable 并入 ConfigDB 还是独立 autoload(倾向并入) | C4 GDD |
| 5 | 难度曲线导出工具(R1 审计的离线载体):headless 导出 resolve 矩阵脚本,C3 期交付——排期倒挂:BoardGenTable 可推理率曲线自 A1(第 5 位)起回填,A1 定稿前须有临时抽查载体(入 systems-index 门禁记录) | C3 GDD 登记排期 |
| 6 | systems-index 树形概要行仍写"九张表单一事实源",与本 GDD 现行十张表 schema 目录(AuxItemTable 转正后)不一致——索引行归 systems-index 维护批修订,本件不代改 | systems-index 维护批 |
## 去向映射(零丢失可审计证据)
| 原文章节 / 表 | 落点 |
|---|---|
| 头部块(状态/版本/支柱/层级/一句话) | design 头部块;评审行 → analysis 附录 A |
| 速览表(定位/拥有/不拥有/上游/下游/硬约束) | design 设计目的 / 系统范围(含硬约束行)/ 依赖与输出 |
| 存在理由·策略·定位三行 | design 设计目的 + analysis 问题 1、7 |
| 体验锚点表 | design 设计目的四条承诺;论证 → analysis 问题 7 |
| 全局流程(三链路字符画 + 出口分发表) | design 核心循环 |
| 核心规则 1 / 2 | design「统一取数与调试覆盖」规则 1 / 2 |
| 核心规则 3 / 4 + 表形状 / 轴归宿两表 | design「表结构与回填」 |
| 核心规则 5 + 流表 / 取数入口表 | design「随机数服务」 |
| 核心规则 6 / 7 / 8 + 错误两类表 | design「加载·校验·热重载」 |
| 规则 6 实现参照——校验双通道表 | design「加载·校验·热重载·校验双通道」 |
| 枚举·十张表目录 / 未回填占位表 / MVP 内容行 | design「表结构与回填」三个子节 |
| 枚举·RNG 流 | design「随机数服务·封闭流与取数入口」(与规则 5 流表去重合并,内容一致) |
| 枚举·missing_type | design「难度行解析·missing_type」 |
| 枚举·致命错误类别 | 并入 design 规则 6 错误两类表(段序违例/池映射悬空/p_perfect 越域三覆盖项并入加载期行) |
| 枚举·override key 空间 | 并入 design R3 边界②(key 形态与支持域内容完全重合) |
| 数值结论与推导 R1(结论/推导/变量/Example/去重键) | design「难度行解析」(结论 + 表达式 + 变量 + 验算);取舍与审计论证 → analysis 问题 3 |
| 数值结论与推导 R2(结论/公式/实现级规约/变量/黄金向量) | design「随机数服务·R2 流种子派生」;机理与候选论证 → analysis 问题 4 |
| 数值结论与推导 R3(结论 + 边界五条) | design「统一取数与调试覆盖·调试覆盖链」;候选取舍 → analysis 问题 6 |
| 数值结论与推导 R4 显式排除 | design 系统范围不负责清单 + 规则 5 增流通道;论证 → analysis 问题 5 |
| 状态(状态机表 + 不变式) | design「加载·校验·热重载·状态机」 |
| 状态·RNG 生命周期 / 快照三行 | design「随机数服务·RNG 生命周期与快照」 |
| 边界情况 EC1–EC16 | design「加载·校验·热重载·边界情况」(编号不变) |
| 依赖表 + 三行注记 | design 依赖与输出;双向一致性核对明细 → analysis 附录 A |
| 登记与对账义务 #4–#11(在案) | design 依赖与输出·登记与对账义务表 |
| 登记与对账义务 #1 / #2 / #3 / #12(已闭环) | analysis 附录 A |
| 呈现与 UI 面 | design「呈现与 UI 面」 |
| Tuning Knobs·D2 自身 knobs + 交互 / 清退注记 | design 调参表·D2 自身 knobs |
| Tuning Knobs·九张表逐表字段行 | design 调参表·表 schema 逐表字段行 |
| 验收标准·测试口径 + AC-1–AC-18 | design 验收标准(编号不变) |
| 开放问题 1–5 | analysis 开放问题(编号不变);#6 为本次迁移新登记的跨文档不一致 |
| 数值锚定论证(weaken/defense_up/atk/active_p0/p_min/k_dmg 等) | analysis 问题 8(数值事实本身留 design 调参表与 MVP 内容行表) |
| 版本历史全部行 | design 版本历史(原行全保留,追加 v2 迁移行) |