# 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/archive/gdd-2026-09-14/d2-data-config.md(系统 ID D2·数据配置——registry 追溯锚) class_name ConfigDbResolver extends RefCounted var _db: ConfigDb # 门面引用(表读取 + 诊断/致命通道——_init 注入) var _warn_dedup: Dictionary[String, bool] = {} # R1 四元组去重注册表(自 ConfigDb 迁入) func _init(db_ref: ConfigDb) -> void: _db = db_ref # 去重注册表清空(门面 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(_db.board_gen.rows, L, D, "board_gen") func resolve_enemy_rowset(L: int, D: int) -> Dictionary: return _resolve_progress(_db.enemy.rows, L, D, "enemy") # 难度曲线与Boss DifficultyTable 消费面(敌人系统.spawn 调用):(L,D) 精确匹配修饰乘数,越域值 clamp(GDD Edge Case——组合事故非配置事故) func resolve_difficulty_modifiers(L: int, D: int) -> Dictionary: if _db.difficulty == null: return {} for row in _db.difficulty.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) -> Dictionary: if L < 1 or D < 0: _db._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(): _db._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 解析(向上取整保证偏难)" _db.push_diag("warning", "resolve_" + missing, "%s 请求 (%d,%d) %s → (%d,%d) [%s]——2026-09-18 拍板" % [table_id, L, D, verb, l_star, d_star, missing]) 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