forked from xiangwang25/whale-town-front-v2
Initial WhaleTown V2 frontend
This commit is contained in:
227
_Core/managers/PlayerStateManager.gd
Normal file
227
_Core/managers/PlayerStateManager.gd
Normal file
@@ -0,0 +1,227 @@
|
||||
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
|
||||
Reference in New Issue
Block a user