fix:修复重连状态与认证流程关键缺陷

This commit is contained in:
2026-03-10 16:17:10 +08:00
parent 88a8eaad02
commit d96abbb8b9
6 changed files with 133 additions and 42 deletions

View File

@@ -102,6 +102,7 @@ var _game_token: String = "" # @deprecated 使用 _access_token 替代
# 初始化管理器
func _init() -> void:
_load_auth_data()
_connect_network_signals()
# 清理资源
func cleanup() -> void:
@@ -110,6 +111,8 @@ func cleanup() -> void:
NetworkManager.cancel_request(request_id)
active_request_ids.clear()
_disconnect_network_signals()
# ============ Token 管理 ============
# 保存 Token 到内存
@@ -675,7 +678,7 @@ func _on_send_login_code_response(success: bool, data: Dictionary, error_info: D
func _on_forgot_password_response(success: bool, data: Dictionary, error_info: Dictionary):
button_state_changed.emit("forgot_password_btn", false, "忘记密码")
var result = ResponseHandler.handle_send_login_code_response(success, data, error_info)
var result = ResponseHandler.handle_forgot_password_response(success, data, error_info)
if result.should_show_toast:
show_toast_message.emit(result.message, result.success)
@@ -714,10 +717,10 @@ func _can_send_verification_code(email: String) -> bool:
if not email_data.sent:
return true
var current_time = Time.get_time_dict_from_system()
var current_timestamp = current_time.hour * 3600 + current_time.minute * 60 + current_time.second
var current_timestamp: int = int(Time.get_unix_time_from_system())
var sent_timestamp: int = int(email_data.get("time", 0))
return (current_timestamp - email_data.time) >= code_cooldown
return float(current_timestamp - sent_timestamp) >= code_cooldown
# 获取剩余冷却时间
func get_remaining_cooldown_time(email: String) -> int:
@@ -725,15 +728,15 @@ func get_remaining_cooldown_time(email: String) -> int:
return 0
var email_data = verification_codes_sent[email]
var current_time = Time.get_time_dict_from_system()
var current_timestamp = current_time.hour * 3600 + current_time.minute * 60 + current_time.second
var current_timestamp: int = int(Time.get_unix_time_from_system())
var sent_timestamp: int = int(email_data.get("time", 0))
var remaining: int = int(code_cooldown - float(current_timestamp - sent_timestamp))
return int(code_cooldown - (current_timestamp - email_data.time))
return maxi(0, remaining)
# 记录验证码发送状态
func _record_verification_code_sent(email: String):
var current_time = Time.get_time_dict_from_system()
var current_timestamp = current_time.hour * 3600 + current_time.minute * 60 + current_time.second
var current_timestamp: int = int(Time.get_unix_time_from_system())
if not verification_codes_sent.has(email):
verification_codes_sent[email] = {}
@@ -758,6 +761,30 @@ func _has_sent_verification_code(email: String) -> bool:
func _is_valid_identifier(identifier: String) -> bool:
return StringUtils.is_valid_email(identifier) or _is_valid_phone(identifier)
# 连接/断开 NetworkManager 请求信号,用于回收 active_request_ids
func _connect_network_signals() -> void:
if not NetworkManager.request_completed.is_connected(_on_network_request_completed):
NetworkManager.request_completed.connect(_on_network_request_completed)
if not NetworkManager.request_failed.is_connected(_on_network_request_failed):
NetworkManager.request_failed.connect(_on_network_request_failed)
func _disconnect_network_signals() -> void:
if NetworkManager.request_completed.is_connected(_on_network_request_completed):
NetworkManager.request_completed.disconnect(_on_network_request_completed)
if NetworkManager.request_failed.is_connected(_on_network_request_failed):
NetworkManager.request_failed.disconnect(_on_network_request_failed)
func _on_network_request_completed(request_id: String, _success: bool, _data: Dictionary) -> void:
_remove_active_request_id(request_id)
func _on_network_request_failed(request_id: String, _error_type: String, _message: String) -> void:
_remove_active_request_id(request_id)
func _remove_active_request_id(request_id: String) -> void:
var index: int = active_request_ids.find(request_id)
if index != -1:
active_request_ids.remove_at(index)
# 验证手机号格式
func _is_valid_phone(phone: String) -> bool:
var regex = RegEx.new()

View File

@@ -44,12 +44,6 @@ var _next_spawn_name: String = "" # 下一个场景的出生
# 便于统一管理和修改场景路径
var scene_paths: Dictionary = {
"main": "res://scenes/MainScene.tscn", # 主场景 - 游戏入口
"auth": "res://scenes/ui/LoginWindow.tscn", # 认证场景 - 登录窗口
"game": "res://scenes/maps/game_scene.tscn", # 游戏场景 - 主要游戏内容
"battle": "res://scenes/maps/battle_scene.tscn", # 战斗场景 - 战斗系统
"inventory": "res://scenes/ui/InventoryWindow.tscn", # 背包界面
"shop": "res://scenes/ui/ShopWindow.tscn", # 商店界面
"settings": "res://scenes/ui/SettingsWindow.tscn", # 设置界面
"square": "res://scenes/Maps/square.tscn", # 广场地图
"room": "res://scenes/Maps/room.tscn", # 房间地图
"fountain": "res://scenes/Maps/fountain.tscn", # 喷泉地图

View File

@@ -106,6 +106,9 @@ var _reconnect_timer: Timer = Timer.new()
# 是否为正常关闭(非异常断开)
var _clean_close: bool = true
# 当前 CLOSED 状态是否已经处理过(防止每帧重复处理 close 事件)
var _closed_state_handled: bool = false
# 心跳定时器
var _heartbeat_timer: Timer = Timer.new()
@@ -163,14 +166,20 @@ func _exit_tree() -> void:
# ============================================================================
# 连接到游戏服务器
func connect_to_game_server() -> void:
func connect_to_game_server(is_reconnect_attempt: bool = false) -> void:
if _connection_state == ConnectionState.CONNECTED or _connection_state == ConnectionState.CONNECTING:
push_warning("已经在连接或已连接状态")
return
_set_connection_state(ConnectionState.CONNECTING)
if is_reconnect_attempt:
_set_connection_state(ConnectionState.RECONNECTING)
else:
_set_connection_state(ConnectionState.CONNECTING)
_clean_close = true
_reconnect_attempt = 0
_closed_state_handled = false
# 仅在首次/手动连接时重置重连计数,重连流程保持累计尝试次数
if not is_reconnect_attempt:
_reconnect_attempt = 0
var err: Error = _websocket_peer.connect_to_url(WEBSOCKET_URL)
if err != OK:
@@ -295,23 +304,40 @@ func _check_websocket_state() -> void:
match state:
WebSocketPeer.STATE_CONNECTING:
_closed_state_handled = false
# 正在连接
if _connection_state != ConnectionState.CONNECTING and _connection_state != ConnectionState.RECONNECTING:
_set_connection_state(ConnectionState.CONNECTING)
WebSocketPeer.STATE_OPEN:
_closed_state_handled = false
# 连接成功
if _connection_state != ConnectionState.CONNECTED:
_on_websocket_connected()
WebSocketPeer.STATE_CLOSING:
_closed_state_handled = false
# 正在关闭
pass
WebSocketPeer.STATE_CLOSED:
# 连接关闭
var code: int = _websocket_peer.get_close_code()
_on_websocket_closed(code != 0) # code=0 表示正常关闭
if _closed_state_handled:
return
_closed_state_handled = true
# 仅在连接生命周期中发生的关闭才触发关闭处理
var should_handle_close: bool = (
_connection_state == ConnectionState.CONNECTED
or _connection_state == ConnectionState.CONNECTING
or _connection_state == ConnectionState.RECONNECTING
)
if should_handle_close:
var close_code: int = _websocket_peer.get_close_code()
_on_websocket_closed(_is_clean_close_code(close_code))
# WebSocket 连接成功处理
func _on_websocket_connected() -> void:
@@ -333,6 +359,11 @@ func _on_websocket_closed(clean_close: bool) -> void:
else:
_set_connection_state(ConnectionState.DISCONNECTED)
# 判断关闭码是否为干净关闭
# Godot 中 close_code == -1 表示非干净关闭(异常断开)
func _is_clean_close_code(close_code: int) -> bool:
return close_code != -1
# ============================================================================
# 内部方法 - 重连机制
# ============================================================================
@@ -375,7 +406,7 @@ func _calculate_reconnect_delay() -> float:
# 重连定时器超时处理
func _on_reconnect_timeout() -> void:
_clean_close = false
connect_to_game_server()
connect_to_game_server(true)
# ============================================================================
# 内部方法 - 心跳机制