extends Node class_name PrivateChatSystem ## 私聊系统 ## 管理玩家之间的私人聊天功能 # 私聊会话数据结构 class PrivateConversation: var conversation_id: String var participant_ids: Array[String] = [] var participant_names: Dictionary = {} # id -> name var messages: Array[Dictionary] = [] var created_at: float var last_activity: float var is_active: bool = true var unread_count: int = 0 func _init(conv_id: String, participants: Array[String], names: Dictionary): conversation_id = conv_id participant_ids = participants.duplicate() participant_names = names.duplicate() created_at = Time.get_unix_time_from_system() last_activity = created_at # 私聊数据存储 var conversations: Dictionary = {} # conversation_id -> PrivateConversation var user_conversations: Dictionary = {} # user_id -> Array[conversation_id] var active_conversation: String = "" var max_conversations: int = 50 var max_messages_per_conversation: int = 500 # 好友系统引用 var friend_system: FriendSystem # 数据持久化 var chat_file_path: String = "user://private_chats.json" # 信号 signal conversation_created(conversation_id: String, participants: Array[String]) signal message_sent(conversation_id: String, sender_id: String, message: String) signal message_received(conversation_id: String, sender_id: String, message: String) signal conversation_opened(conversation_id: String) signal conversation_closed(conversation_id: String) signal unread_count_changed(conversation_id: String, count: int) signal typing_indicator(conversation_id: String, user_id: String, is_typing: bool) func _ready(): """初始化私聊系统""" load_chat_data() print("PrivateChatSystem initialized") ## 设置好友系统引用 func set_friend_system(fs: FriendSystem) -> void: """ 设置好友系统引用 @param fs: 好友系统实例 """ friend_system = fs ## 开始私聊 func start_private_chat(target_id: String, target_name: String) -> String: """ 开始与指定用户的私聊 @param target_id: 目标用户ID @param target_name: 目标用户名称 @return: 会话ID,失败返回空字符串 """ # 检查是否为好友(如果有好友系统) if friend_system and not friend_system.is_friend(target_id): print("Cannot start private chat: not friends with ", target_name) return "" # 检查是否被屏蔽 if friend_system and friend_system.is_blocked(target_id): print("Cannot start private chat: user is blocked") return "" # 查找现有会话 var existing_conversation = find_conversation_with_user(target_id) if not existing_conversation.is_empty(): print("Using existing conversation with ", target_name) return existing_conversation # 检查会话数量限制 if conversations.size() >= max_conversations: print("Cannot create new conversation: limit reached") return "" # 创建新会话 var conversation_id = generate_conversation_id() var participants = ["player", target_id] var names = {"player": "You", target_id: target_name} var conversation = PrivateConversation.new(conversation_id, participants, names) conversations[conversation_id] = conversation # 更新用户会话索引 _add_conversation_to_user_index("player", conversation_id) _add_conversation_to_user_index(target_id, conversation_id) # 保存数据 save_chat_data() # 发射信号 conversation_created.emit(conversation_id, participants) print("Private chat started with ", target_name, " (", conversation_id, ")") return conversation_id ## 发送私聊消息 func send_private_message(conversation_id: String, message: String) -> bool: """ 发送私聊消息 @param conversation_id: 会话ID @param message: 消息内容 @return: 是否成功发送 """ if not conversations.has(conversation_id): print("Conversation not found: ", conversation_id) return false var conversation = conversations[conversation_id] # 验证消息 if message.strip_edges().is_empty(): print("Cannot send empty message") return false if message.length() > 1000: print("Message too long") return false # 创建消息记录 var message_record = { "id": generate_message_id(), "sender_id": "player", "message": message, "timestamp": Time.get_unix_time_from_system(), "read": false } # 添加到会话历史 conversation.messages.append(message_record) conversation.last_activity = message_record.timestamp # 限制消息历史长度 if conversation.messages.size() > max_messages_per_conversation: conversation.messages.pop_front() # 记录好友互动 if friend_system: for participant_id in conversation.participant_ids: if participant_id != "player": friend_system.record_interaction(participant_id, "private_chat") # 保存数据 save_chat_data() # 发射信号 message_sent.emit(conversation_id, "player", message) print("Private message sent in ", conversation_id, ": ", message) return true ## 接收私聊消息 func receive_private_message(conversation_id: String, sender_id: String, message: String) -> void: """ 接收私聊消息 @param conversation_id: 会话ID @param sender_id: 发送者ID @param message: 消息内容 """ if not conversations.has(conversation_id): print("Conversation not found for received message: ", conversation_id) return var conversation = conversations[conversation_id] # 创建消息记录 var message_record = { "id": generate_message_id(), "sender_id": sender_id, "message": message, "timestamp": Time.get_unix_time_from_system(), "read": false } # 添加到会话历史 conversation.messages.append(message_record) conversation.last_activity = message_record.timestamp # 更新未读计数(如果不是当前活跃会话) if active_conversation != conversation_id: conversation.unread_count += 1 unread_count_changed.emit(conversation_id, conversation.unread_count) # 限制消息历史长度 if conversation.messages.size() > max_messages_per_conversation: conversation.messages.pop_front() # 保存数据 save_chat_data() # 发射信号 message_received.emit(conversation_id, sender_id, message) print("Private message received in ", conversation_id, " from ", sender_id, ": ", message) ## 打开会话 func open_conversation(conversation_id: String) -> bool: """ 打开指定会话 @param conversation_id: 会话ID @return: 是否成功打开 """ if not conversations.has(conversation_id): print("Conversation not found: ", conversation_id) return false # 关闭当前活跃会话 if not active_conversation.is_empty(): close_conversation(active_conversation) # 设置为活跃会话 active_conversation = conversation_id var conversation = conversations[conversation_id] # 标记所有消息为已读 for message in conversation.messages: message.read = true # 重置未读计数 if conversation.unread_count > 0: conversation.unread_count = 0 unread_count_changed.emit(conversation_id, 0) # 保存数据 save_chat_data() # 发射信号 conversation_opened.emit(conversation_id) print("Conversation opened: ", conversation_id) return true ## 关闭会话 func close_conversation(conversation_id: String) -> void: """ 关闭指定会话 @param conversation_id: 会话ID """ if active_conversation == conversation_id: active_conversation = "" conversation_closed.emit(conversation_id) print("Conversation closed: ", conversation_id) ## 删除会话 func delete_conversation(conversation_id: String) -> bool: """ 删除会话 @param conversation_id: 会话ID @return: 是否成功删除 """ if not conversations.has(conversation_id): print("Conversation not found: ", conversation_id) return false var conversation = conversations[conversation_id] # 从用户会话索引中移除 for participant_id in conversation.participant_ids: _remove_conversation_from_user_index(participant_id, conversation_id) # 如果是当前活跃会话,关闭它 if active_conversation == conversation_id: close_conversation(conversation_id) # 删除会话 conversations.erase(conversation_id) # 保存数据 save_chat_data() print("Conversation deleted: ", conversation_id) return true ## 获取会话列表 func get_conversations_list() -> Array[Dictionary]: """ 获取用户的会话列表 @return: 会话信息数组 """ var conversations_list = [] # 获取用户参与的所有会话 var user_conv_ids = user_conversations.get("player", []) for conv_id in user_conv_ids: if conversations.has(conv_id): var conversation = conversations[conv_id] var last_message = "" var last_sender = "" if conversation.messages.size() > 0: var last_msg = conversation.messages[-1] last_message = last_msg.message last_sender = last_msg.sender_id # 获取对方用户信息 var other_participants = [] for participant_id in conversation.participant_ids: if participant_id != "player": other_participants.append({ "id": participant_id, "name": conversation.participant_names.get(participant_id, "Unknown") }) conversations_list.append({ "id": conv_id, "participants": other_participants, "last_message": last_message, "last_sender": last_sender, "last_activity": conversation.last_activity, "unread_count": conversation.unread_count, "message_count": conversation.messages.size(), "is_active": conversation.is_active }) # 按最后活动时间排序(最新的在前) conversations_list.sort_custom(func(a, b): return a.last_activity > b.last_activity) return conversations_list ## 获取会话消息 func get_conversation_messages(conversation_id: String, limit: int = 0) -> Array[Dictionary]: """ 获取会话消息历史 @param conversation_id: 会话ID @param limit: 限制返回的消息数量(0表示返回全部) @return: 消息数组 """ if not conversations.has(conversation_id): return [] var conversation = conversations[conversation_id] var messages = conversation.messages if limit <= 0 or limit >= messages.size(): return messages.duplicate() # 返回最近的消息 return messages.slice(messages.size() - limit, messages.size()) ## 搜索会话消息 func search_conversation_messages(conversation_id: String, query: String) -> Array[Dictionary]: """ 在会话中搜索消息 @param conversation_id: 会话ID @param query: 搜索关键词 @return: 匹配的消息数组 """ if not conversations.has(conversation_id): return [] var conversation = conversations[conversation_id] var results = [] var search_query = query.to_lower() for message in conversation.messages: if message.message.to_lower().contains(search_query): results.append(message.duplicate()) return results ## 查找与用户的会话 func find_conversation_with_user(user_id: String) -> String: """ 查找与指定用户的会话 @param user_id: 用户ID @return: 会话ID,如果不存在则返回空字符串 """ var user_conv_ids = user_conversations.get("player", []) for conv_id in user_conv_ids: if conversations.has(conv_id): var conversation = conversations[conv_id] if user_id in conversation.participant_ids: return conv_id return "" ## 获取未读消息总数 func get_total_unread_count() -> int: """ 获取所有会话的未读消息总数 @return: 未读消息总数 """ var total = 0 var user_conv_ids = user_conversations.get("player", []) for conv_id in user_conv_ids: if conversations.has(conv_id): total += conversations[conv_id].unread_count return total ## 设置输入状态 func set_typing_status(conversation_id: String, is_typing: bool) -> void: """ 设置输入状态 @param conversation_id: 会话ID @param is_typing: 是否正在输入 """ if conversations.has(conversation_id): typing_indicator.emit(conversation_id, "player", is_typing) ## 处理输入状态通知 func handle_typing_notification(conversation_id: String, user_id: String, is_typing: bool) -> void: """ 处理其他用户的输入状态通知 @param conversation_id: 会话ID @param user_id: 用户ID @param is_typing: 是否正在输入 """ if conversations.has(conversation_id): typing_indicator.emit(conversation_id, user_id, is_typing) ## 生成会话ID func generate_conversation_id() -> String: """生成唯一的会话ID""" var timestamp = Time.get_unix_time_from_system() var random = randi() return "conv_%d_%d" % [timestamp, random] ## 生成消息ID func generate_message_id() -> String: """生成唯一的消息ID""" var timestamp = Time.get_unix_time_from_system() var random = randi() return "msg_%d_%d" % [timestamp, random] ## 添加会话到用户索引 func _add_conversation_to_user_index(user_id: String, conversation_id: String) -> void: """ 添加会话到用户索引 @param user_id: 用户ID @param conversation_id: 会话ID """ if not user_conversations.has(user_id): user_conversations[user_id] = [] var user_convs = user_conversations[user_id] if not conversation_id in user_convs: user_convs.append(conversation_id) ## 从用户索引移除会话 func _remove_conversation_from_user_index(user_id: String, conversation_id: String) -> void: """ 从用户索引移除会话 @param user_id: 用户ID @param conversation_id: 会话ID """ if user_conversations.has(user_id): var user_convs = user_conversations[user_id] user_convs.erase(conversation_id) ## 保存聊天数据 func save_chat_data() -> void: """保存聊天数据到本地文件""" var data = { "conversations": {}, "user_conversations": user_conversations, "active_conversation": active_conversation } # 序列化会话数据 for conv_id in conversations: var conversation = conversations[conv_id] data.conversations[conv_id] = { "participant_ids": conversation.participant_ids, "participant_names": conversation.participant_names, "messages": conversation.messages, "created_at": conversation.created_at, "last_activity": conversation.last_activity, "is_active": conversation.is_active, "unread_count": conversation.unread_count } var file = FileAccess.open(chat_file_path, FileAccess.WRITE) if file: var json_string = JSON.stringify(data) file.store_string(json_string) file.close() print("Private chat data saved") else: print("Failed to save private chat data") ## 加载聊天数据 func load_chat_data() -> void: """从本地文件加载聊天数据""" if not FileAccess.file_exists(chat_file_path): print("No private chat data file found, starting fresh") return var file = FileAccess.open(chat_file_path, FileAccess.READ) if file: var json_string = file.get_as_text() file.close() var json = JSON.new() var parse_result = json.parse(json_string) if parse_result == OK: var data = json.data # 加载会话数据 if data.has("conversations"): for conv_id in data.conversations: var conv_data = data.conversations[conv_id] var conversation = PrivateConversation.new( conv_id, conv_data.get("participant_ids", []), conv_data.get("participant_names", {}) ) conversation.messages = conv_data.get("messages", []) conversation.created_at = conv_data.get("created_at", Time.get_unix_time_from_system()) conversation.last_activity = conv_data.get("last_activity", conversation.created_at) conversation.is_active = conv_data.get("is_active", true) conversation.unread_count = conv_data.get("unread_count", 0) conversations[conv_id] = conversation # 加载用户会话索引 if data.has("user_conversations"): user_conversations = data.user_conversations # 加载活跃会话 if data.has("active_conversation"): active_conversation = data.active_conversation print("Private chat data loaded: ", conversations.size(), " conversations") else: print("Failed to parse private chat data JSON") else: print("Failed to open private chat data file") ## 获取统计信息 func get_statistics() -> Dictionary: """ 获取私聊系统统计信息 @return: 统计信息字典 """ var total_messages = 0 var total_unread = 0 var active_conversations = 0 for conv_id in conversations: var conversation = conversations[conv_id] total_messages += conversation.messages.size() total_unread += conversation.unread_count if conversation.is_active: active_conversations += 1 return { "total_conversations": conversations.size(), "active_conversations": active_conversations, "total_messages": total_messages, "total_unread": total_unread, "current_active": active_conversation, "max_conversations": max_conversations, "max_messages_per_conversation": max_messages_per_conversation }