## 存档内元进度数据件(D3 拆件——自 save_manager 收编元进度族):存档内元进度数据的读写唯一层。 ## 数据读写原语族(写口 13)+只读投影(读 6——tree/forge/attune/career 四域值拷贝出户); ## 业务规则与写口编排归 MetaProgression,本件只承载键域读写(照单承载,零业务判定)。 ## 零 _data 副本零缓存——全部读写经注入 save 的内存数据模型单点。 class_name MetaStateStore extends RefCounted var _save # SaveManagerCore 注入引用(_data 唯一取数点) func _init(save_ref) -> void: _save = save_ref # ---- 写口原语族(13)---- # 钥石消费唯一口:余额不足拒绝且零副作用(钥石只增不减——消费除外,元进度验收判据) func spend_keystone(n: int) -> bool: if keystone_balance() < n: return false _save._data["meta"]["keystone_balance"] = keystone_balance() - n return true func unlock_item(item_id: String) -> void: _save._data["meta"]["item_unlocks"][item_id] = true func set_tree_level(node_id: String, level: int) -> void: var tn: Dictionary[Variant, Variant] = _save._data["meta"].get("tree_nodes", {}) as Dictionary tn[node_id] = maxi(0, level) _save._data["meta"]["tree_nodes"] = tn func set_fork_side(group: String, side: String) -> void: var fs: Dictionary[Variant, Variant] = _save._data["meta"].get("fork_sides", {}) as Dictionary fs[group] = side _save._data["meta"]["fork_sides"] = fs func set_forge_route_level(route_id: String, level: int) -> void: var dom: Dictionary[Variant, Variant] = _forge_domain() var lv: Dictionary[Variant, Variant] = dom.get("levels", {}) as Dictionary lv[route_id] = maxi(0, level) dom["levels"] = lv _save._data["meta"]["forge_routes"] = dom func add_forge_unlock(route_id: String) -> void: var dom: Dictionary[Variant, Variant] = _forge_domain() var un: Array[Variant] = dom.get("unlocked", []) as Array if not un.has(route_id): un.append(route_id) dom["unlocked"] = un _save._data["meta"]["forge_routes"] = dom func set_forge_weapon(route_id: String) -> void: var dom: Dictionary[Variant, Variant] = _forge_domain() dom["weapon"] = route_id _save._data["meta"]["forge_routes"] = dom func set_forge_armor(route_id: String) -> void: var dom: Dictionary[Variant, Variant] = _forge_domain() dom["armor"] = route_id _save._data["meta"]["forge_routes"] = dom func set_attunement_equipped(item_ids: Array) -> void: var out: Array[Variant] = [] for v in item_ids: out.append(String(v)) _save._data["meta"]["attunement_equipped"] = out func set_attune_refresh_level(n: int) -> void: _save._data["meta"]["attune_refresh_level"] = maxi(0, n) # 真视类工具累计使用入账(写入唯一经本口冒险收束聚合,受理计数点=battle 层经冒险层聚合) func add_vision_used(n: int) -> void: _save._data["meta"]["vision_used"] = maxi(0, career_state()["vision_used"] + maxi(0, n)) # 域更新原语(正式冒险收束唯一入账口——组合根经本函数入账,禁直改内部结构): # 钥石入账(summary.keystone_total——逐杀掉落已在冒险内计入,boss_drops 参数为 # 摘要归档副本不重复入账)+ 逐关卡完成关次 clear_count +1 与 Boss 首杀标记 + Boss 击杀总数累计 # (同调位里程碑计数源)+ 摘要头部插入(cap 10,最新在前,元素附 # keystone_drops 副本——复盘可归因)+ 生涯终身计数自增(总局数开局即计: # 三结局同经本口恰计一次;冒险成功局数按 summary.cleared 判定三关全通才计 1。终身计数写入 # 单口=本函数,禁第二写入点)。 func apply_adventure_summary(summary: Dictionary, boss_drops: Array = []) -> void: _save._data["meta"]["adventure_total"] = career_state()["adventure_total"] + 1 if bool(summary.get("cleared", false)): _save._data["meta"]["adventure_cleared"] = career_state()["adventure_cleared"] + 1 _add_keystone(int(summary.get("keystone_total", 0))) var cleared := int(summary.get("levels_cleared", 0)) for li in range(1, cleared + 1): var key := str(li) _save._data["meta"]["level_clear_counts"][key] = int(_save._data["meta"]["level_clear_counts"].get(key, 0)) + 1 _save._data["meta"]["boss_first_kill"][key] = true _save._data["meta"]["boss_kill_count"] = career_state()["boss_kill_count"] + cleared # Boss 恒唯一终点:levels_cleared 即本次冒险 Boss 击杀数(含重复) var entry: Dictionary[Variant, Variant] = summary.duplicate(true) entry["boss_drops"] = boss_drops.duplicate(true) var arr: Array[Variant] = _save._data["meta"]["recent_summaries"] arr.push_front(entry) while arr.size() > _save.SUMMARY_CAP: arr.pop_back() func mark_first_adventure_done() -> void: _save._data["meta"]["first_adventure_done"] = true # 钥石入账原语(生产消费零——apply_adventure_summary 专用;测量面经 _ 前缀直调) func _add_keystone(n: int) -> void: _save._data["meta"]["keystone_balance"] = keystone_balance() + n # ---- 只读投影族(6——值拷贝出户,禁碰内部结构契约同款)---- func keystone_balance() -> int: return int(_save._data["meta"]["keystone_balance"]) func item_unlocked(item_id: String) -> bool: return _save._data["meta"]["item_unlocks"].has(item_id) ## 天赋树域只读投影:{nodes: node_id→已购等级, fork_sides: fork_group→"a"|"b"} func tree_state() -> Dictionary: return { "nodes": (_save._data["meta"].get("tree_nodes", {}) as Dictionary).duplicate(), "fork_sides": (_save._data["meta"].get("fork_sides", {}) as Dictionary).duplicate(), } ## 锻造域只读投影:{levels: 六路线等级, unlocked: 直购清单, weapon/armor: 当前选中} ## (解锁态不落档——派生判定单点在 MetaProgression.forge_route_unlocked) func forge_state() -> Dictionary: var dom: Dictionary[Variant, Variant] = _forge_domain() return { "levels": (dom.get("levels", {}) as Dictionary).duplicate(), "unlocked": (dom.get("unlocked", []) as Array).duplicate(), "weapon": String(dom.get("weapon", "sword")), "armor": String(dom.get("armor", "light")), } ## 同调域只读投影:{equipped: 装配 item_id 有序数组(装配序即呈现序), refresh_level: Y 升级等级} func attune_state() -> Dictionary: return { "equipped": (_save._data["meta"].get("attunement_equipped", []) as Array).duplicate(), "refresh_level": int(_save._data["meta"].get("attune_refresh_level", 0)), } ## 生涯域只读投影:{clear_counts, boss_first_kill, boss_kill_count, adventure_total, ## adventure_cleared, vision_used, recent_summaries, first_adventure_done} func career_state() -> Dictionary: return { "clear_counts": (_save._data["meta"]["level_clear_counts"] as Dictionary).duplicate(), "boss_first_kill": (_save._data["meta"]["boss_first_kill"] as Dictionary).duplicate(), "boss_kill_count": int(_save._data["meta"].get("boss_kill_count", 0)), "adventure_total": int(_save._data["meta"].get("adventure_total", 0)), "adventure_cleared": int(_save._data["meta"].get("adventure_cleared", 0)), "vision_used": int(_save._data["meta"].get("vision_used", 0)), "recent_summaries": (_save._data["meta"]["recent_summaries"] as Array).duplicate(true), "first_adventure_done": bool(_save._data["meta"].get("first_adventure_done", true)), } # 锻造域取数(本件内部单点) func _forge_domain() -> Dictionary: return _save._data["meta"].get("forge_routes", {}) as Dictionary