extends Node # ============================================================================ # WebSocketManager.gd - WebSocket连接管理器 # ============================================================================ # 负责与后端 Native WebSocket 服务进行实时通信 # # 协议文档: new_docs/game_architecture_design.md # 后端地址: ws://localhost:3000/location-broadcast # ============================================================================ signal connected_to_server() signal connection_closed() signal connection_error() signal session_joined(data: Dictionary) signal user_joined(data: Dictionary) signal user_left(data: Dictionary) signal position_updated(data: Dictionary) const WS_URL = "wss://whaletownend.xinghangee.icu/location-broadcast" const PING_INTERVAL = 25.0 # 秒 var _socket: WebSocketPeer var _connected: bool = false var _ping_timer: float = 0.0 var _auth_token: String = "" func _ready(): _socket = WebSocketPeer.new() process_mode = Node.PROCESS_MODE_ALWAYS # 保证暂停时也能处理网络 print("WebSocketManager Initialized") func _process(delta): _socket.poll() var state = _socket.get_ready_state() if state == WebSocketPeer.STATE_OPEN: if not _connected: _on_connected() # 处理接收到的数据包 while _socket.get_available_packet_count() > 0: var packet = _socket.get_packet() _handle_packet(packet) # 心跳处理 _ping_timer += delta if _ping_timer >= PING_INTERVAL: _send_heartbeat() _ping_timer = 0.0 elif state == WebSocketPeer.STATE_CLOSED: if _connected: _on_disconnected() func connect_to_server(): if _socket.get_ready_state() == WebSocketPeer.STATE_OPEN: print("WebSocket 已经是连接状态") return print("正在连接 WebSocket: ", WS_URL) var err = _socket.connect_to_url(WS_URL) if err != OK: print("WebSocket 连接请求失败: ", err) connection_error.emit() else: # Godot WebSocket connect is non-blocking, wait for state change in _process pass func close_connection(): _socket.close() func set_auth_token(token: String): _auth_token = token # ============ 协议发送 ============ func send_packet(event: String, data: Dictionary): if _socket.get_ready_state() != WebSocketPeer.STATE_OPEN: return var message = { "event": event, "data": data } var json_str = JSON.stringify(message) _socket.put_packet(json_str.to_utf8_buffer()) func join_session(map_id: String, initial_pos: Vector2): var data = { "sessionId": map_id, "initialPosition": { "x": initial_pos.x, "y": initial_pos.y, "mapId": map_id }, "token": _auth_token } print("发送加入会话请求: ", map_id, " mapId Payload: ", data.initialPosition.mapId) send_packet("join_session", data) func leave_session(map_id: String): print("发送离开会话请求: ", map_id) send_packet("leave_session", {"sessionId": map_id}) func send_position_update(map_id: String, pos: Vector2, anim_data: Dictionary = {}): var data = { "x": pos.x, "y": pos.y, "mapId": map_id, "metadata": anim_data } # print("发送位置更新: ", map_id) if map_id == "": print("WARNING: Sending position update with EMPTY mapId! Pos: ", pos) send_packet("position_update", data) func _send_heartbeat(): send_packet("heartbeat", {"timestamp": Time.get_unix_time_from_system()}) # ============ 事件处理 ============ func _on_connected(): _connected = true print("WebSocket 连接成功!") connected_to_server.emit() func _on_disconnected(): _connected = false var code = _socket.get_close_code() var reason = _socket.get_close_reason() print("WebSocket 连接断开. Code: %d, Reason: %s" % [code, reason]) connection_closed.emit() func _handle_packet(packet: PackedByteArray): var json_str = packet.get_string_from_utf8() var json = JSON.new() var err = json.parse(json_str) if err != OK: print("JSON 解析失败: ", json.get_error_message()) return var message = json.data if not message is Dictionary or not message.has("event"): return var event = message["event"] var data = message.get("data", {}) if event != "heartbeat_response": print("WebSocket Rx: ", event) # Debug logs for all events match event: "session_joined": session_joined.emit(data) print("加入会话成功,当前房间人数: ", data.get("users", []).size()) "user_joined": user_joined.emit(data) print("用户加入: ", data.get("userId")) "user_left": user_left.emit(data) print("用户离开: ", data.get("userId")) "position_update": print("WebSocket Rx position_update: ", data.get("userId", "unknown")) position_updated.emit(data) "heartbeat_response": pass # 静默处理 "error": print("WebSocket 错误事件: ", JSON.stringify(data)) _: print("未处理的 WebSocket 事件: ", event)