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

61 KiB
Raw Blame History

D2 数据配置与数值表(Data Config & Balance Tables)

状态:Approved · 版本:v2 · 2026-09-14 承载支柱:P1、P2(基础设施层,间接支撑全部四支柱) · 层级:Layer 1 Foundation · Milestone MVP · 设计顺序第 1 位 一句话:D2 把全部影响手感与平衡的数字收进可配置、可校验的数值表,经 ConfigDB 单点发放、RngService 统一种子化——战斗可复现、平衡可热调、headless 可测的数据底座。 推演件:design/gdd/analysis/d2-data-config.md(本文件只收结论,理由在那里)

设计目的

D2 是全部玩法数值的单一事实源:data/tables 的 .tres + autoload ConfigDB + autoload RngService——schema 先行、数值回填。没有 D2,参数散落硬编码:调一次难度改五处代码、战斗无法用固定种子复现、headless 自动化测试无从谈起。它是玩家永远不该注意到的地基:不制造情绪,但失职会直接摧毁 P1/P2 的信任底线。

  1. 设计师"改数字不改代码"——全部影响手感的数字(AP、旗、折算比例、奖励值)集中一处可调,热重载即改即验,"这轮玩起来不对劲"能快速修正且不引入新毛刺。
  2. 开发与测试"同决策必同结果"——RNG 统一种子化,相同决策序列必然相同战斗结果,回放 / 审计 / 自动化测试可复现。
  3. 难度"越下越险由结构保证"——数值表天生带(关卡序号, 节点深度)两维,难度曲线可审计、可回溯,而非散落各处的魔法数字。
  4. CI 与无窗口环境照样跑完整战斗——数据层零界面依赖。

系统范围

负责:

  • 全部表 schema 类(data/schemas)与数据文件(data/tables)
  • autoload ConfigDB / RngService · SCHEMA_VERSION 常量
  • 加载 / 校验 / 热重载状态机 · 校验双通道与诊断收集器
  • debug override 链 · 难度行解析 resolve
  • 十张已定稿表 + 两张占位表的结构与键(数值由 owner 系统按设计顺序回填)

不负责:

  • 平衡数值定值与玩法公式——伤害、掉落权重、成长曲线(owner 系统 GDD 与 registry:B1 / B4 / C3 等)
  • 玩法随机预置——任何系统若需玩法随机(如结算浮动),自带方案走增流通道并通过 P1 评审(规则 5)
  • 存档(D3)· 任何 UI 表现面
  • 精英 / Boss 修饰语义(C1 / C3——DifficultyTable 只预留 elite_ / boss_ 命名空间)· MetaTable 键结构(C4)

硬约束:玩法数值零代码字面量 · 零 UI 依赖 · fail-fast 无软回退 · RNG 流集合封闭 · 表路径固定(debug 注入根除外)· release 无 override 源。

核心循环

数据加载与校验链路

进程启动(Unloaded)
  │ ConfigDB._ready() / load_tables(root, collect_only)
  ▼
Loading ──── 按表清单逐一 load() ── 文件缺失 → Failed
  ▼
Validating ── 单个资源加载成功 → schema validate(),错误入诊断收集器
  ▼
┌ 校验双通道 ──────────────────────────────────────────┐
│ 游戏通道 collect_only=false(默认):                 │
│   错误 → push_error 清单 → 致命错误路径              │
│   editor / CI / headless / release 一律致命          │
│ 测试通道 collect_only=true(仅 debug/测试构建):     │
│   收集不升级 → 冒烟脚本逐夹具断言类别 → 一次性退出   │
└──────────────────────────────────────────────────────┘
  ▼
Ready ────── 全部通过 → 类型化属性可读

热重载链路(仅 debug)

编辑器热重载 / 调试键 → Reloading
  │
  ├─ 战斗中(set_reload_gate 已置位)→ 拒绝返回 false,停留 Ready
  │                                    (战斗结束后手动再触发,不自动重放)
  ▼
重走 Loading → Validating
  │
  ├─ 校验失败 → 保留旧表停留 Ready + debug 错误清单(唯一软着陆,不杀调试会话)
  ▼
校验通过 → Ready:新值经类型化属性可读 + config_reloaded 恰一次(仅 debug,D1 调试用)
※ RNG 状态线独立:Reloading / Failed 不触碰 RngService——计数器与 master_seed 不变(AC-4)

RNG 取数链路

进程启动 → 流待命(未播种取数 = 致命)
  ▼
冒险开始 → C2 set_master_seed()(仅全流计数器全零时受理)
  ▼
scope 事件:board_gen = 每次生成新扫雷图(A1 换图时)
            reward_roll = 每次 board install 批(格奖励批 + 清图奖励批)
            encounter = 每场战斗实例化(B1 begin_battle——unit_count 区间骰)
  │ open_stream(stream):计数器 +1 → R2 派生 → 返回已播种实例(同一 scope 事件内取数共用)
  ▼
冒险结束 → 流保留供复盘;快照 = master_seed + 各流 scope 计数器
          (须在无在飞 open_stream 实例时切出——scope 事件边界之外)

出口分发

出口 触发 动作 约束
启动致命中止 启动加载任一致命错误 输出错误清单并中止构建;headless 独立进程非 0 退出 全构建一致,无软回退
热重载软着陆 debug 热重载校验失败 保留旧表停留 Ready + debug 错误清单 唯一例外
运行期致命 请求越域 / 未播种流取数 游戏内致命错误路径;headless quit 非 0 不分构建
热重载成功 debug 且门未置位且校验通过 新值可读 + config_reloaded 恰一次 战斗中被门拒绝
存档拒读 SCHEMA_VERSION 高于当前 拒绝读取 比较归 D3,常量归 D2

表结构与回填(schema 先行)

规则:

  1. 规则 3(结构先行、数值回填):全部数值表按"结构 + 数据"两件套交付——结构 = data/schemas/ 下一个自定义 Resource 类(每字段带类型、范围、默认值和注释),数据 = data/tables/ 下数据文件;D2 先交付全部 schema 与占位表(含键结构),具体数值由 owner 系统 GDD 回填,先有格子、后填数字。 举证:无计算。十张已回填表 schema 目录见本节,逐表字段行见调参表节。
  2. 规则 4(进度坐标查行):跟着冒险进度成长的数值表(难度、生成参数、敌人配置)每行带(关卡序号, 节点深度)两维坐标——系统按坐标取数,无精确命中时取不超过请求坐标的最近已有行;敌人等实体键在命中行内按名字精确匹配,那一行没有这个名字就是悬空引用、直接致命中止,不做身份近似。 举证:解析规则(floor 取行、warning 四元组去重、越域前置守卫)见「难度行解析」节;悬空引用 = 加载期致命(规则 6)。
表的形状 行键怎么定
进度成长表 行键 =(关卡序号 level_index, 节点深度 node_depth)
实体复合键表 进度两键之后再复合实体主键列(如 EnemyTable 的 enemy_id;合成规则写入 schema 注释)
单行全局常量表 无成长语义的表允许只放一行
元进度表 存档/天赋/代币归 MetaTable,键结构归 C4 定
两维坐标之外的数值轴 归宿
战斗内轴(胜场/轮次等) 由 owner 公式承载或作为表列;归属登记进 schema 注释(C3 定稿时声明)
难度第三维"精英/Boss 修饰" game-concept 定稿:难度 = f(关卡序号, 节点深度, 精英/Boss 修饰);DifficultyTable 预留 elite_ / boss_ 前缀扩展字段命名空间,语义由 C3 定稿——本 GDD 不定义任何修饰数值、不预写修饰枚举
两键定不了精英性的节点形态 如分支地图同深度并存精英与普通节点——允许改键,按接口漂移修订规则回写(与 MetaTable 同等豁免待遇)

设计意图:进度坐标可以就近近似,"是哪种敌人"不能近似——身份近似会静默改变遭遇构成、损害 P2 归因。

十张已回填表 schema 目录(逐表字段行见调参表节)

表资源 键结构 Rule 4 豁免 跨字段 / 结构校验(加载期致命) 悬空引用政策 Owner
ActionEconomyTable 单行全局 单行全局定义表(先例) 任一动作成本 ≤ ap_per_round(schema validate() 跨字段类别承载,条件性夹具登记) — A3 ✓
VariationTable 按 variant_id(含 unlock_level 列) 定义表非进度成长表——进度语义承载于 unlock_level 列(schema 注释) info_mask=hide_numbers ⇒ cell_constraint=safe_nonzero(夹具 variation_mask_constraint) counter_item_ids MVP 不校验——A5 首个道具 id 回填时补校验 + 条件性夹具 A4 ✓
StatusEffectTable 按 effect_id 定义表非进度成长表(schema 注释承载) magnitude:percent ∈ [-100,100] ∧ ≠0 / flat ≥ 1 跨字段校验 effect_id 校验已激活(B4 RewardTable 首引 defense_up——夹具 b4_dangling_effect) B3 ✓
BoardGenTable (level_index, node_depth)——首个进度键表(depth-0 锚行内建;第三轴落点 = Boss:Dmax 行约定 + elite 命名空间预留 + A1 OQ6 重审;改键退路 = 规则 4 接口漂移通道) 无(进度成长表) fog_domain_ok(F2)+ min_safe_feasible(F2b)+ cost_feasible(F2c:attempts×W×H ≤ 16384 provisional,运行期禁墙钟逃生) — A1 ✓
EnemyTable (level_index, node_depth, enemy_id)——每行集恰一敌种 无(进度成长表,A1 同型) 每行集恰一敌种(行集内 enemy_id 唯一,违规加载期致命) — B2 ✓
HeroTable 单行全局 单行全局定义表(ActionEconomyTable 先例) atk = 0 加载拒绝("0 基线 × 百分比增益恒零"死锁自 schema 层杜绝) — B2 ✓
RewardTable 按 reward_id(多行;pool_tag 分池不参与键) 定义表非进度成长表(schema 注释承载) 池空(pool_tag × 雾/非雾两态各 ≥1 活行)· clear_default 恒正当量 · buff⇒effect_id 必填 · safe_cell 活 buff 行集非空 · floor_supply_missing / no_damage_row(跨 RewardConfigTable) effect_id 精确引用 StatusEffectTable(已激活) B4 ✓
RewardConfigTable 单行全局 单行全局常量表(HeroTable / ActionEconomyTable 先例) k_dmg=0 = F5 断言关闭(现行默认——刀保底语义由供给控制器战斗首件保证取代;no_damage_row 后闸托底) — B4 ✓
SettlementTable 单行全局 单行全局常量/结构表(HeroTable / ActionEconomyTable 先例) segment_order 恒等拍板段序校验违例致命 · effect_pool_map 键 ⊆ StatusEffectTable 活行集 · p_perfect 载体域 {100,200} 域外加载致命——三行致命 manifest:segorder_violation / poolmap_dangling / pperfect_oob effect_pool_map 悬空加载期致命 B1 ✓
AuxItemTable 按 item_id 定义表非进度成长表(schema 注释承载) target ∈ 各空间 effect_kind 支持域交集(A5 承载——真视窄域护栏校验,夹具 a5_target_violation) counter_item_ids(VariationTable → item_id)首引已定稿〔probe_dust〕、悬空校验激活随 D2×② 对侧批 A5 ✓(原 HelperItemTable 占位更名转正——A5 定稿登记)

未回填占位表

表资源 占位内容 键结构 Owner
DifficultyTable 成长参数 + 精英/Boss 修饰预留命名空间(乘数域 [0.1,10] registry 预登记;越域 clamp+warning = registry 登记的显式例外——组合事故非配置事故,非 fail-fast 场景) (level_index, node_depth) C3(第 12 位)
MetaTable 代币/天赋字段名 单行全局(元进度轴豁免,C4 可改键) C4(第 16 位)

MVP 内容行(事实登记归 registry)

表 MVP 行集 值状态
ActionEconomyTable 单行:ap_per_round=8 · dig/插旗/拔旗=1 · rap_refresh_cost=8 · move/chain=0(冻结) 定稿值,登记归 registry action_economy
VariationTable 恰含 fog 行(unlock_level=2 · hide_numbers · safe_nonzero) 岩浆/冰冻无 MVP 行(垂直切片建行)
StatusEffectTable 四行 attack_up / defense_up / ambush / weaken(全 stack) 值 provisional,锚验收归 B4/B2/B1;weaken = −65(值域 [60,85]——B1 F0 裁决,条款 2 锚闭合);defense_up = −30(减伤墙批 C3 投值,叠满两层 −60 帽——B3/registry 同批)
BoardGenTable 参考行 L1 / L2 provisional(C3 调参所有权)
EnemyTable 三敌种行 goblin / bugbear / ogre_chief(C3 修订批转正——registry enemy.mvp_content 为准) 值 provisional——溯源义务见登记与对账义务表
HeroTable 单行(max_hp / atk=6 原型锚) max_hp 出处待查;atk provisional 归 C3
RewardTable 默认根行集八行:defense_up_basic / attack_up_basic / spark_aoe / heal_minor / knife_t1 / knife_adv / heal_pack / clear_blast 值 provisional 归 C3;格子池四行即时类 + 注入池三行可选类(active_inject——供给控制器承载,原"即时 75% / 可选 25%"权重占比由注入机制替代)+ 清图槽单行
RewardConfigTable 单行 t_fog_min=2 · k_dmg=0 · n_draft=32 · p_min=8 · active_p0=0.4 · active_decay=0.5 provisional 归 C3
SettlementTable 单行默认(D_ref=12 · p_perfect=200 · 拍板段序 · clamp −100/+100 · floor · +4 字段:damage_a_per_cell=1 / damage_a_cap=8 / damage_b_per_flag=2 / armor_effectiveness 克制矩阵——护甲克制批,C3 修订批接口漂移) provisional 归 C3

加载·校验·热重载

规则:

  1. 规则 6(出错当场中止):D2 在加载与运行期发现数据出错一律致命中止,不做软回退——错误数值上线比崩溃更伤(P1/P2 信任底线);错误分两类处置(下表)。唯一例外:debug 热重载校验失败时保留旧表停留 Ready、给出错误清单,不杀运行中的调试会话。 举证:未播种流取数见边界表 EC7;请求越域见难度行解析前置守卫。两类构建分流见本节「校验双通道」。
  2. 规则 7(零界面依赖):D2 自己的代码与测试一律不 import 任何 Control/场景类——纯数据层不碰表现;没有界面依赖,CI 与无窗口环境才能跑完整战斗。 举证:无计算。验收 = 静态扫描 + headless 实跑两项合成判定(AC-10)。
  3. 规则 8(版本拒读):版本常量 SCHEMA_VERSION 归 D2;表文件与存档(D3)携带版本号,存档带来的版本号高于当前支持时直接拒绝读取——旧程序不硬猜新格式的数据。 举证:无计算。拒读行为见边界表 EC9(比较逻辑归 D3,常量归 D2)。
错误类别 什么情况 处置
加载期校验错误 启动加载/热重载时查出:字段越界、类型错、NaN、表为空或某 level 无行、缺 depth-0 锚行、重复键、悬空引用、权重和 ≤0、段序违例、池映射悬空、p_perfect 越域 经校验双通道处理;启动路径在 editor、CI、headless、release 一律致命
运行期致命 运行中越界请求:关卡/深度坐标越域(解析入口前置守卫拦截)、未设种子就取随机数 不分构建一律致命:游戏内走致命错误路径,headless 冒烟进程 quit 非 0

设计意图:MVP 有意不做软回退——带病数值上线比崩溃更伤信任底线。

校验双通道(规则 6 实现参照:ConfigDB.load_tables(root, collect_only))

通道 / 机制 要点
游戏通道(collect_only=false,默认) 校验错误 → push_error 错误清单 → 走致命错误路径(游戏内中止构建;headless 下独立进程非 0 退出——--script 协议,设计顺序 #1 时无主场景可依赖);release 构建的致命表现(引擎默认错误路径的实际行为验证)显式 deferred→首次 release 导出 checklist(与 AC-18 同待遇)
测试通道(collect_only=true,仅 debug/测试构建) 收集错误不升级,供冒烟脚本逐夹具断言错误类别后一次性退出
夹具注入 debug/test 构建允许经命令行 --data-root=<路径> 让 ConfigDB 从注入根加载(夹具放 tests/fixtures/);禁止把夹具拷进 data/tables/(污染 AC-1 的干净检出前提)
诊断收集器 resolve / 校验 / override 的 warning 与错误共用同一类目体系,统一经 ConfigDB 内部诊断收集器投递,同时镜像 push_warning 供开发期控制台(Godot 无进程内拦截 push_warning 的 API——冒烟断言必须走收集器);测试通道暴露只读诊断清单与 reset_diagnostics();跨调用去重状态(R1 四元组注册表)随 load_tables() 或 reset_diagnostics() 清空(用例间无顺序依赖);游戏通道 warning 仅镜像控制台,不承诺收集

状态机

状态 进入条件 行为/出口
Unloaded 进程启动前 磁盘 .tres 未加载
Loading ConfigDB._ready() 或 load_tables() 按表清单逐一 load();文件缺失即入 Failed
Validating 单个资源加载成功 调 schema 的 validate(),错误入收集器
Ready 全部通过 类型化属性可读
Failed(启动路径) 启动加载任一致命错误 全构建致命中止并输出错误清单
Failed(reload 路径) 热重载校验失败 保留旧表停留 Ready + debug 错误清单(不杀运行中的调试会话)
Reloading(仅 debug) 编辑器热重载 / 调试键 战斗中拒绝(返回 false,战斗结束后手动再触发);否则重走 Loading → Ready

不变式:RNG 与 ConfigDB 状态线相互独立——Reloading / Failed(任一路径)不触碰 RngService,计数器与 master_seed 不变(派生只依赖盐/master_seed/scope,与表数据无关;若按状态机对称性在 reload 时重置 RNG 将击穿 AC-4)。

边界情况

# 条件 行为 依据
EC1 表文件缺失或 load() 失败 致命中止,错误清单含路径;无软回退 规则 6
EC2 字段越界 / NaN / 类型不符 validate() 收集后致命 规则 6
EC3 表为空或某 level 行集为空 校验阶段致命(R1 前置条件),不会进入运行期 规则 6
EC4 请求 (level_index, node_depth) 无精确行 按 R1 floor 解析 + warning(按四元组去重)——预期行为,不是错误 R1
EC5 level_index 超过表最大 level 命中最大 level 行(floor 规则的自然结果,无独立 clamp 分支) R1
EC6 master_seed 为负 abs() 归一化 + warning,保证 ∈ [0, 2^63);恰为 INT64_MIN → 致命(abs 恒等回绕,与 0 静默别名——机理是输出掩码抹掉 bit 63) R2
EC7 未设 master_seed 就取随机数 push_error 后显式中止(GDScript 的 push_error 本身不终止进程——游戏内走致命错误路径,冒烟脚本 quit(1)),取到的值不可用——C2 未接线的显式暴露,禁止 seed=0 软回退 规则 6
EC8 战斗进行中请求热重载 拒绝并返回 false;战斗结束后手动再触发(不自动重放) 状态机表
EC9 存档携带的 SCHEMA_VERSION 高于当前 拒绝读取(比较逻辑归 D3,常量归 D2) 规则 8
EC10 奖励权重表权重和 ≤ 0 validate 致命(B4 回填后必须 > 0) 规则 6
EC11 debug override 类型或范围与 schema 字段不符 warning + 忽略该条(仅 debug;release 无 override 源) R3
EC12 同一流名被重复注册或请求未知名流 debug 断言中止(流名封闭) 规则 5
EC13 两个系统同帧请求同一流 允许——open_stream 各自取号(计数器各 +1)按调用顺序串行生效;单线程假设成立(Godot 主线程玩法逻辑),不引入锁 规则 5
EC14 请求越域(level_index < 1 或 node_depth < 0) 规则 6 致命(R1 前置守卫) R1
EC15 某 level 行集缺 depth-0 锚行 validate 致命(防"入口天灾":入口请求静默 floor 到深行造成难度突刺);写死开、无运行期开关,C3 如需重议走本 GDD 显式修订流程(非 knob) 规则 6
EC16 热重载校验失败 保留旧表停留 Ready + debug 错误清单 状态机 reload 路径

统一取数与调试覆盖

规则:

  1. 规则 1(数字只写在表里):凡是设计师要调的数字(行动点、插旗成本、奖励值、敌人数值……)只存在于 data/tables/ 下的 .tres 数值表里,一处定义、处处引用;代码文件里禁止出现玩法数值字面量(引擎/工程常量除外),评审发现写死的玩法数值即评审阻塞项。 举证:无计算。违规检测 = 启发式扫描 + 人工复核(AC-14,随各 owner 回填定稿与里程碑 gate-check 执行)。
  2. 规则 2(取数只找 ConfigDB):全部 19 个系统读数值只有一条路——经 autoload ConfigDB 的类型化属性读取(例 ConfigDB.action_economy.ap_per_round);禁止绕过它自己 load() 表文件或长期缓存副本(副本绕过校验,热重载换新值时它也不知情)。唯一例外:debug/测试构建可从命令行注入的根目录加载。 举证:无计算。注入根机制见「校验双通道」夹具注入行。

设计意图:单点发放 + 单点读取,热调与校验才有意义。

调试覆盖链(R3 debug_override,仅 debug 构建)

结论:effective = override[key] if _has_override(key) else table_value——仅 debug 构建加载 override 源;v1 仅支持单行全局表字段;类型/范围不符 → warning + 忽略;release 结构性不存在;永不回写 .tres。

# 边界
① 覆盖判定与存储内聚于 ConfigDB(规则 2 单点),gameplay 不可见 override 来源
② key = schema 字段点路径(与规则 2 属性路径同构,例 action_economy.ap_per_round);未知 key → debug warning + 忽略该条;v1 仅支持单行全局表字段——进度键表的行寻址语法(如 difficulty.(2,0).hp)登记为后续扩展,当前 override 对进度表无 key 空间
③ override 值类型与范围必须与 schema 字段一致,不一致 → debug warning + 忽略该条(复用 schema 校验逻辑,防止 debug 会话注入越界值污染平衡基线)
④ release 构建不加载、不注册任何 override 源(恒等是结构保证而非"碰巧不生效");debug 谓词实现为可注入形式(OS.is_debug_build() 之外引入 feature 标签闸,例 sim_release)——AC-8 的模拟以此为基础
⑤ override 仅为运行时状态,永不回写 .tres

随机数服务(RngService)

规则:

  1. 规则 5(随机只从 RngService 按流取):全项目玩法代码的随机数只此一家——autoload RngService 持有封闭的三条具名流(下表),流集合封闭、只含具名消费者;要新增随机流(含 B1 若需结算随机)必须改代码走增流通道并通过 P1 支柱评审(随机须有界、可见或可推理);玩法代码禁止 randomize() 或自建 RandomNumberGenerator。master seed 由 C2 在冒险开始时设定——同一冒险内相同决策序列必然相同战斗结果。 举证:种子派生公式与黄金向量见本节「R2 流种子派生」;依据 = B4 契约源〔AC-1〕· R2 黄金向量。

封闭流与取数入口

流 消费者 scope 取号事件
board_gen A1 布雷 每次生成新扫雷图(A1 换图时)
reward_roll B4 掉落 每次 board install 批(格奖励批 + 清图奖励批)——B4 AC-1 为契约源
encounter B1 战斗实例化 每场战斗实例化恰一 scope(begin_battle 实例化期,扫雷开始前——unit_count 区间均匀骰,挖掘决策域之外 P1 合规;C3 遭遇随机化批增流,registry 已登记)

新增流 = 增流通道:改代码 + P1 支柱评审(随机须有界、可见或可推理)。

取数入口 给谁用 行为
open_stream(stream) -> RandomNumberGenerator 玩法代码(有状态流门面) 每调用一次 = 一次 scope 取号:该流计数器 +1 → 派生 → 返回已播种实例;一个 scope 事件内所有取数共用该实例
derive_at(stream, scope) 测试/预览(纯函数) 不推计数器——预览取数不污染正式序列(杜绝预览类取数的平衡 Heisenbug)

R2 流种子派生(stream_seed_derivation)

结论:纯派生函数——同一冒险内(master_seed 固定)同流各 scope 种子互不碰撞;同输入恒同输出;跨 Godot 版本恒定(不用运行时 hash()——其跨版本稳定性无承诺);输出 ∈ [0, 2^63)。跨 master_seed 的全局单射不做声明(数学上由鸽笼原理排除)。Output Range:[0, 2^63)。

derive_at(stream, scope) = ( SALT_s XOR wrap64(master_seed + scope × GOLDEN_RATIO) ) AND 0x7FFFFFFFFFFFFFFF
wrap64 = GDScript int(64 位二补数)自然回绕 = MOD 2^64

实现级规约(必须逐条遵守,否则黄金向量失配)

规约 要点
wrap64 GDScript int(64 位二补数)的自然回绕 = MOD 2^64;禁止 float 中间量(53 位尾数必丢精度)、禁止对中间量使用 %(带符号取余语义易误用)、禁止"主动修复溢出"(中间积本就越界——乘数 GOLDEN_RATIO = 0x9E3779B97F4A7C15 > 2^63,scope=1 即回绕,这是设计依赖的语义,不是缺陷)
常量书写 三个常量(盐×2 + 乘数)均 ≥2^63,GDScript 十六进制字面量按二补数解析为负——统一用分段表达式书写(例 (0x9E3779B9 << 32) | 0x7F4A7C15,显式括号、不依赖优先级记忆),禁止直接书写 ≥2^63 的完整字面量;注意 GDScript 的 ^ 是按位 XOR
输出掩码 经 AND 掩码保证非负(∈ [0, 2^63))后再赋 RandomNumberGenerator.seed

Variables:

变量 类型 范围 说明
SALT_s int64 编译期常量 board_gen=0xA0761D6478BD642F · reward_roll=0xE7037ED1A0B428DB · encounter=0x8EBC6AF09C88C6E3(互异奇常数,均 ≠ 乘数)
master_seed int64 [0, 2^63) 冒险主种子;set_master_seed() 对负输入 abs() 归一化并 warning;恰为 INT64_MIN → 致命(abs 在 int64 对 INT64_MIN 恒等回绕,实测与 0 在全流种子逐一相等——别名机理是输出掩码抹掉 bit 63,掩码本身是规约的一部分);仅许全流计数器全零时调用(冒险中途重播种会静默清零计数器,击穿同冒险无碰撞前提与 D3 快照语义 → debug 断言)
scope int64 ≥0 派生入参;有状态门面的取号值(每流独立计数器:set_master_seed() 时归零,每次 open_stream +1,永不重置、不随关卡/图序重置——否则不同关卡的同序号图会得到相同种子);负 scope → debug 断言中止(derive_at 是预览工具入口,静默负值会与 scope+2^63 经输出掩码别名)

黄金向量(AC-3 的常量依据,经独立复算验证):

流 master_seed scope stream_seed
board_gen 42 0 2339089373825164293
board_gen 42 1 4485977604321908752
board_gen 42 2 2024629813010603131
board_gen 42 3 8849696722413293638
reward_roll 42 0 7422916049646135537
encounter 42 0 1061841193803499209
  • Example:同流同 scope 重复调用 derive_at 恒等(纯函数);同帧对同一流连续 open_stream 两次 → 计数器各 +1,得两个互异且顺序确定的种子。

RNG 生命周期与快照

  • RNG 生命周期:进程启动 → 流待命(未播种时取数即致命)→ 冒险开始设定 master_seed → 每次具名 scope 事件派生种子 → 冒险结束保留供复盘。
  • 快照 = master_seed + 各流 scope 计数器(仅记录计数器、缺 master_seed 不足以恢复序列——进程重启会从种子序列起点重放;见 D3 接口)。
  • 快照切出须发生在无在飞 open_stream 实例时(scope 事件边界之外):门面实例作用域限定于单次 scope 事件、消费者不得跨事件持有——在飞实例的内部取数进度不入快照,违反则续玩/复盘与实况分叉(AC-15 失效),该前提由 D3 消费侧遵守。

难度行解析(R1 difficulty_row_resolution)

结论:resolve 恒返回已有行——进度键 floor 解析、实体键精确匹配;不存在 default 行兜底、不存在 clamp 外推;非精确命中记 warning(四元组去重);请求越域在解析前置守卫致命。Output Range:行资源必有值(前置条件由校验保证);极端输入(超表大关卡号)命中最大已有行。

row = resolve(table, level_index, node_depth)   (ConfigDB 公开解析方法,table 经类型化属性取得)
前置守卫:level_index < 1 ∨ node_depth < 0 → 规则 6 致命(请求越域,不进解析)
L* = max{ lv ∈ LevelKeys(table) | lv ≤ level_index };空集(请求低于表最小键,向上解析)→ L* = min LevelKeys(table)
D* = max{ dp ∈ DepthKeys(L*) | dp ≤ node_depth };空集 → D* = min DepthKeys(L*)

Variables:

变量 类型 范围 说明
level_index int ≥1 当前关卡序号(1 起);越域 → 致命
node_depth int ≥0 节点深度(0=关卡入口);越域 → 致命
L* / D* int 表内键 命中行键
  • 无兜底 / 无外推的前置:表非空、每个 level 至少 1 行、每个 level 含 depth-0 锚行是规则 6 校验前置;超表成长外推是 C3 owner 公式的职责,D2 只解析到最近已有行。
  • warning 定位为开发期异常信号(防刷屏去重是刻意的),不是难度审计工具——离线审计由曲线导出工具承担(headless 脚本导出 resolve(level 1..N × depth 0..M) 矩阵供 diff,登记为 C3 期交付物)。
  • Example:表含行 (1,0)(1,4)(2,0)(2,6)——resolve(3,3) → L*=2、D*=0 → 返回 (2,0) 行,warning 一条(missing_type=both);resolve(1,4) → 精确命中零 warning;resolve(99,99) → 命中 (2,6),missing_type=both(与前者去重键不同,各自一条)。
  • 去重键 = (table_id, missing_type, L*, D*) 四元组,内容含请求 (level_index, node_depth)、解析结果 (L*, D*)、缺失类型;去重注册表随每次 load_tables() 或 reset_diagnostics() 清空。

missing_type(R1 warning 分类枚举)

值 判定
base_ceil level 分量向上解析(请求低于表最小键)——恒记 base_ceil(depth 分量缺失与否只写入 warning 内容,不改类型)
level_floor / depth_floor 单维向下解析
both level_floor 与 depth_floor 同时发生
  • depth 分量只有精确命中或向下 floor 两种情形(EC15 锚行保证每个 level 含 depth-0,永不 ceil);AC-5 各用例的 missing_type 均由本规则推导。

设计意图:解析永不发明数据——floor 到已有行并留 warning,外推归 C3 owner 公式。

依赖与输出

上游(hard):无——Foundation 层,D2 不依赖任何系统;master_seed 由 C2 冒险开始时设定。

方向 系统 性质 接口要点
下游 全部其他 19 系统 hard(规则 1) ConfigDB 类型化读取;禁止其他取数路径(A2 经 A3 表间接承载参数)
下游 A1 hard BoardGenTable 回填(首个进度键表)+ VariationTable schema(biome/tag 字段)+ board_gen 流(换图时取号)
下游 A3 hard ActionEconomyTable schema 回填
下游 A4 hard VariationTable 回填
下游 B2 hard EnemyTable 回填(十字段 + 三敌种行 + 每行集恰一敌种校验)+ HeroTable 新增(接口漂移回写)
下游 B3 hard StatusEffectTable 回填
下游 B4 hard RewardTable 回填(九字段 + 跨字段校验族 + 默认根行集,use_timing 承重 MVP 单值)+ RewardConfigTable 新增(单行全局)+ reward_roll 流(scope = 每次 board install 批——格奖励批 + 清图奖励批,B4 规则 2 接口漂移)
下游 B1 hard SettlementTable 回填(可回放步骤流的数据前提)+ debug 热重载门标志 set_reload_gate()(战斗开始置位 / 结束复位,仅 debug 构建)+ encounter 流(战斗实例化期取号恰一 scope——unit_count 区间骰,C3 遭遇随机化批增流)
下游 C2 / C3 hard RngService.set_master_seed() + DifficultyTable 行解析 + 曲线导出工具交付物
下游 D3 hard SCHEMA_VERSION + 存档内 master_seed + 各流 scope 计数器快照(续玩/复盘;含只读计数器接口,快照须在无在飞实例时切出)
下游 A5 / C4 hard(垂直切片 / Alpha) AuxItemTable 回填(A5 定稿登记——原 HelperItemTable 占位更名转正;counter_item_ids 表值回填与悬空校验激活随 D2×② 对侧批)/ MetaTable 回填
下游 D1 / D4 / D5 / D6 soft 如需参数表再增 schema(现无占位);display_name 本地化归 D6
外发 —— —— 不订阅任何玩法事件;仅 debug 构建发 config_reloaded(D1 调试用)
  • 数据读取类事实依赖不逐条列边(完整清单以本表为准);A2 无直接依赖(只外发事件,参数经 A3 表承载),与 systems-index 的 A2 回边规则一致。
  • 接口漂移修订规则:owner GDD 定稿时可修改占位 schema 类(schema 与表同仓),但必须回写本 GDD 表清单与 design/registry/entities.yaml,并在本文件版本历史登记修订;回执登记粒度 = 受影响字段/枚举/流——逐表 diff schema 目录(schema 目录 + 逐表字段行 + MVP 内容行 + 依赖表),禁按"对侧 GDD"粒度整批登记;占位参考值定稿时必须删除本 GDD 调参表清单中的对应条目(值的事实登记归 owner GDD 与 registry)。
  • 双向一致性已与 systems-index 依赖分层表核对一致(核对明细见 analysis 附录);已知待定:C3 是否消费 B1 输出——见索引门禁增补记录,归 C3 GDD 定稿,不影响 D2。

登记与对账义务(在案项——已闭环项见 analysis 附录)

编号 内容 对侧 状态
4 counter_item_ids 悬空引用(D2 首个引用型字段)——MVP 不校验,首个道具 id 回填时补校验 + 条件性夹具 A5 条件性(未激活)
5 EnemyTable MVP 行值(goblin 18HP / 4ATK 等)溯源补登(原型 REPORT,出处待查) B2 / C3 待补
6 HeroTable max_hp MVP 值溯源补登(出处待查) B2 / C3 待补
7 胜场成长机制去留(+25% HP / +1 ATK——反雪球问题) C3 待裁决
8 曲线导出工具(headless 导出 resolve 矩阵供 diff)——R1 审计的离线载体 C3 C3 期交付物(排期倒挂注意见 analysis 开放问题 #5)
9 规则 5 对全项目玩法代码的随机扫描 Technical Setup 项目级 CI 项
10 release 构建致命表现验证(引擎默认错误路径实际行为) 首次 release 导出 deferred(AC-18 checklist)
11 战斗级可回放集成测试(同 master_seed 同动作序列 → 步骤流逐行相同) B1 deferred(AC-15)

P0 最小闭环

  1. D2 交付全部 schema 类与占位表(含键结构)——先有格子。
  2. owner 系统 GDD 按设计顺序回填数值(十张已定稿 + 两张占位)。
  3. 进程启动:ConfigDB.load_tables() 逐一加载 + schema validate(),经校验双通道。
  4. 全部通过 → Ready:19 系统经类型化属性读数,无第二取数路径。
  5. C2 冒险开始 set_master_seed();三条封闭流按各自 scope 事件取号。
  6. debug 构建热重载即改即验(战斗中被门拒绝,结束后手动再触发)。
  7. godot --headless --script 冒烟 quit(0)——加载、校验、取数、派生全链路绿。

P1 / P2 后置

优先级 内容 后置原因
P1 战斗级可回放集成测试(同 master_seed 同动作序列 → 步骤流逐行相同,AC-15) D2 阶段无战斗载体,deferred→B1
P1 难度曲线导出工具(headless 导出 resolve 矩阵供 diff——R1 审计的离线载体) C3 期交付物;排期倒挂见 analysis 开放问题 #5
P2 release 构建致命表现 + override 结构不存在验证(AC-18) deferred→首次 release 导出 checklist
P2 进度键表 override 行寻址语法(如 difficulty.(2,0).hp) v1 仅支持单行全局表字段,登记为后续扩展
P2 编辑器内表文件热重载自动化 低优先、未指派(analysis 开放问题 #2)
P2 gdUnit4 引入与冒烟用例迁移 Technical Setup 阶段裁决(analysis 开放问题 #1)

呈现与 UI 面

项 要点
玩家 UI 无——MVP 无面向玩家的 UI;debug override 与夹具注入均经 Godot 编辑器 / 命令行参数设置(--data-root=,仅 debug),不做自定义面板
校验失败呈现 editor / CI 输出控制台(错误清单格式见 AC-1);release 构建走引擎默认错误路径(实际表现验证 deferred→首次导出 checklist)
开发侧可视化 Godot 编辑器 Resource inspector(自带)+ 校验错误控制台输出
音频 无需求(纯数据层,无直接表现面)

调参表

D2 自身 knobs(元参数)

Knob 默认 调过高 调过低
floor 解析策略 floor + warning(无外推) —— 引入外推/静默会掩盖 C3 难度断档
rng_stream_names 封闭 3 流(board_gen / reward_roll / encounter) 增流需改代码 + P1 评审(有意设卡) 流复用破坏可复现隔离
debug_override_enabled false(仅 debug 构建) 污染测试基线 ——
表路径清单 data/tables/ 固定(debug 注入根除外) —— 散装路径破坏单点访问
depth-0 锚行校验 写死开(非 knob,规则 6) —— ——(重议须走本 GDD 显式修订,EC15)
  • Knob 交互:floor 策略与 C3 的难度语义共享,改动需 C3 GDD 知情;校验严格度不设 knob(fatal 写死——放行带病数值会使 CI 冒烟失去意义)。
  • 未决占位与溯源义务(provisional——owner 定稿前不视为平衡事实;定稿后删除对应条目,值的事实登记归 owner GDD 与 registry):EnemyTable 行值溯源(义务 #5)· HeroTable max_hp 溯源(义务 #6)· 胜场成长机制去留(义务 #7)——见登记与对账义务表;已定稿占位参考值(标中旗 / 清图奖励 / 状态四行 / 奖励池等)已随各 owner 定稿清退出本清单。

表 schema 逐表字段行(D2 核心资产——字段全集以各 owner GDD Schema 节与 registry 为准)

ActionEconomyTable(单行全局 · A3 回填 ✓)

字段 knob 说明
ap_per_round ✓ 每轮行动点
dig_ap_cost ✓ 挖掘成本
flag_place_ap_cost ✓ 插旗成本
flag_pull_ap_cost ✓ 拔旗成本
rap_refresh_cost ✓ RAP 刷新门槛
move_ap_cost ✗ 冻结 移动成本
chain_ap_cost ✗ 冻结 连锁展开成本
跨字段校验 — 任一动作成本 ≤ ap_per_round(违规加载期致命,条件性夹具登记)

VariationTable(按 variant_id · A4 回填 ✓)

字段 类型 / 域 knob 说明
variant_id String 主键唯一 — 行键
display_name String — 本地化归 D6
unlock_level int [1,999] ✓ 进度语义承载列(规则 4 豁免载体)
scope region / global — global 预留 C3
info_mask none / hide_numbers — 雾行 = hide_numbers
cell_constraint any / safe_nonzero — 雾行 = safe_nonzero
biome_tag StringList ✓ ∅=通配
counter_item_ids StringList ✗ A5 预留;悬空引用政策见目录表
承重规则 — — 生成期布置约束:雾区仅非 0 安全格(区内无雷无 0 格,A1 生成期强制)+ 零特判原则

StatusEffectTable(按 effect_id · B3 回填 ✓)

字段 类型 / 域 说明
effect_id String 主键唯一 行键;引用校验已激活
display_name String 本地化归 D6
target_side hero / enemy 作用侧
magnitude percent ∈ [-100,100] ∧ ≠0 / flat ≥ 1 跨字段校验
unit percent / flat 量纲
duration_settlements [1,99] 持续结算次数
stack_policy stack / refresh / independent 叠层策略
max_stack [1,16] 仅 stack 消费

BoardGenTable((level_index, node_depth) 首个进度键表 · A1 回填 ✓)

字段 类型 / 域 knob 说明
board_width / board_height int [8,64] ✓ 板尺寸
mine_density float (0,0.5] ✓ 密度浮点(尺寸解耦);布雷数下限 round(d×(W×H−9)) ≥ 1
inferability_target float [0.85,1] ✓ P1 门槛承重参数 + 绝对锚
solver_rules single / single_subset ✗ 冻结 single_subset 推理定义域非调参
min_safe_count int [1,999] ✓ 退化板对冲
max_gen_attempts int [1,32] ✓ 生成-验证循环上限
fog_region_count int [0,32] ✓ 雾区数
fog_target_ratio float [0,1) ✓ ≤ min(8d, 0.25) 绝对上限
board_biome StringSet 非空 — 域校验致命(词表 owner 未定稿前只校验非空)
elite_ / boss_ 前缀 命名空间预留 ✗ 第三轴登记约定——语义归 C1/C3,本 GDD 不定义
跨字段谓词 — — fog_domain_ok(F2)+ min_safe_feasible(F2b)+ cost_feasible(F2c:attempts×W×H ≤ 16384 provisional,运行期禁墙钟逃生)——加载期致命

EnemyTable((level_index, node_depth, enemy_id) · B2 回填 ✓)

字段 类型 / 域 knob 说明
enemy_id String(行集内主键) — 行集内唯一(每行集恰一敌种)
display_name String — 本地化归 D6
unit_count int [1,3] ✓ 遭遇区间下界(C3 修订批——区间 [unit_count, unit_count_max] 经 B1 encounter 骰定本战实际数量;新敌种首遇节点固定不加骰)
unit_count_max int [unit_count,3],可省略 ✓ 遭遇区间上界(缺省 = 定值,旧行零迁移——C3 修订批新增字段)
armor_type enum {none, a, b},缺省 none ✓ 护甲类型(克制矩阵 = SettlementTable.armor_effectiveness;MVP 映射 goblin=none / bugbear=a / ogre_chief=b——护甲克制批)
hp int [1,999] ✓ 难度修饰前基线
atk int [0,999] ✓ attack 行为伤害基值;0 = 纯伏击伤敌种合法
heavy_multiplier int [1,16] ✓ 无 heavy 拍敌种不消费(非校验项先例)
pattern StringList,环长 [1,8] — MVP 校验域 {attack, charge, heavy}——guard/boost/hinder/summon 预留值校验拒绝
advantage_per_round_cap int [0,16] ✓ 默认 4 定稿(反灾难护栏);0 = 免疫伏击合法极端

HeroTable(单行全局 · B2 回填 ✓ · 接口漂移新增)

字段 类型 / 域 knob 说明
max_hp int [1,999] ✓ MVP 值 provisional(出处待查)
atk int [1,999] — 0 = 加载拒绝(基础攻击恒存在,"0 基线 × 百分比增益恒零"死锁自 schema 层杜绝);MVP = 6 原型锚 provisional 归 C3;消费面 = 主角战斗段先手攻击

RewardTable(按 reward_id · B4 回填 ✓)

字段 类型 / 域 knob 说明
reward_id String 主键 — 行键(多行;pool_tag 分池不参与键)
category buff / damage_item / heal_pack / instant_aoe / instant_heal — 两类交付轴:即时类 {buff, instant_aoe, instant_heal} 当场兑付不进库存 / 可选类 {damage_item, heal_pack} 入关卡域库存;预留值校验拒绝
effect_id String 可空 — buff 类必填(StatusEffectTable 精确引用);非 buff 恒空
display_name String 非空 — D1 呈现数据源,本地化归 D6(B2/B3 同库惯例)
power int [0,999] ✓ item 类加载校验 ≥1;buff 类不消费非校验
weight int [0,999] ✓ 0 = 不入池
pool_tag safe_cell / active_inject / clear_default — clear_<biome> 命名空间预留拒绝;active_inject = 供给控制器注入池(可选类三行——install 期注入,非逐格 roll)
tier int [1,8] ✓ A4 雾档约束载体
use_timing pre_settlement(MVP 单值) — 承重——道具使用窗口 MVP 激活,扩枚举走修订

RewardConfigTable(单行全局 · B4 回填 ✓ · 接口漂移新增)

字段 类型 / 域 默认 说明
t_fog_min int [1,8] 2 F2 雾档过滤门限
k_dmg int [0,999] 0 0 = F5 断言关闭(现行默认——刀保底语义由供给控制器战斗首件保证取代;no_damage_row 后闸托底)
active_p0 float [0,1] 0.4 供给控制器注入概率初值(首件之后每张新板)——E[战斗获取] ≈ 1 标定目标,归 C3
active_decay float (0,1] 0.5 注入概率指数递减 0.4→0.2→0.1→…(加难杠杆候选 0.6 随 C3 OQ7 扫描)
n_draft int [1,999] 32 F5 草稿重 roll 上限
p_min int [1,999] 8 默认根最低刀 power——K≥1 供给闸刀力下界(floor_supply_missing)

SettlementTable(单行全局 · B1 回填 ✓ · 共十二字段)

字段 类型 / 域 默认 knob 说明
equivalence_ref_damage(D_ref) int [1,999] 12 ✓ 当量参考敞口;变更触发 B1 全对照表 + 条款③⑤对账重跑(禁独立调参)
p_perfect percent {100,200} 200 ✓ 完美排雷清图奖励第二份兑付触发——非整数倍数乘数无运行时载体,域外加载致命
segment_order StringList 拍板段序 ✗ 结构冻结 恒等拍板段序校验,违例致命(防实现乱序静默漂移)
source_label_map Dictionary source_class→文案键 封闭枚举全覆盖 ✗ 结构冻结 P2 归因呈现映射;键集 = B3 source_class ∪ {道具/判定扩展, enemy_action, flag_miss, hero_attack};新增键 = 接口漂移
effect_pool_map Dictionary effect_id→{hero_offense, hero_defense, enemy_output, flat_attach} 四键定稿映射 ✗ 结构冻结 效果语义映射;键 ⊆ StatusEffectTable 活行集,悬空加载期致命;新 effect_id 上线须随批登记
pool_clamp_lo int pp −100 ✗ 结构冻结 percent 池地板域下界(乘数域随之 [0,2])
pool_clamp_hi int pp +100 ✗ 结构冻结 percent 池地板域上界
round_direction enum {floor} floor ✗ 结构冻结 单一取整规则
damage_a_per_cell int ≥ 0 1 ✓ 伤害A 开格充能/格(护甲克制批——充能与结算归 B1 战斗段〔F6〕,C3 投值)
damage_a_cap int ≥ 0 8 ✓ 伤害A 单轮充能封顶(0 = 不封顶——防连锁轮失控)
damage_b_per_flag int ≥ 0 2 ✓ 伤害B 标雷充能/首次标中雷(每雷实例一次去重)
armor_effectiveness Dictionary {base, dmg_a, dmg_b} × {none, a, b} 特化 ×150 / 无甲 ×100 / 对位 ×50 键集 ✗ 结构冻结 / 数值 ✓ 伤害类型 × 护甲克制矩阵——主角攻击三分量(基础/伤害A/伤害B)各自查表后 floor 相加;敌种甲型映射归 EnemyTable.armor_type

验收标准

测试口径

口径 要点
测试载体 --headless --script 冒烟框架(脚本 extends SceneTree 以获得 quit(code);该模式 autoload 须由脚本显式实例化——AC-1 前提声明;设计顺序 #1 时无主场景可依赖)
覆盖 8/8 Core Rules;规则 6 加载期校验错误类别全部有夹具(悬空引用为条件性夹具,已随 B4 首引激活);运行期致命(请求越域 EC14、未播种 EC7)由 AC-5b / AC-17 行为级覆盖;R1 / R2 全部边界
致命类断言协议 致命用例(AC-2b、AC-5b 游戏通道半、AC-6 后半、AC-11、AC-17)各为独立进程调用,冒烟 runner 清单逐条登记"调用 → 期望退出码";单进程内只做测试通道收集断言
warning 断言 一律经诊断收集器(见校验双通道),每用例先 reset_diagnostics()
人工与延迟 AC-14 人工 · AC-15 deferred→B1 · AC-18 deferred→首次 release 导出

AC 清单(Given-When-Then,编号不变)

AC Given When Then 覆盖
AC-1 干净检出 godot --headless --script tests/smoke_data.gd 核心规则 #3 表清单的全部表(以清单为准,不写死数量)加载且 data/tables/ 无清单外 .tres;脚本成功 quit(0),任一失败 quit(1) 并输出错误清单(表路径 + 字段 + 错误类别) 规则 3/6
AC-2 tests/fixtures/ 夹具集(越界字段 / 文件缺失 / 空表 / 某 level 无行 / 缺 depth-0 锚行 / 重复键 / 权重和 ≤0 各一;悬空引用为条件性夹具——已随 B4 首引激活) 冒烟脚本经 --data-root 注入逐夹具运行 load_tables(root, collect_only=true)(测试通道,单进程逐个断言) 每个夹具的错误清单含对应类别(EC1 / EC2 / EC3 / EC15 / EC10 及重复键类别) 规则 6 / EC
AC-2b 任一致命夹具经注入根加载 冒烟 runner 以独立 headless 进程执行游戏通道 load_tables(root, collect_only=false)(--script 协议,脚本显式实例化 autoload;不依赖主场景) 进程非 0 退出且错误清单完整——验证"游戏内真的会死"而非仅"校验器能发现" 规则 6 游戏通道
AC-3 R2 黄金向量表(6 常量) 纯函数 derive_at 复算(board_gen master=42 scope 0–3、reward_roll master=42 scope=0、encounter master=42 scope=0);同流同 scope 重复调用 逐个等于向量表常量;重复调用恒等(纯函数无副作用) R2
AC-4 master_seed=42 open_stream("board_gen") 连续取号 ≥100 次(跨模拟"关卡切换");同期调用任意 reload() 公开只读计数器单调不重置(各关同序号图种子互异);计数器不变(状态线独立) R2 / 规则 5 / 状态机表
AC-5 真实 DifficultyTable schema 构造的表含行 (1,0)(1,4)(2,0)(2,6)(每用例先 reset_diagnostics()) 依次 resolve(3,3) → resolve(3,4) → resolve(1,4) → resolve(99,99);单行表 {(2,0)} 上 resolve(1,5) (3,3):返回 (2,0) 行且诊断收集器 warning 恰一条(missing_type=both,含请求/结果/类型);(3,4):warning 不新增(四元组去重键相同);(1,4):精确命中且零 warning;(99,99):命中 (2,6) 且新增恰一条(去重键含 D*,与首条不同);单行表:命中 (2,0) 且 missing_type=base_ceil(由 R1 分类规则推导:level 分量向上解析恒记 base_ceil) R1
AC-5b 真实 DifficultyTable schema 构造的合法表 resolve(0, 3)(level_index < 1)与 resolve(2, -1)(node_depth < 0);同用例经游戏通道独立进程复跑 测试通道诊断清单各含"请求越域"致命类别一条且不进入解析(EC14 / R1 前置守卫);独立进程非 0 退出 R1 / EC14
AC-6 master_seed=-7;master_seed=INT64_MIN;derive_at 传入负 scope set_master_seed();set_master_seed();derive_at 归一化为 7 + 诊断收集器 warning 一条,后续种子 ∈ [0, 2^63)(EC6);INT64_MIN 致命(非 warning;独立进程断言退出码非 0);负 scope debug 断言中止(负值经输出掩码与 scope+2^63 别名) R2 / EC6
AC-7 debug 构建 override{"action_economy.ap_per_round"=12}(域内值——A3 schema 域 [1,32];越域 override 会被 R3③ 忽略,出域示例会使本 AC 假失败) 经 ConfigDB 读取;override key 为未知路径、类型或范围与 schema 不符;reload() 后 effective=12;诊断收集器 warning + 忽略该条;.tres 文件内容不变(R3 边界①③⑤) R3
AC-8 非 debug 谓词模拟(feature 标签) _has_override(key) 恒 false——本条仅证明门存在性;"release 不加载 override 源"的结构保证验证 deferred→首次 release 导出 checklist R3④
AC-9 D2 文件集(data/schemas、ConfigDB、RngService、tests) 静态扫描(模式覆盖 load(、preload(、ResourceLoader.load、"res://data/" + 动态拼接;res://tests/fixtures/ 前缀豁免——不在 res://data/ 扫描域) 无 randomize() 调用、无 ConfigDB 之外的 data 表加载(规则 2/5);规则 5 对全项目玩法代码的扫描登记为项目级 CI 项(义务 #9) 规则 2/5
AC-10 D2 文件集 静态扫描 + AC-1 headless 实跑 无 extends Control/Node2D、无 .tscn preload,且 AC-1 headless 实跑通过——两项合成判定规则 7(扫描是启发式,硬证据是 headless 实跑) 规则 7
AC-11 RngService(debug 构建) 请求未知名流或重复注册流名 debug 断言中止(EC12;独立进程退出码非 0) 规则 5 / EC12
AC-12 同帧对同一流 连续两次 open_stream 两个互异且顺序确定的种子(EC13) 规则 5 / EC13
AC-13 冒烟脚本运行 反射断言 SCHEMA_VERSION 常量存在且 ConfigDB 可读;全部 schema 携带版本字段;进度类表(BoardGen/Enemy/Difficulty)暴露 (level_index, node_depth[, enemy_id]) 键字段;DifficultyTable schema 暴露 elite_ / boss_ 前缀预留字段("高版本拒读"路径 deferred→D3) 规则 8 + 规则 4 键契约 + 第三维命名空间
AC-14(人工) 每次回填定稿 验收人复核 规则 1 数值字面量禁令成立:启发式扫描(warning 级,误报难免)+ 人工复核三要素——验收人 = owner GDD 回填定稿评审 + 里程碑 gate-check;时机 = 每次回填定稿;证据 = 评审记录 / gate-check 登记 规则 1
AC-15(deferred→B1) 同 master_seed 同动作序列 B1 集成测试重放 结算步骤流逐行相同(D2 阶段无战斗载体) 规则 5 可回放
AC-16 debug 构建且 B1 侧经 set_reload_gate(true) 置位(模拟战斗中);门未置位;reload 后新表校验失败 reload() 置位:返回 false、ConfigDB 值不变、不发 config_reloaded;未置位:返回 true 且新值经类型化属性可读且 config_reloaded 发出恰一次(仅 debug 构建);校验失败:旧表保留、状态停留 Ready(EC16) 状态机表 / EC16 / 规则 6
AC-17 未设 master_seed open_stream 或 derive_at push_error + 冒烟通道断言中止路径(quit 非 0)(EC7) 规则 6 / EC7
AC-18(deferred→首次 release 导出) release 模板构建 致命校验错误发生;查找 override 源 表现符合"引擎默认错误路径"预期;override 结构性不存在(R3 边界④、校验双通道 release 侧) 规则 6 / R3④

版本历史

版本 日期 改动
v2 2026-09-14 两件套格式迁移:按模板 v2 骨架重排——头部收敛为状态/版本/一句话/推演件指针;设计推演(公式推导论证、数值锚定论证、候选取舍、体验锚点论证、已裁决争议)移至 design/gdd/analysis/d2-data-config.md;评审元数据与已闭环对账义务(#1/#2/#3/#12)入 analysis 附录;规则、数值、枚举、EC、AC、OQ 编号与内容零变更
跨评审 D2 漂移批 2026-09-14 /review-all-gdds 🔴-2 五处补漂移修订批(X-8 遗漏项补登,registry 同批):RNG 流封闭清单 2→3 流(encounter——消费者 B1,scope = 每场战斗实例化恰一 scope;Core Rule 5 / 取数链路 / 盐值 0x8EBC6AF09C88C6E3 / 黄金向量 +1 常量〔AC-3 五→六〕/ set_master_seed 全流零计数前提)· pool_tag 枚举增 active_inject · RewardConfigTable +2 字段(active_p0=0.4 / active_decay=0.5)+ k_dmg 默认 1→0 且"C3 禁区默认值"条款解除 · 默认根行集 clear_knife→clear_blast(注入池占比注记替代 75/25)· HelperItemTable 更名 AuxItemTable(A5 定稿转正,schema 目录九→十张)· X-8 补登:SettlementTable 逐表字段行补 4 字段(共十二字段)、EnemyTable MVP 行三敌种登记 · 接口漂移修订规则增"回执按受影响字段/枚举粒度逐表 diff schema 目录"流程纪律;核心规则表增依据列(lint R8 引用列迁移)
C3 修订批回写 2026-09-14 /design-review C3 修订批(X-8 回执,registry 同批):EnemyTable schema +2 字段(unit_count_max——遭遇区间上界 / armor_type——护甲类型枚举 {none,a,b},克制矩阵挂 SettlementTable)· SettlementTable +4 字段(damage_a_per_cell=1 / damage_a_cap=8 / damage_b_per_flag=2 / armor_effectiveness 克制矩阵——护甲克制批转正,机制与结算归 B1、C3 投值)· DifficultyTable 表清单行补乘数域与 clamp 例外注记(registry 登记的组合事故例外,非 fail-fast 场景)· 敌种键更名 goblin/bugbear/ogre_chief(DND 批对齐)
v1.0-lean 2026-09-13 格式迁移:legacy 原稿按 lean 样例重排——修订注记出正文收敛至本表;核心规则 / 枚举 / 边界 / AC 转表格;加载校验与热重载链路转字符画;九张表 schema 逐表字段行入 Tuning Knobs;义务与夹具登记收敛为登记与对账义务表。正文残留旧称按 registry 与各 owner 成稿写现行值:SettlementTable 八字段口径(pool_clamp 拆 lo/hi)、p_perfect 载体域 {100,200}、source_label_map 键集含 hero_attack、RewardTable category 五值与默认根八行集——语义零变更
两级奖励批 + 基础攻击裁决 2026-09-11 RewardTable category 三值扩为五值(即时 / 可选两类交付轴)+ 默认根行集重登记八行(原五行为集退役);RewardConfigTable p_min 默认 4→8;HeroTable atk 改域 [1,999] 且 0 = 加载拒绝(基础攻击恒存在),消费面 = 主角战斗段先手攻击
B1 回填 + 评审批收编 2026-09-10 SettlementTable 定稿回填(registry 原记七字段);同日评审批统一八字段口径——pool_clamp_lo_hi 拆 lo/hi 两字段、p_perfect 域 [100,999] 改载体域 {100,200}、source_label_map 键集补 enemy_action / flag_miss(hero_attack 随 B1 成稿)
B4 full 评审 delta 2026-09-09 RewardTable 增 display_name(九字段)+ 默认根行集登记 + RewardConfigTable 新增(单行全局四字段,接口漂移——B4 标量 knob 的 Rule 1 载体)+ Core Rule 5 reward_roll 语义正文补同步(每次 board install 批)
B4 回填定稿 2026-09-09 RewardTable 八字段 + 跨字段校验族 + use_timing 占位转承重 + 首个 effect_id 引用回填激活 StatusEffectTable 悬空校验 + reward_roll scope 语义改写 + Tuning Knobs 奖励池占位条目清退
B2 回填定稿 2026-09-09 EnemyTable 八字段 + 双敌种行 + 每行集恰一敌种校验;HeroTable 新增(接口漂移回写)
A1 full 评审 delta 2026-09-09 BoardGenTable inferability_target 收窄 [0.85,1](P1 绝对锚)+ fog_target_ratio 绝对上限 min(8d, 0.25) + 布雷数下限 round(d×(W×H−9)) ≥ 1 + F2c 成本谓词(运行期禁墙钟逃生)+ elite_/boss_ 命名空间预留(第三轴登记约定,Boss=Dmax 行 + A1 OQ6 重审门)
A1 回填定稿 2026-09-09 BoardGenTable 九字段 + F2/F2b 跨字段谓词 + solver_rules 冻结 + MVP 参考行(provisional,C3 调参所有权)——首个进度键表
B3 回填定稿 2026-09-08 StatusEffectTable schema 八字段 + 四行 MVP 内容(键 = effect_id,Rule 4 豁免注明;effect_id 悬空校验待首引激活)
A4 re-review delta 2026-09-08 VariationTable 增跨字段校验 hide_numbers⇒safe_nonzero(加载期致命,夹具 variation_mask_constraint)+ counter_item_ids knob 误标修正(非 knob)
A4 回填定稿 2026-09-08 VariationTable 八字段 + fog 行 + Rule 4 豁免注明(registry 新条目 variation_table / variant_pool_gate)
A3 三轮评审 delta 2026-09-07 ActionEconomyTable 增跨字段 validate 规则(任一动作成本 ≤ ap_per_round,schema 类承载、违规致命、条件性夹具登记)
A3 RAP 结构修订 2026-09-07 flags_per_round / flag_unit_cost / stop_multiplier / clear_multiplier 四字段删除(旗无上限、停手 / 清图折算乘数退役)、rap_refresh_cost 新增;AC-7 示例值域内修正(99 出域会使本 AC 假失败)
A3 回填定稿 2026-09-07 ActionEconomyTable 字段清单交付 + 成本三字段入表 + 冻结字段(ap_per_round=8 等定稿值登记 registry)
收口 2026-09-07 两轮评审 + delta 复核 5/5 PASS 后 Approved;CD-GDD-ALIGN 终裁 NEEDS REVISION → 修订落实 → 独立 delta 核对通过
原型占位值清退 2026-09-07 起随各 owner 定稿 标中旗 +5 / 面旗(量纲与语义经 A3 OQ5 重锚 → weaken 行)、清图 +10(→ B4 清图奖励插槽)、增伤 1.5× / 减伤 0.5× / 持续 2 次结算(→ StatusEffectTable 四行)、奖励池 5 类(→ RewardTable 五值)——机制与数值事实登记归 owner GDD 与 registry