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 # Since there's no specific RPC for just marking as read, we can just do a claim with 0 rewards if needed, # or add an RPC for it. For now we just let claim or delete handle the server-side state. # Let's add an empty claim or just handle it purely local until claimed/deleted if it has no rewards. pass