extends Node # ============================================================================ # SocketIOClient.gd - Socket.IO 协议封装 # ============================================================================ # 封装 Godot 的 WebSocketPeer,实现简化的 Socket.IO 协议 # # 核心职责: # - WebSocket 连接管理 # - Socket.IO 消息协议(简化版 JSON 格式) # - 事件监听器管理 # - 消息发送/接收 # # 注意事项: # - 后端使用简化版 Socket.IO(纯 JSON,无二进制协议) # - 发送消息使用 "t" 字段标识事件类型 # - 所有消息通过 JSON 序列化 # ============================================================================ class_name SocketIOClient # ============================================================================ # 信号定义 # ============================================================================ # 连接成功信号 signal connected() # 连接断开信号 # 参数: # clean_close: bool - 是否为正常关闭 signal disconnected(clean_close: bool) # 事件接收信号 # 参数: # event_name: String - 事件名称(从 "t" 字段提取) # data: Dictionary - 事件数据 signal event_received(event_name: String, data: Dictionary) # 错误发生信号 # 参数: # error: String - 错误信息 signal error_occurred(error: String) # ============================================================================ # 常量定义 # ============================================================================ # 连接状态枚举 enum ConnectionState { DISCONNECTED, # 未连接 CONNECTING, # 连接中 CONNECTED # 已连接 } # ============================================================================ # 成员变量 # ============================================================================ # WebSocket 客户端 var _websocket_peer: WebSocketPeer = WebSocketPeer.new() # 连接状态 var _connection_state: ConnectionState = ConnectionState.DISCONNECTED # 服务器 URL var _server_url: String = "" # 事件监听器: {event_name: [Callable, ...]} var _event_listeners: Dictionary = {} # ============================================================================ # 生命周期方法 # ============================================================================ # 初始化 func _ready() -> void: print("SocketIOClient 初始化完成") # 处理进程 - 轮询 WebSocket 消息 func _process(_delta: float) -> void: # 轮询 WebSocket 状态 _websocket_peer.poll() # 检查连接状态变化 var new_state: ConnectionState = _get_connection_state() if new_state != _connection_state: _connection_state = new_state _on_state_changed(_connection_state) # 处理接收到的消息 _process_incoming_messages() # ============================================================================ # 公共 API - 连接管理 # ============================================================================ # 连接到服务器 # # 参数: # url: String - WebSocket 服务器 URL (ws:// 或 wss://) # # 使用示例: # socket_client.connect_to_server("wss://example.com/game") func connect_to_server(url: String) -> void: if _connection_state == ConnectionState.CONNECTED: push_warning("已经连接到服务器,无需重复连接") return _server_url = url print("=== SocketIOClient 开始连接 ===") print("服务器 URL: ", _server_url) # 创建 WebSocket 客户端 _websocket_peer = WebSocketPeer.new() # 发起连接 var error := _websocket_peer.connect_to_url(url) if error != OK: push_error("WebSocket 连接失败: %s" % error) error_occurred.emit("WebSocket 连接失败") return _connection_state = ConnectionState.CONNECTING print("WebSocket 连接中...") # 断开连接 func disconnect_from_server() -> void: if _connection_state == ConnectionState.DISCONNECTED: return print("=== SocketIOClient 断开连接 ===") _websocket_peer.close() _connection_state = ConnectionState.DISCONNECTED disconnected.emit(true) # 检查是否已连接 # # 返回值: # bool - 是否已连接 func is_connected() -> bool: return _connection_state == ConnectionState.CONNECTED # ============================================================================ # 公共 API - 事件发送 # ============================================================================ # 发送事件(对应 socket.emit) # # 参数: # event_name: String - 事件名称(如 "login", "chat") # data: Dictionary - 事件数据 # # 使用示例: # socket_client.emit("login", {"type": "login", "token": "abc123"}) # socket_client.emit("chat", {"t": "chat", "content": "Hello", "scope": "local"}) func emit(event_name: String, data: Dictionary) -> void: if not is_connected(): push_error("无法发送事件: 未连接到服务器") error_occurred.emit("未连接到服务器") return # 序列化为 JSON var json_string := JSON.stringify(data) if json_string.is_empty(): push_error("JSON 序列化失败") error_occurred.emit("JSON 序列化失败") return # 发送数据包 var packet := json_string.to_utf8_buffer() var error := _websocket_peer.send(packet) if error != OK: push_error("发送数据包失败: %s" % error) error_occurred.emit("发送数据包失败") return print("📤 发送事件: ", event_name) print(" 数据: ", json_string if json_string.length() < 200 else json_string.substr(0, 200) + "...") # ============================================================================ # 公共 API - 事件监听 # ============================================================================ # 添加事件监听器(对应 socket.on) # # 参数: # event_name: String - 事件名称 # callback: Callable - 回调函数,接收 data: Dictionary 参数 # # 使用示例: # socket_client.add_event_listener("chat_render", func(data): # print("收到消息: ", data.txt) # ) func add_event_listener(event_name: String, callback: Callable) -> void: if not _event_listeners.has(event_name): _event_listeners[event_name] = [] _event_listeners[event_name].append(callback) print("注册事件监听器: ", event_name, " -> ", callback) # 移除事件监听器 # # 参数: # event_name: String - 事件名称 # callback: Callable - 要移除的回调函数 func remove_event_listener(event_name: String, callback: Callable) -> void: if not _event_listeners.has(event_name): return var listeners: Array = _event_listeners[event_name] listeners.erase(callback) if listeners.is_empty(): _event_listeners.erase(event_name) print("移除事件监听器: ", event_name, " -> ", callback) # ============================================================================ # 内部方法 - 消息处理 # ============================================================================ # 处理接收到的消息 func _process_incoming_messages() -> void: # 检查是否有可用数据包 while _websocket_peer.get_available_packet_count() > 0: # 接收数据包 var packet: PackedByteArray = _websocket_peer.get_packet() # 解析为字符串 var json_string: String = packet.get_string_from_utf8() # 解析 JSON var json := JSON.new() var parse_result := json.parse(json_string) if parse_result != OK: push_error("JSON 解析失败: " + json_string) error_occurred.emit("JSON 解析失败") continue var data: Dictionary = json.data # 提取事件类型(从 "t" 字段) var event_name: String = data.get("t", "") if event_name.is_empty(): # 如果没有 "t" 字段,尝试其他方式识别 if data.has("type"): event_name = data["type"] elif data.has("code"): event_name = "error" else: push_warning("收到未知格式消息: " + json_string) continue print("📨 收到事件: ", event_name) print(" 数据: ", json_string if json_string.length() < 200 else json_string.substr(0, 200) + "...") # 调用事件监听器 _notify_event_listeners(event_name, data) # 发射通用信号 event_received.emit(event_name, data) # 通知事件监听器 func _notify_event_listeners(event_name: String, data: Dictionary) -> void: if not _event_listeners.has(event_name): return var listeners: Array = _event_listeners[event_name] for callback in listeners: if callback.is_valid(): callback.call(data) # ============================================================================ # 内部方法 - 状态管理 # ============================================================================ # 获取当前连接状态 func _get_connection_state() -> ConnectionState: match _websocket_peer.get_ready_state(): WebSocketPeer.STATE_CONNECTING: return ConnectionState.CONNECTING WebSocketPeer.STATE_OPEN: return ConnectionState.CONNECTED WebSocketPeer.STATE_CLOSING: return ConnectionState.CONNECTING WebSocketPeer.STATE_CLOSED: return ConnectionState.DISCONNECTED _: return ConnectionState.DISCONNECTED # 连接状态变化处理 func _on_state_changed(new_state: ConnectionState) -> void: match new_state: ConnectionState.CONNECTED: print("✅ WebSocket 连接成功") connected.emit() ConnectionState.DISCONNECTED: print("🔌 WebSocket 连接断开") disconnected.emit(false) ConnectionState.CONNECTING: print("⏳ WebSocket 连接中...")