Files
gplan-2/game/core/config_db_resolver.gd
T
DKChan eea345882b feat(迭代27 T6+T7): 波五b 卫生件包+文档同步闸——对拍全同
T6 卫生件(P2 组收口):
- 死代码 13 函数删除(审计 16 处复核=ui_kit:486 实读现役不删,追认单#14)+FeatsEngine
  整文件退役(class_name 注销)
- 字符串 Callable×10 位→方法引用形态(编译期方法存在性校验;语法实证 METHOD_REF=true)
- 状态机 enum 化: adventure State(外部 String 契约 getter 词表逐位一致+外部纯读实证)/
  standee HeroState(register/set String 形参零变化+probe 面恒等)
- ConfigDB _fatal 退出归根(核心层去 quit/crash→_fatal_flag,决策归组合根 fail-fast 通道)
  +resolver 诊断/数据通道全面 Callable 化(ConfigDb↔Resolver 类型环断根)

T7 文档同步闸:
- 实现报告 design/qa/iter27-实现报告-2026-10-14.md(五波+闸表+追认单十五项+反哺点两条+目检五件)
- 06 迭代 27 条销号+GDD 反哺点两条新条;07 ㉖ 目检节+v1.0 版本行;roadmap ✅ 换代
- 审计报告本体按退役规则 git rm(吸收即死;修正计数由卡片承载);卡片来源行改指路

闸: 对拍三变体全同(第五跑)+冒烟 1081/0+run_all 27 套+probe click+render golden+static_scan 全绿
2026-10-15 01:41:37 +08:00

128 lines
6.1 KiB
GDScript
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.
# VERTICAL SLICE - NOT FOR PRODUCTION
# Date: 2026-10-02(code-quality 修复批 T5——ConfigDb 拆分:R1 难度行解析协作类,自 config_db.gd 迁出)
# 职责单一化(R1 解析域):resolve_board_gen / resolve_enemy_rowset / resolve_difficulty_modifiers
# 及其私有算术(_resolve_progress / _ceil_key)与 R1 专属的告警去重注册表。ConfigDb autoload 门面
# 保持——全部消费方(战斗结算/敌人系统/棋盘生成/呈现层/冒烟)经门面同名方法取数,公有签名零变化。
# 诊断通道归门面:push_diag / _fatal 经 _db 引用回呼(协作类同仓内部通道——不另设公共出口,
# 行为与拆分前逐位一致,含越域 Fatal 退出语义)。
# 迁移注记:_warn_dedup 去重注册表随解析逻辑同迁(唯一消费方 = _resolve_progress)——
# 门面 load_tables / reset_diagnostics 经 reset_warn_dedup() 同步清空,清空时点零变化。
# 实现 GDD:design/gdd/systems/表现与支撑/数据配置.md(系统 ID D2·数据配置——registry 追溯锚)
class_name ConfigDbResolver
extends RefCounted
var _diag: Callable # 诊断/致命通道(迭代 27 T6——门面类型反持解耦,validator 先例:签名 (level, category, message))
var _reset_warn: Callable # 去重注册表清空通道(reset_diagnostics 时点由门面驱动)
var _board_gen_rows_get: Callable # () -> Array——board_gen 行集活读(数据面经 Callable 注入,ConfigDb 类型环断根)
var _enemy_rows_get: Callable # () -> Array——enemy 行集活读
var _difficulty_get: Callable # () -> DifficultyTable(可空——表缺省合法态)
var _warn_dedup: Dictionary[String, bool] = {} # R1 四元组去重注册表(自 ConfigDb 迁入)
func _init(diag_cb: Callable, reset_warn_cb: Callable, board_gen_rows_cb: Callable,
enemy_rows_cb: Callable, difficulty_cb: Callable) -> void:
_diag = diag_cb
_reset_warn = reset_warn_cb
_board_gen_rows_get = board_gen_rows_cb
_enemy_rows_get = enemy_rows_cb
_difficulty_get = difficulty_cb
# 去重注册表清空(门面 load_tables / reset_diagnostics 调用——与拆分前清空时点逐位一致)
func reset_warn_dedup() -> void:
_warn_dedup.clear()
# ---- R1 难度行解析(2026-09-18 用户拍板修订:ceil 向上取整保证偏难;域越界与内容缺口 Fatal 退出)----
func resolve_board_gen(L: int, D: int) -> Dictionary:
return _resolve_progress(_board_gen_rows_get.call(), L, D, "board_gen")
func resolve_enemy_rowset(L: int, D: int) -> Array[Dictionary]:
# 行集数组形态(2026-10-07 敌人表行集多行批——原单行 Dictionary 退役):ceil 命中 (l*,d*) 后
# 返回该坐标全部行、按表文件行序(行序即契约——同坐标多行文件内相邻由 EnemyTable.validate 兜底)。
# 空集表达 = 空数组(生产表下 ceil 命中坐标恒有行,空集仅表空时可达——validate 已拦)。
return _resolve_progress(_enemy_rows_get.call(), L, D, "enemy", true)
# 难度曲线与Boss DifficultyTable 消费面(敌人系统.spawn 调用):(L,D) 精确匹配修饰乘数,越域值 clamp(GDD Edge Case——组合事故非配置事故)
func resolve_difficulty_modifiers(L: int, D: int) -> Dictionary:
var dt = _difficulty_get.call()
if dt == null:
return {}
for row in dt.rows:
if int(row.get("level_index", 0)) == L and int(row.get("node_depth", -1)) == D:
return {
"hp_mult": clampf(float(row.get("hp_mult", 1.0)), 0.1, 10.0),
"atk_mult": clampf(float(row.get("atk_mult", 1.0)), 0.1, 10.0),
}
return {}
func _resolve_progress(rows: Array, L: int, D: int, table_id: String, return_all := false) -> Variant:
if L < 1 or D < 0:
_diag.call("fatal", "request_oob", "%s 请求越域 (%d,%d)——进度坐标低于合法域(关卡序号≥1、节点深度≥0)" % [table_id, L, D])
return {}
var level_keys: Array[int] = []
for row in rows:
var lv := int(row.get("level_index", 0))
if not level_keys.has(lv):
level_keys.append(lv)
if level_keys.is_empty():
_diag.call("fatal", "structural", "%s 行集为空——锚行校验应已拦截" % table_id)
return {}
level_keys.sort()
var l_star := _ceil_key(level_keys, L)
var l_clamped := l_star < 0
if l_clamped:
l_star = int(level_keys[-1]) # 超出最大行 → 取最大行封顶(2026-09-18 追加拍板:可取范围内向上取整,超出用最大值)
var depth_keys: Array[int] = []
for row in rows:
if int(row.get("level_index", 0)) == l_star:
var dv := int(row.get("node_depth", 0))
if not depth_keys.has(dv):
depth_keys.append(dv)
depth_keys.sort()
var d_star := _ceil_key(depth_keys, D)
var d_clamped := d_star < 0
if d_clamped:
d_star = int(depth_keys[-1])
var missing := ""
if l_clamped and d_clamped:
missing = "both_clamp"
elif l_clamped:
missing = "level_clamp"
elif d_clamped:
missing = "depth_clamp"
elif l_star != L and d_star != D:
missing = "both_ceil"
elif l_star != L:
missing = "level_ceil"
elif d_star != D:
missing = "depth_ceil"
if missing != "":
var dedup_key := "%s|%s|%d|%d" % [table_id, missing, l_star, d_star]
if not _warn_dedup.has(dedup_key):
_warn_dedup[dedup_key] = true
var verb := "clamp 解析(超出最大行取最大值)" if missing.contains("clamp") else "ceil 解析(向上取整保证偏难)"
_diag.call("warning", "resolve_" + missing, "%s 请求 (%d,%d) %s → (%d,%d) [%s]——2026-09-18 拍板" % [table_id, L, D, verb, l_star, d_star, missing])
if return_all:
var all_out: Array[Dictionary] = []
for row in rows:
if int(row.get("level_index", 0)) == l_star and int(row.get("node_depth", 0)) == d_star:
all_out.append(row)
return all_out
for row in rows:
if int(row.get("level_index", 0)) == l_star and int(row.get("node_depth", 0)) == d_star:
return row
return {}
# 取 sorted_keys 中第一个 >= request 的键;无(请求高于最大行)返回 -1 → 调用方 Fatal
func _ceil_key(sorted_keys: Array, request: int) -> int:
for k in sorted_keys:
if int(k) >= request:
return int(k)
return -1