177 lines
7.3 KiB
GDScript
177 lines
7.3 KiB
GDScript
## 存档内元进度数据件(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
|