forked from xiangwang25/whale-town-front-v2
228 lines
8.3 KiB
GDScript
228 lines
8.3 KiB
GDScript
extends Node
|
||
|
||
# ============================================================================
|
||
# PlayerStateManager.gd - 当前玩家状态聚合管理器
|
||
# ============================================================================
|
||
# 缓存后端 /player/snapshot,并向 UI 广播钱包、背包、外观和设置变化。
|
||
# ============================================================================
|
||
|
||
signal snapshot_changed(snapshot: Dictionary)
|
||
signal wallet_changed(wallet: Dictionary)
|
||
signal inventory_changed(inventory: Dictionary)
|
||
signal appearance_changed(appearance: Dictionary)
|
||
signal settings_changed(settings: Dictionary)
|
||
signal snapshot_failed(message: String)
|
||
|
||
var _snapshot: Dictionary = {}
|
||
var _wallet: Dictionary = {}
|
||
var _inventory: Dictionary = {}
|
||
var _appearance: Dictionary = {}
|
||
var _settings: Dictionary = {}
|
||
var _loadingSnapshot: bool = false
|
||
var _snapshotRequestGeneration: int = -1
|
||
|
||
func _ready() -> void:
|
||
var authManager := get_node_or_null("/root/AuthManager")
|
||
if authManager != null and authManager.has_signal("auth_state_changed"):
|
||
authManager.auth_state_changed.connect(_on_auth_state_changed)
|
||
|
||
func get_snapshot() -> Dictionary:
|
||
return _snapshot.duplicate(true)
|
||
|
||
func get_wallet() -> Dictionary:
|
||
return _wallet.duplicate(true)
|
||
|
||
func get_inventory() -> Dictionary:
|
||
return _inventory.duplicate(true)
|
||
|
||
func get_appearance() -> Dictionary:
|
||
return _appearance.duplicate(true)
|
||
|
||
func get_settings() -> Dictionary:
|
||
return _settings.duplicate(true)
|
||
|
||
func get_balance() -> int:
|
||
return int(_wallet.get("balance", 0))
|
||
|
||
func is_loaded() -> bool:
|
||
return not _snapshot.is_empty()
|
||
|
||
func refresh_snapshot() -> void:
|
||
if not _is_authenticated():
|
||
clear_state()
|
||
return
|
||
if _loadingSnapshot:
|
||
return
|
||
_loadingSnapshot = true
|
||
_snapshotRequestGeneration = _current_account_generation()
|
||
var api := _api_client()
|
||
if api == null:
|
||
_loadingSnapshot = false
|
||
_snapshotRequestGeneration = -1
|
||
snapshot_failed.emit("ApiClient 不可用")
|
||
return
|
||
api.call(
|
||
"get_json",
|
||
"/player/snapshot",
|
||
Callable(self, "_on_snapshot_response").bind(_snapshotRequestGeneration),
|
||
true
|
||
)
|
||
|
||
func apply_snapshot(snapshot: Dictionary) -> void:
|
||
_snapshot = snapshot.duplicate(true)
|
||
_wallet = _dictionary(snapshot.get("wallet", {}))
|
||
_inventory = _dictionary(snapshot.get("inventory", {}))
|
||
_appearance = _dictionary(snapshot.get("appearance", {}))
|
||
_settings = _dictionary(snapshot.get("settings", {}))
|
||
_apply_to_local_managers()
|
||
snapshot_changed.emit(get_snapshot())
|
||
wallet_changed.emit(get_wallet())
|
||
inventory_changed.emit(get_inventory())
|
||
appearance_changed.emit(get_appearance())
|
||
settings_changed.emit(get_settings())
|
||
|
||
func apply_wallet(wallet: Dictionary) -> void:
|
||
_wallet = wallet.duplicate(true)
|
||
if not _snapshot.is_empty():
|
||
_snapshot["wallet"] = _wallet.duplicate(true)
|
||
wallet_changed.emit(get_wallet())
|
||
|
||
func apply_inventory(inventory: Dictionary) -> void:
|
||
_inventory = inventory.duplicate(true)
|
||
if not _snapshot.is_empty():
|
||
_snapshot["inventory"] = _inventory.duplicate(true)
|
||
inventory_changed.emit(get_inventory())
|
||
_apply_inventory_to_appearance()
|
||
|
||
func apply_purchase_payload(payload: Dictionary) -> void:
|
||
var snapshotVariant: Variant = payload.get("snapshot", {})
|
||
if snapshotVariant is Dictionary:
|
||
apply_snapshot(snapshotVariant as Dictionary)
|
||
return
|
||
var walletVariant: Variant = payload.get("wallet", {})
|
||
if walletVariant is Dictionary:
|
||
apply_wallet(walletVariant as Dictionary)
|
||
var inventoryVariant: Variant = payload.get("inventory", {})
|
||
if inventoryVariant is Dictionary:
|
||
apply_inventory(inventoryVariant as Dictionary)
|
||
|
||
func update_appearance(skinId: String, completion: Callable = Callable()) -> void:
|
||
var api := _api_client()
|
||
if api == null:
|
||
var errorInfo := {"message": "ApiClient 不可用"}
|
||
snapshot_failed.emit(str(errorInfo.get("message")))
|
||
_call_update_completion(completion, false, {}, errorInfo)
|
||
return
|
||
var requestGeneration := _current_account_generation()
|
||
api.call(
|
||
"patch_json",
|
||
"/player/appearance",
|
||
{"skin_id": skinId},
|
||
Callable(self, "_on_update_response").bind(completion, requestGeneration),
|
||
true
|
||
)
|
||
|
||
func update_settings(settings: Dictionary, completion: Callable = Callable()) -> void:
|
||
var api := _api_client()
|
||
if api == null:
|
||
var errorInfo := {"message": "ApiClient 不可用"}
|
||
snapshot_failed.emit(str(errorInfo.get("message")))
|
||
_call_update_completion(completion, false, {}, errorInfo)
|
||
return
|
||
var requestGeneration := _current_account_generation()
|
||
api.call(
|
||
"patch_json",
|
||
"/player/settings",
|
||
{"settings": settings},
|
||
Callable(self, "_on_update_response").bind(completion, requestGeneration),
|
||
true
|
||
)
|
||
|
||
func clear_state() -> void:
|
||
_snapshot.clear()
|
||
_wallet.clear()
|
||
_inventory.clear()
|
||
_appearance.clear()
|
||
_settings.clear()
|
||
_loadingSnapshot = false
|
||
_snapshotRequestGeneration = -1
|
||
snapshot_changed.emit({})
|
||
wallet_changed.emit({})
|
||
inventory_changed.emit({})
|
||
appearance_changed.emit({})
|
||
settings_changed.emit({})
|
||
|
||
func _on_auth_state_changed(isAuthenticated: bool, _user: Dictionary) -> void:
|
||
if isAuthenticated:
|
||
if _snapshotRequestGeneration != _current_account_generation():
|
||
_loadingSnapshot = false
|
||
_snapshotRequestGeneration = -1
|
||
refresh_snapshot()
|
||
else:
|
||
clear_state()
|
||
|
||
func _on_snapshot_response(success: bool, response: Dictionary, errorInfo: Dictionary, requestGeneration: int) -> void:
|
||
if requestGeneration != _current_account_generation():
|
||
if requestGeneration == _snapshotRequestGeneration:
|
||
_loadingSnapshot = false
|
||
_snapshotRequestGeneration = -1
|
||
return
|
||
if requestGeneration == _snapshotRequestGeneration:
|
||
_loadingSnapshot = false
|
||
_snapshotRequestGeneration = -1
|
||
_apply_snapshot_response(success, response, errorInfo)
|
||
|
||
func _apply_snapshot_response(success: bool, response: Dictionary, errorInfo: Dictionary) -> void:
|
||
if not success:
|
||
snapshot_failed.emit(str(errorInfo.get("message", "玩家状态读取失败")))
|
||
return
|
||
var dataVariant: Variant = response.get("data", {})
|
||
if dataVariant is Dictionary:
|
||
apply_snapshot(dataVariant as Dictionary)
|
||
else:
|
||
snapshot_failed.emit("玩家状态格式错误")
|
||
|
||
func _on_update_response(success: bool, response: Dictionary, errorInfo: Dictionary, completion: Callable, requestGeneration: int) -> void:
|
||
if requestGeneration != _current_account_generation():
|
||
return
|
||
_apply_snapshot_response(success, response, errorInfo)
|
||
_call_update_completion(completion, success, response, errorInfo)
|
||
|
||
func _call_update_completion(completion: Callable, success: bool, response: Dictionary, errorInfo: Dictionary) -> void:
|
||
if completion.is_valid():
|
||
completion.call(success, response, errorInfo)
|
||
|
||
func _apply_to_local_managers() -> void:
|
||
_apply_inventory_to_appearance()
|
||
var appearanceManager := get_node_or_null("/root/AppearanceManager")
|
||
if appearanceManager != null and appearanceManager.has_method("apply_account_profile"):
|
||
var profile := _dictionary(_snapshot.get("profile", {}))
|
||
var appearance := _dictionary(_snapshot.get("appearance", {}))
|
||
profile["skin_id"] = str(appearance.get("selected_skin_id", profile.get("selected_skin_id", "")))
|
||
profile["owned_skin_ids"] = appearance.get("owned_skin_ids", [])
|
||
profile["owned_skins"] = appearance.get("owned_skins", [])
|
||
appearanceManager.call("apply_account_profile", profile)
|
||
var settingsManager := get_node_or_null("/root/SettingsManager")
|
||
if settingsManager != null and settingsManager.has_method("apply_account_settings"):
|
||
settingsManager.call("apply_account_settings", get_settings())
|
||
|
||
func _apply_inventory_to_appearance() -> void:
|
||
var skinIds: Variant = _inventory.get("skin_ids", [])
|
||
var appearanceManager := get_node_or_null("/root/AppearanceManager")
|
||
if skinIds is Array and appearanceManager != null and appearanceManager.has_method("set_owned_skin_ids"):
|
||
appearanceManager.call("set_owned_skin_ids", skinIds)
|
||
|
||
func _dictionary(value: Variant) -> Dictionary:
|
||
return (value as Dictionary).duplicate(true) if value is Dictionary else {}
|
||
|
||
func _api_client() -> Node:
|
||
return get_node_or_null("/root/ApiClient")
|
||
|
||
func _is_authenticated() -> bool:
|
||
var authManager := get_node_or_null("/root/AuthManager")
|
||
return bool(authManager.call("is_authenticated")) if authManager != null and authManager.has_method("is_authenticated") else false
|
||
|
||
func _current_account_generation() -> int:
|
||
var authManager := get_node_or_null("/root/AuthManager")
|
||
return int(authManager.call("get_account_generation")) if authManager != null and authManager.has_method("get_account_generation") else 0
|