创建新工程

This commit is contained in:
moyin
2025-12-05 19:00:14 +08:00
commit ff4fa5fffd
227 changed files with 32804 additions and 0 deletions

241
scripts/NetworkManager.gd Normal file
View File

@@ -0,0 +1,241 @@
extends Node
class_name NetworkManager
## 网络管理器
## 负责管理客户端与服务器的 WebSocket 连接
# 信号定义
signal connected_to_server()
signal disconnected_from_server()
signal connection_error(error: String)
signal message_received(message: Dictionary)
# 安全管理器
var security_manager: SecurityManager
var rate_limiter: RateLimiter
# WebSocket 客户端
var _client: WebSocketPeer = null
var _server_url: String = "ws://localhost:8080"
var _is_connected: bool = false
# 重连相关
var _reconnect_attempts: int = 0
var _max_reconnect_attempts: int = 5
var _reconnect_delay: float = 1.0
var _reconnect_timer: float = 0.0
var _should_reconnect: bool = false
# 连接超时相关
var _connection_timeout: float = 10.0
var _connection_timer: float = 0.0
var _is_connecting: bool = false
func _ready():
"""初始化网络管理器"""
# 使用默认网络设置避免GameConfig依赖
_max_reconnect_attempts = 3
_reconnect_delay = 1.0
_connection_timeout = 10.0
# 初始化安全组件
security_manager = SecurityManager.new()
add_child(security_manager)
rate_limiter = RateLimiter.new()
add_child(rate_limiter)
print("[NETWORK] NetworkManager initialized")
func connect_to_server(url: String = "") -> void:
"""连接到服务器"""
if not url.is_empty():
_server_url = url
print("[NETWORK] Connecting to server: ", _server_url)
# 如果已经在连接中,先断开
if _is_connecting:
disconnect_from_server()
_client = WebSocketPeer.new()
var err = _client.connect_to_url(_server_url)
if err != OK:
var error_msg = "连接失败: " + str(err)
print("[NETWORK] Failed to connect: ", err)
connection_error.emit(error_msg)
return
# 开始连接超时计时
_is_connecting = true
_connection_timer = _connection_timeout
print("[NETWORK] Connection initiated (timeout: ", _connection_timeout, "s)")
func disconnect_from_server() -> void:
"""断开服务器连接"""
if _client:
_client.close()
_client = null
_is_connected = false
_is_connecting = false
_connection_timer = 0.0
print("Disconnected from server")
disconnected_from_server.emit()
func send_message(message: Dictionary) -> void:
"""发送消息到服务器(使用消息协议)"""
if not _is_connected or not _client:
print("Cannot send message: not connected")
return
# 速率限制检查
var client_id = "local_client" # 本地客户端标识
if not rate_limiter.is_message_allowed(client_id):
print("[WARNING] [NETWORK] Message blocked by rate limiter")
return
# 安全验证消息格式
if not SecurityManager.validate_message_format(message):
print("[ERROR] [NETWORK] Invalid message format blocked: ", message.get("type", "unknown"))
return
# 使用 MessageProtocol 序列化
var json_string = MessageProtocol.serialize(message)
_client.send_text(json_string)
print("Sent message: ", message.get("type", "unknown"))
func send_typed_message(type: MessageProtocol.MessageType, data: Dictionary = {}) -> void:
"""发送指定类型的消息"""
var message = MessageProtocol.create_message(type, data)
send_message(message)
func is_server_connected() -> bool:
"""检查是否已连接到服务器"""
return _is_connected
func _process(delta):
"""处理网络消息和重连逻辑"""
# 处理重连计时器
if _should_reconnect and _reconnect_timer > 0:
_reconnect_timer -= delta
if _reconnect_timer <= 0:
_attempt_reconnect()
# 处理连接超时
if _is_connecting and _connection_timer > 0:
_connection_timer -= delta
if _connection_timer <= 0:
_handle_connection_timeout()
return
if not _client:
return
_client.poll()
var state = _client.get_ready_state()
# 检查连接状态
if state == WebSocketPeer.STATE_OPEN:
if not _is_connected:
_is_connected = true
_is_connecting = false # 连接成功,停止超时计时
_connection_timer = 0.0
_reconnect_attempts = 0 # 重置重连计数
_should_reconnect = false
print("Connected to server!")
connected_to_server.emit()
# 接收消息
while _client.get_available_packet_count() > 0:
var packet = _client.get_packet()
var json_string = packet.get_string_from_utf8()
# 检查消息长度防止DoS攻击
if json_string.length() > 10000: # 10KB限制
print("[ERROR] [NETWORK] Message too large, potential DoS attack. Size: ", json_string.length())
continue
# 使用 MessageProtocol 反序列化
var message = MessageProtocol.deserialize(json_string)
if not message.is_empty():
# 验证消息格式(基础验证)
if MessageProtocol.validate_message(message):
# 安全验证消息格式(增强验证)
if SecurityManager.validate_message_format(message):
print("Received message: ", message.get("type", "unknown"))
message_received.emit(message)
else:
print("[ERROR] [NETWORK] Security validation failed for message: ", message.get("type", "unknown"))
else:
print("[ERROR] [NETWORK] Invalid message format: ", json_string)
else:
print("[ERROR] [NETWORK] Failed to parse message: ", json_string)
elif state == WebSocketPeer.STATE_CLOSING:
pass
elif state == WebSocketPeer.STATE_CLOSED:
if _is_connected:
_is_connected = false
print("Connection closed")
disconnected_from_server.emit()
# 触发重连
_trigger_reconnect()
elif _is_connecting:
# 连接过程中关闭,可能是连接失败
_handle_connection_failure()
_client = null
func _trigger_reconnect() -> void:
"""触发重连逻辑"""
if _reconnect_attempts < _max_reconnect_attempts:
_should_reconnect = true
# 指数退避1秒、2秒、4秒
_reconnect_timer = _reconnect_delay * pow(2, _reconnect_attempts)
print("Will attempt reconnect in ", _reconnect_timer, " seconds (attempt ", _reconnect_attempts + 1, "/", _max_reconnect_attempts, ")")
else:
print("Max reconnect attempts reached")
connection_error.emit("Failed to reconnect after " + str(_max_reconnect_attempts) + " attempts")
func _attempt_reconnect() -> void:
"""尝试重新连接"""
_reconnect_attempts += 1
print("Attempting to reconnect... (attempt ", _reconnect_attempts, "/", _max_reconnect_attempts, ")")
connect_to_server()
func reset_reconnect() -> void:
"""重置重连状态"""
_reconnect_attempts = 0
_should_reconnect = false
_reconnect_timer = 0.0
func _handle_connection_timeout() -> void:
"""处理连接超时"""
print("[ERROR] [NETWORK] Connection timeout after ", _connection_timeout, " seconds")
_is_connecting = false
_connection_timer = 0.0
# 关闭WebSocketPeer连接
if _client:
_client.close()
_client = null
connection_error.emit("连接超时:无法连接到服务器,请检查服务器是否启动")
func _handle_connection_failure() -> void:
"""处理连接失败"""
print("[ERROR] [NETWORK] Connection failed during handshake")
_is_connecting = false
_connection_timer = 0.0
connection_error.emit("连接失败:服务器拒绝连接或服务器未启动")
func set_connection_timeout(timeout: float) -> void:
"""设置连接超时时间"""
_connection_timeout = timeout
func get_connection_timeout() -> float:
"""获取连接超时时间"""
return _connection_timeout