Files
tekton/scripts/managers/mail_manager.gd
T
2026-05-12 17:55:53 +08:00

142 lines
3.9 KiB
GDScript

extends Node
signal mail_updated
signal unread_count_changed(count: int)
var mails: Array = []
var claimed_ids: Array = []
var read_ids: Array = []
var _is_fetching: bool = false
func _ready() -> void:
if UserProfileManager:
UserProfileManager.profile_loaded.connect(_on_profile_loaded)
func _on_profile_loaded(_profile: Dictionary) -> void:
fetch_mails()
func fetch_mails() -> void:
if _is_fetching or not NakamaManager.session: return
_is_fetching = true
var r = await NakamaManager.client.rpc_async(NakamaManager.session, "get_mail", "{}")
_is_fetching = false
if r.is_exception():
push_error("[MailManager] Failed to fetch mails: " + r.get_exception().message)
return
var payload = JSON.parse_string(r.payload)
if payload and payload is Dictionary:
mails = payload.get("mails", [])
var state = payload.get("state", {})
claimed_ids = state.get("claimed_ids", [])
read_ids = state.get("read_ids", [])
# Sort by date descending
mails.sort_custom(func(a, b):
return a.get("date", "") > b.get("date", "")
)
mail_updated.emit()
_update_unread_count()
func _update_unread_count() -> void:
var count = 0
for m in mails:
if m.id not in read_ids:
count += 1
unread_count_changed.emit(count)
func claim_reward(mail_id: String) -> bool:
var r = await NakamaManager.client.rpc_async(NakamaManager.session, "claim_mail_reward", JSON.stringify({"mail_id": mail_id}))
if r.is_exception():
push_error("[MailManager] Claim failed: " + r.get_exception().message)
return false
var payload = JSON.parse_string(r.payload)
if payload and payload.get("success"):
claimed_ids = payload.get("claimed_ids", claimed_ids)
if mail_id not in read_ids:
read_ids.append(mail_id)
mail_updated.emit()
_update_unread_count()
# Refresh wallet
UserProfileManager.load_profile()
return true
return false
func delete_mail(mail_id: String) -> bool:
var r = await NakamaManager.client.rpc_async(NakamaManager.session, "delete_mail", JSON.stringify({"mail_id": mail_id}))
if r.is_exception():
push_error("[MailManager] Delete failed: " + r.get_exception().message)
return false
var payload = JSON.parse_string(r.payload)
if payload and payload.get("success"):
var deleted_ids = payload.get("deleted_ids", [])
# Remove from local array
for i in range(mails.size() - 1, -1, -1):
if mails[i].id in deleted_ids:
mails.remove_at(i)
if mail_id not in read_ids:
read_ids.append(mail_id)
mail_updated.emit()
_update_unread_count()
return true
return false
func mark_as_read(mail_id: String) -> void:
if mail_id in read_ids: return
read_ids.append(mail_id)
_update_unread_count()
# Persist read state to server via delete_mail RPC pattern (just saves state)
_save_inbox_state()
func _save_inbox_state() -> void:
if not NakamaManager.session: return
var state_payload = {
"claimed_ids": claimed_ids,
"deleted_ids": [],
"read_ids": read_ids
}
# We use storage write via a lightweight RPC or direct storage
var r = await NakamaManager.client.rpc_async(
NakamaManager.session, "save_mail_state",
JSON.stringify(state_payload)
)
if r.is_exception():
push_warning("[MailManager] Could not save mail state: " + r.get_exception().message)
func read_all_and_claim_all() -> void:
"""Mark all mails as read and claim all unclaimed rewards."""
if mails.is_empty(): return
# Mark all as read
for mail in mails:
var mid = mail.get("id", "")
if mid not in read_ids:
read_ids.append(mid)
# Claim all unclaimed rewards
var to_claim: Array = []
for mail in mails:
var mid = mail.get("id", "")
if mid in claimed_ids: continue
var rewards = mail.get("rewards", [])
var has_rewards = false
if typeof(rewards) == TYPE_DICTIONARY:
has_rewards = rewards.get("star", 0) > 0 or rewards.get("gold", 0) > 0
elif typeof(rewards) == TYPE_ARRAY:
has_rewards = rewards.size() > 0
if has_rewards:
to_claim.append(mid)
for mid in to_claim:
await claim_reward(mid)
_update_unread_count()
mail_updated.emit()