Files
gplan-2/game/core/meta_state_store.gd
T

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