Files
whale-town-front/_Core/managers/WebSocketManager.gd
WhaleTown Developer 25a21f92be feat(chat): 优化聊天UI布局和WebSocket连接
- 更新 WebSocket URL 以支持 Socket.IO 握手参数 (EIO=4)
- 重构聊天面板布局,使用绝对定位和百分比锚点
- 优化输入框样式,添加装饰元素
- 修复输入框焦点释放的事件冲突问题
- 将 ChatUI 集成到主场景中
- 改进主场景容器布局设置
2026-01-08 23:59:21 +08:00

337 lines
10 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node
# ============================================================================
# WebSocketManager.gd - WebSocket 连接生命周期管理
# ============================================================================
# 管理 WebSocket 连接状态、自动重连和错误恢复
#
# 核心职责:
# - 连接状态管理(断开、连接中、已连接、重连中)
# - 自动重连机制(指数退避)
# - 连接错误恢复
# - Socket.IO 客户端封装
#
# 使用方式:
# WebSocketManager.connect_to_game_server()
# WebSocketManager.connection_state_changed.connect(_on_state_changed)
#
# 注意事项:
# - 作为自动加载单例,全局可访问
# - 自动处理连接断开和重连
# - 通过信号通知连接状态变化
# ============================================================================
class_name WebSocketManager
# ============================================================================
# 信号定义
# ============================================================================
# 连接状态变化信号
# 参数:
# new_state: ConnectionState - 新的连接状态
signal connection_state_changed(new_state: ConnectionState)
# 连接丢失信号
signal connection_lost()
# 重连成功信号
signal reconnection_succeeded()
# 重连失败信号
# 参数:
# attempt: int - 当前重连尝试次数
# max_attempts: int - 最大重连次数
signal reconnection_failed(attempt: int, max_attempts: int)
# ============================================================================
# 枚举定义
# ============================================================================
# 连接状态枚举
enum ConnectionState {
DISCONNECTED, # 未连接
CONNECTING, # 连接中
CONNECTED, # 已连接
RECONNECTING, # 重连中
ERROR # 错误状态
}
# ============================================================================
# 常量定义
# ============================================================================
# WebSocket 服务器 URL
# 添加 Socket.IO 握手参数EIO=4 表示 Engine.IO 版本transport=websocket
const WEBSOCKET_URL: String = "wss://whaletownend.xinghangee.icu/game/socket.io/?EIO=4&transport=websocket"
# 默认最大重连次数
const DEFAULT_MAX_RECONNECT_ATTEMPTS: int = 5
# 默认重连基础延迟(秒)
const DEFAULT_RECONNECT_BASE_DELAY: float = 3.0
# 最大重连延迟(秒)
const MAX_RECONNECT_DELAY: float = 30.0
# ============================================================================
# 成员变量
# ============================================================================
# Socket.IO 客户端
var _socket_client: SocketIOClient
# 当前连接状态
var _connection_state: ConnectionState = ConnectionState.DISCONNECTED
# 自动重连启用标志
var _auto_reconnect_enabled: bool = true
# 最大重连次数
var _max_reconnect_attempts: int = DEFAULT_MAX_RECONNECT_ATTEMPTS
# 重连基础延迟
var _reconnect_base_delay: float = DEFAULT_RECONNECT_BASE_DELAY
# 当前重连尝试次数
var _reconnect_attempt: int = 0
# 重连定时器
var _reconnect_timer: Timer = Timer.new()
# 是否为正常关闭(非异常断开)
var _clean_close: bool = true
# ============================================================================
# 生命周期方法
# ============================================================================
# 初始化
func _ready() -> void:
print("WebSocketManager 初始化完成")
# 创建 Socket.IO 客户端
_socket_client = SocketIOClient.new()
add_child(_socket_client)
# 连接信号
_socket_client.connected.connect(_on_socket_connected)
_socket_client.disconnected.connect(_on_socket_disconnected)
_socket_client.error_occurred.connect(_on_socket_error)
# 设置重连定时器
_setup_reconnect_timer()
# 清理
func _exit_tree() -> void:
if is_instance_valid(_reconnect_timer):
_reconnect_timer.stop()
_reconnect_timer.queue_free()
# ============================================================================
# 公共 API - 连接管理
# ============================================================================
# 连接到游戏服务器
func connect_to_game_server() -> void:
if _connection_state == ConnectionState.CONNECTED or _connection_state == ConnectionState.CONNECTING:
push_warning("已经在连接或已连接状态")
return
print("=== WebSocketManager 开始连接 ===")
_set_connection_state(ConnectionState.CONNECTING)
_clean_close = true
_reconnect_attempt = 0
_socket_client.connect_to_server(WEBSOCKET_URL)
# 断开 WebSocket 连接
func disconnect_websocket() -> void:
print("=== WebSocketManager 断开连接 ===")
_clean_close = true
# 停止重连定时器
_reconnect_timer.stop()
# 断开客户端
_socket_client.disconnect_from_server()
_set_connection_state(ConnectionState.DISCONNECTED)
# 检查 WebSocket 是否已连接
#
# 返回值:
# bool - WebSocket 是否已连接
func is_websocket_connected() -> bool:
return _connection_state == ConnectionState.CONNECTED
# 获取当前连接状态
#
# 返回值:
# ConnectionState - 当前连接状态
func get_connection_state() -> ConnectionState:
return _connection_state
# ============================================================================
# 公共 API - 自动重连
# ============================================================================
# 启用/禁用自动重连
#
# 参数:
# enabled: bool - 是否启用自动重连
# max_attempts: int - 最大重连次数(默认 5
# base_delay: float - 基础重连延迟,秒(默认 3.0
#
# 使用示例:
# WebSocketManager.enable_auto_reconnect(true, 5, 3.0)
func enable_auto_reconnect(enabled: bool, max_attempts: int = DEFAULT_MAX_RECONNECT_ATTEMPTS, base_delay: float = DEFAULT_RECONNECT_BASE_DELAY) -> void:
_auto_reconnect_enabled = enabled
_max_reconnect_attempts = max_attempts
_reconnect_base_delay = base_delay
print("自动重连: ", "启用" if enabled else "禁用")
print("最大重连次数: ", _max_reconnect_attempts)
print("基础重连延迟: ", _reconnect_base_delay, "")
# 获取 Socket.IO 客户端
#
# 返回值:
# SocketIOClient - Socket.IO 客户端实例
#
# 使用示例:
# var socket = WebSocketManager.get_socket_client()
# socket.emit("chat", {"t": "chat", "content": "Hello"})
func get_socket_client() -> SocketIOClient:
return _socket_client
# ============================================================================
# 内部方法 - 连接状态管理
# ============================================================================
# 设置连接状态
func _set_connection_state(new_state: ConnectionState) -> void:
if _connection_state == new_state:
return
_connection_state = new_state
print("📡 连接状态变更: ", ConnectionState.keys()[new_state])
# 发射信号
connection_state_changed.emit(new_state)
# ============================================================================
# 内部方法 - Socket 事件处理
# ============================================================================
# Socket 连接成功处理
func _on_socket_connected() -> void:
print("✅ WebSocketManager: Socket 连接成功")
# 如果是重连,发射重连成功信号
if _connection_state == ConnectionState.RECONNECTING:
_reconnect_attempt = 0
reconnection_succeeded.emit()
print("🔄 重连成功")
_set_connection_state(ConnectionState.CONNECTED)
# Socket 连接断开处理
func _on_socket_disconnected(clean_close: bool) -> void:
print("🔌 WebSocketManager: Socket 连接断开")
print(" 正常关闭: ", clean_close)
_clean_close = clean_close
# 如果是异常断开且启用了自动重连
if not clean_close and _auto_reconnect_enabled:
connection_lost.emit()
_attempt_reconnect()
else:
_set_connection_state(ConnectionState.DISCONNECTED)
# Socket 错误处理
func _on_socket_error(error: String) -> void:
print("❌ WebSocketManager: Socket 错误 - ", error)
_set_connection_state(ConnectionState.ERROR)
# ============================================================================
# 内部方法 - 重连机制
# ============================================================================
# 设置重连定时器
func _setup_reconnect_timer() -> void:
_reconnect_timer = Timer.new()
_reconnect_timer.one_shot = true
_reconnect_timer.autostart = false
add_child(_reconnect_timer)
_reconnect_timer.timeout.connect(_on_reconnect_timeout)
# 尝试重连
func _attempt_reconnect() -> void:
# 检查是否超过最大重连次数
if _reconnect_attempt >= _max_reconnect_attempts:
print("❌ 达到最大重连次数 (", _max_reconnect_attempts, "),停止重连")
reconnection_failed.emit(_reconnect_attempt, _max_reconnect_attempts)
_set_connection_state(ConnectionState.ERROR)
return
_reconnect_attempt += 1
_set_connection_state(ConnectionState.RECONNECTING)
# 计算重连延迟(指数退避)
var delay := _calculate_reconnect_delay()
print("🔄 尝试重连 (", _reconnect_attempt, "/", _max_reconnect_attempts, ")")
print(" 延迟: ", delay, "")
# 启动重连定时器
_reconnect_timer.start(delay)
# 计算重连延迟(指数退避)
func _calculate_reconnect_delay() -> float:
# 指数退避: base_delay * 2^(attempt-1)
var delay: float = _reconnect_base_delay * pow(2.0, _reconnect_attempt - 1)
# 限制最大延迟
return min(delay, MAX_RECONNECT_DELAY)
# 重连定时器超时处理
func _on_reconnect_timeout() -> void:
print("⏰ 重连定时器超时,开始重连...")
_socket_client.connect_to_server(WEBSOCKET_URL)
# ============================================================================
# 工具方法
# ============================================================================
# 获取连接状态描述
#
# 返回值:
# String - 连接状态描述
func get_state_description() -> String:
match _connection_state:
ConnectionState.DISCONNECTED:
return "未连接"
ConnectionState.CONNECTING:
return "连接中"
ConnectionState.CONNECTED:
return "已连接"
ConnectionState.RECONNECTING:
return "重连中 (%d/%d)" % [_reconnect_attempt, _max_reconnect_attempts]
ConnectionState.ERROR:
return "错误"
_:
return "未知状态"
# 获取重连信息
#
# 返回值:
# Dictionary - 重连信息 {enabled, attempt, max_attempts, delay}
func get_reconnect_info() -> Dictionary:
return {
"enabled": _auto_reconnect_enabled,
"attempt": _reconnect_attempt,
"max_attempts": _max_reconnect_attempts,
"next_delay": _calculate_reconnect_delay() if _connection_state == ConnectionState.RECONNECTING else 0.0
}