673 lines
27 KiB
C#
673 lines
27 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Runtime.InteropServices;
|
||
using Logic.CrashSight;
|
||
using Logic.Pool;
|
||
using MemoryPack;
|
||
using Steamworks;
|
||
using TH1_Logic.Net;
|
||
using UnityEngine;
|
||
|
||
namespace TH1_Logic.Steam
|
||
{
|
||
public class SimpleP2P
|
||
{
|
||
public static SimpleP2P Instance { get; } = new SimpleP2P();
|
||
|
||
// 推荐的虚拟端口范围
|
||
private static readonly int TargetPort = 1214;
|
||
|
||
// 连接映射表:SteamID -> 连接句柄
|
||
private readonly Dictionary<CSteamID, HSteamNetConnection> _connections = new Dictionary<CSteamID, HSteamNetConnection>();
|
||
|
||
// 连接超时追踪
|
||
private readonly Dictionary<CSteamID, float> _connectionTimeouts = new Dictionary<CSteamID, float>();
|
||
private const float ConnectionTimeout = 30f; // 30秒超时
|
||
|
||
// 重连尝试计数
|
||
private readonly Dictionary<CSteamID, int> _retryCount = new Dictionary<CSteamID, int>();
|
||
private const int MaxRetryCount = 3;
|
||
|
||
// 监听套接字
|
||
private float _socketRecord;
|
||
private HSteamListenSocket _listenSocket;
|
||
|
||
// 回调
|
||
private Callback<SteamNetConnectionStatusChangedCallback_t> _cbConnectionStatusChanged;
|
||
private Callback<SteamNetworkingMessagesSessionRequest_t> _cbSessionRequest;
|
||
|
||
// 事件委托
|
||
public event Action<CSteamID> OnPeerConnectedEvent;
|
||
public event Action<CSteamID> OnPeerDisconnectedEvent;
|
||
public event Action<CSteamID, byte[]> OnMessageReceivedEvent;
|
||
public event Action<string> OnConnectionErrorEvent;
|
||
|
||
public bool IsInitialized => _listenSocket != HSteamListenSocket.Invalid;
|
||
|
||
// 初始化
|
||
public void Initialize()
|
||
{
|
||
_socketRecord = 3;
|
||
_listenSocket = HSteamListenSocket.Invalid;
|
||
|
||
_cbConnectionStatusChanged = Callback<SteamNetConnectionStatusChangedCallback_t>.Create(OnConnectionStatusChanged);
|
||
// 添加:注册 SteamNetworkingMessages 会话请求回调
|
||
_cbSessionRequest = Callback<SteamNetworkingMessagesSessionRequest_t>.Create(OnSessionRequest);
|
||
}
|
||
|
||
// 添加:处理 SteamNetworkingMessages 的会话请求
|
||
private void OnSessionRequest(SteamNetworkingMessagesSessionRequest_t callback)
|
||
{
|
||
var remoteSteamID = callback.m_identityRemote.GetSteamID();
|
||
LogSystem.LogInfo($"收到来自 {remoteSteamID} 的 NetworkingMessages 会话请求");
|
||
|
||
// 接受会话请求(必须调用,否则对方发送会失败)
|
||
SteamNetworkingMessages.AcceptSessionWithUser(ref callback.m_identityRemote);
|
||
LogSystem.LogInfo($"已接受来自 {remoteSteamID} 的会话");
|
||
}
|
||
|
||
// 创建监听套接字
|
||
private void CreateListenSocket()
|
||
{
|
||
ForceCleanupPort(TargetPort);
|
||
LogSystem.LogInfo($"尝试虚拟端口 {TargetPort}...");
|
||
_listenSocket = SteamNetworkingSockets.CreateListenSocketP2P(TargetPort, 0, null);
|
||
|
||
if (_listenSocket != HSteamListenSocket.Invalid)
|
||
{
|
||
LogSystem.LogInfo($"成功在虚拟端口 {TargetPort} 创建监听套接字: {_listenSocket}");
|
||
}
|
||
}
|
||
|
||
// 定时刷新套接字创建
|
||
private void RefreshListenSocket()
|
||
{
|
||
_socketRecord += Time.deltaTime;
|
||
if (_listenSocket == HSteamListenSocket.Invalid && _socketRecord > 3f)
|
||
{
|
||
_socketRecord = 0;
|
||
SteamNetworkingUtils.GetRelayNetworkStatus(out var relayStatus);
|
||
if (relayStatus.m_eAvail == ESteamNetworkingAvailability.k_ESteamNetworkingAvailability_Current)
|
||
{
|
||
CreateListenSocket();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ForceCleanupPort(int port)
|
||
{
|
||
LogSystem.LogInfo($"强制清理虚拟端口 {port}");
|
||
// 关闭所有现有连接
|
||
DisconnectAll();
|
||
// 关闭当前监听套接字
|
||
SteamNetworkingSockets.CloseListenSocket(_listenSocket);
|
||
_listenSocket = HSteamListenSocket.Invalid;
|
||
LogSystem.LogInfo("已关闭现有监听套接字");
|
||
|
||
// 强制清理特定端口的所有连接
|
||
SteamNetworkingSockets.RunCallbacks();
|
||
}
|
||
|
||
// 连接到指定玩家
|
||
public bool ConnectToPeer(CSteamID steamID)
|
||
{
|
||
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return false;
|
||
if (_connections.ContainsKey(steamID))
|
||
{
|
||
LogSystem.LogInfo($"Already connected to {steamID}");
|
||
return true;
|
||
}
|
||
|
||
// 先进行连接前检查
|
||
if (!PreConnectionCheck(steamID))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 创建连接配置
|
||
var options = new SteamNetworkingConfigValue_t[1];
|
||
options[0] = new SteamNetworkingConfigValue_t();
|
||
options[0].m_eValue = ESteamNetworkingConfigValue.k_ESteamNetworkingConfig_TimeoutInitial;
|
||
options[0].m_eDataType = ESteamNetworkingConfigDataType.k_ESteamNetworkingConfig_Int32;
|
||
options[0].m_val.m_int32 = 15000; // 15秒超时
|
||
|
||
// 创建到目标玩家的连接
|
||
var identity = new SteamNetworkingIdentity();
|
||
identity.SetSteamID(steamID);
|
||
|
||
var connection = SteamNetworkingSockets.ConnectP2P(ref identity, TargetPort, options.Length, options);
|
||
if (connection == HSteamNetConnection.Invalid)
|
||
{
|
||
OnConnectionErrorEvent?.Invoke($"Failed to connect to {steamID}");
|
||
return false;
|
||
}
|
||
|
||
_connections[steamID] = connection;
|
||
_connectionTimeouts[steamID] = Time.time + ConnectionTimeout;
|
||
LogSystem.LogInfo($"Connecting to peer: {steamID}");
|
||
DiagnoseNetworkStatus(steamID);
|
||
return true;
|
||
}
|
||
|
||
// 连接前检查
|
||
private bool PreConnectionCheck(CSteamID targetSteamID)
|
||
{
|
||
// 检查Steam是否已登录
|
||
if (!SteamUser.BLoggedOn())
|
||
{
|
||
LogSystem.LogError("Steam not logged in");
|
||
return false;
|
||
}
|
||
|
||
// 检查目标用户是否在线
|
||
var friendState = SteamFriends.GetFriendPersonaState(targetSteamID);
|
||
if (friendState == EPersonaState.k_EPersonaStateOffline)
|
||
{
|
||
LogSystem.LogWarning($"Target user {targetSteamID} appears offline");
|
||
}
|
||
|
||
// 检查当前lobby信息
|
||
LogSystem.LogInfo("Checking lobby status...");
|
||
|
||
return true;
|
||
}
|
||
|
||
private void DiagnoseNetworkStatus(CSteamID targetSteamID)
|
||
{
|
||
LogSystem.LogInfo("=== P2P 连接诊断 ===");
|
||
|
||
// Steam 状态
|
||
LogSystem.LogInfo($"Steam 登录状态: {SteamUser.BLoggedOn()}");
|
||
LogSystem.LogInfo($"本地 Steam ID: {SteamUser.GetSteamID()}");
|
||
|
||
// 目标用户状态
|
||
var friendState = SteamFriends.GetFriendPersonaState(targetSteamID);
|
||
LogSystem.LogInfo($"目标用户状态: {friendState}");
|
||
|
||
// 检查是否是好友
|
||
var relationShip = SteamFriends.GetFriendRelationship(targetSteamID);
|
||
LogSystem.LogInfo($"好友关系: {relationShip}");
|
||
|
||
// Steam 网络状态
|
||
SteamNetworkingUtils.GetRelayNetworkStatus(out var relayStatus);
|
||
LogSystem.LogInfo($"Steam 中继网络: {relayStatus.m_eAvail}");
|
||
LogSystem.LogInfo($"中继网络调试信息: {relayStatus.m_debugMsg}");
|
||
|
||
if (relayStatus.m_eAvail != ESteamNetworkingAvailability.k_ESteamNetworkingAvailability_Current)
|
||
{
|
||
LogSystem.LogWarning($"Steam 中继网络问题: {relayStatus.m_debugMsg}");
|
||
}
|
||
}
|
||
|
||
// 更新方法 - 需要在主循环中调用
|
||
public void Update()
|
||
{
|
||
RefreshListenSocket();
|
||
CheckConnectionTimeouts();
|
||
}
|
||
|
||
// 检查连接超时
|
||
private void CheckConnectionTimeouts()
|
||
{
|
||
var currentTime = Time.time;
|
||
var timeoutList = new List<CSteamID>();
|
||
|
||
foreach (var kvp in _connectionTimeouts)
|
||
{
|
||
if (currentTime > kvp.Value)
|
||
{
|
||
timeoutList.Add(kvp.Key);
|
||
}
|
||
}
|
||
|
||
foreach (var steamID in timeoutList)
|
||
{
|
||
LogSystem.LogError($"Connection to {steamID} timed out");
|
||
_connectionTimeouts.Remove(steamID);
|
||
|
||
if (_connections.TryGetValue(steamID, out var conn))
|
||
{
|
||
SteamNetworkingSockets.CloseConnection(conn, 0, "Connection timeout", false);
|
||
_connections.Remove(steamID);
|
||
}
|
||
|
||
OnConnectionErrorEvent?.Invoke($"Connection to {steamID} timed out");
|
||
}
|
||
}
|
||
|
||
// 断开与指定玩家的连接
|
||
public void DisconnectFromPeer(CSteamID steamID)
|
||
{
|
||
if (!_connections.TryGetValue(steamID, out var connection))
|
||
return;
|
||
|
||
SteamNetworkingSockets.CloseConnection(connection, 0, "Disconnected by user", false);
|
||
_connections.Remove(steamID);
|
||
_connectionTimeouts.Remove(steamID);
|
||
LogSystem.LogInfo($"Disconnected from peer: {steamID}");
|
||
}
|
||
|
||
// 断开所有连接
|
||
public void DisconnectAll()
|
||
{
|
||
foreach (var kvp in _connections)
|
||
{
|
||
SteamNetworkingSockets.CloseConnection(kvp.Value, 0, "Disconnecting all", false);
|
||
}
|
||
_connections.Clear();
|
||
_connectionTimeouts.Clear();
|
||
_retryCount.Clear();
|
||
LogSystem.LogInfo("Disconnected from all peers");
|
||
}
|
||
|
||
// 连接状态变化回调
|
||
private void OnConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t info)
|
||
{
|
||
var state = info.m_info.m_eState;
|
||
|
||
// 获取连接信息
|
||
SteamNetworkingSockets.GetConnectionInfo(info.m_hConn, out var connectionInfo);
|
||
var remote = connectionInfo.m_identityRemote.GetSteamID();
|
||
|
||
// 清除超时计时器(如果连接状态有变化)
|
||
if (_connectionTimeouts.ContainsKey(remote) &&
|
||
state != ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connecting)
|
||
{
|
||
_connectionTimeouts.Remove(remote);
|
||
}
|
||
|
||
// 记录详细的连接信息用于诊断
|
||
LogSystem.LogInfo($"Connection details - Remote: {remote}, State: {state}");
|
||
LogSystem.LogInfo($"End reason: {info.m_info.m_eEndReason}");
|
||
|
||
switch (state)
|
||
{
|
||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connecting:
|
||
LogSystem.LogInfo($"Connecting to {remote}...");
|
||
|
||
// 检查这是否是传入连接(对方主动连接我们)
|
||
// 如果我们的连接字典中没有这个连接,说明是对方主动连接的
|
||
if (!_connections.ContainsKey(remote) && info.m_info.m_hListenSocket != HSteamListenSocket.Invalid)
|
||
{
|
||
LogSystem.LogInfo($"检测到来自 {remote} 的传入连接请求");
|
||
// 检查是否应该接受这个连接
|
||
if (ShouldAcceptIncomingConnection(remote))
|
||
{
|
||
LogSystem.LogInfo($"接受来自 {remote} 的连接");
|
||
var result = SteamNetworkingSockets.AcceptConnection(info.m_hConn);
|
||
if (result != EResult.k_EResultOK)
|
||
{
|
||
LogSystem.LogError($"无法接受连接: {result}");
|
||
SteamNetworkingSockets.CloseConnection(info.m_hConn, 0, "Failed to accept", false);
|
||
return;
|
||
}
|
||
_connections[remote] = info.m_hConn;
|
||
}
|
||
else
|
||
{
|
||
LogSystem.LogInfo($"拒绝来自 {remote} 的连接");
|
||
SteamNetworkingSockets.CloseConnection(info.m_hConn, 0, "Connection rejected", false);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LogSystem.LogInfo($"这是我们主动发起的连接到 {remote}");
|
||
}
|
||
break;
|
||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_FindingRoute:
|
||
LogSystem.LogInfo($"Finding route to {remote}...");
|
||
// 这个状态通常意味着正在通过Steam中继寻找路由
|
||
LogSystem.LogInfo("正在通过Steam中继网络寻找连接路径...");
|
||
break;
|
||
|
||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connected:
|
||
LogSystem.LogInfo($"Successfully connected to {remote}");
|
||
if (!_connections.ContainsKey(remote))
|
||
{
|
||
_connections[remote] = info.m_hConn;
|
||
}
|
||
// 清除超时和重试计数
|
||
_connectionTimeouts.Remove(remote);
|
||
_retryCount.Remove(remote);
|
||
OnPeerConnectedEvent?.Invoke(remote);
|
||
break;
|
||
|
||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ClosedByPeer:
|
||
LogSystem.LogInfo($"Connection closed by peer: {remote}");
|
||
HandleDisconnection(remote, info.m_hConn);
|
||
break;
|
||
|
||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ProblemDetectedLocally:
|
||
LogSystem.LogWarning($"Connection problem detected locally: {remote}");
|
||
LogSystem.LogWarning($"Problem details: {info.m_info.m_szEndDebug}");
|
||
HandleDisconnection(remote, info.m_hConn);
|
||
break;
|
||
|
||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_None:
|
||
// 检查具体的失败原因
|
||
var endReason = info.m_info.m_eEndReason;
|
||
LogSystem.LogError($"Connection failed - Reason: {endReason}");
|
||
|
||
// 提供更详细的错误信息
|
||
switch (endReason)
|
||
{
|
||
case (int)ESteamNetConnectionEnd.k_ESteamNetConnectionEnd_Misc_Timeout:
|
||
LogSystem.LogError("连接超时 - 可能的原因:1.目标用户不在线 2.网络问题 3.防火墙阻止");
|
||
break;
|
||
case (int)ESteamNetConnectionEnd.k_ESteamNetConnectionEnd_Misc_InternalError:
|
||
LogSystem.LogError("内部错误 - Steam网络服务可能有问题");
|
||
break;
|
||
case (int)ESteamNetConnectionEnd.k_ESteamNetConnectionEnd_AppException_Generic:
|
||
LogSystem.LogError("应用程序异常 - 目标应用可能没有正确处理连接");
|
||
break;
|
||
case (int)ESteamNetConnectionEnd.k_ESteamNetConnectionEnd_Remote_Timeout:
|
||
LogSystem.LogError("远程超时 - 目标用户网络问题");
|
||
break;
|
||
default:
|
||
if (endReason >= 1000 && endReason < 2000)
|
||
{
|
||
LogSystem.LogError($"应用层拒绝连接 - 错误码: {endReason},可能原因:1.对方未创建监听套接字 2.对方主动拒绝 3.对方游戏未运行");
|
||
}
|
||
else
|
||
{
|
||
LogSystem.LogError($"未知连接失败原因: {endReason}");
|
||
}
|
||
break;
|
||
}
|
||
|
||
HandleDisconnection(remote, info.m_hConn);
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 检查是否应该接受这个连接
|
||
private bool ShouldAcceptIncomingConnection(CSteamID steamID)
|
||
{
|
||
// 基本检查:确保是有效的Steam ID
|
||
if (!steamID.IsValid())
|
||
{
|
||
LogSystem.LogWarning($"接收到无效的Steam ID连接请求: {steamID}");
|
||
return false;
|
||
}
|
||
|
||
// 检查是否超过最大连接数
|
||
if (_connections.Count >= 10) // 假设最大10个连接
|
||
{
|
||
LogSystem.LogWarning("已达到最大连接数,拒绝新连接");
|
||
return false;
|
||
}
|
||
|
||
// 检查是否是好友(可选)
|
||
var relationship = SteamFriends.GetFriendRelationship(steamID);
|
||
LogSystem.LogInfo($"连接请求来自: {steamID}, 关系: {relationship}");
|
||
|
||
return true; // 默认接受所有连接
|
||
}
|
||
|
||
// 处理断开连接
|
||
private void HandleDisconnection(CSteamID steamID, HSteamNetConnection connection)
|
||
{
|
||
if (_connections.ContainsKey(steamID))
|
||
{
|
||
_connections.Remove(steamID);
|
||
OnPeerDisconnectedEvent?.Invoke(steamID);
|
||
}
|
||
_connectionTimeouts.Remove(steamID);
|
||
SteamNetworkingSockets.CloseConnection(connection, 0, "", false);
|
||
}
|
||
|
||
// 发送消息到指定玩家
|
||
public bool SendTo(CSteamID target, byte[] data, bool reliable = true, bool ordered = true)
|
||
{
|
||
if (data == null || data.Length == 0)
|
||
{
|
||
LogSystem.LogWarning("Trying to send null or empty data");
|
||
return false;
|
||
}
|
||
|
||
if (!_connections.TryGetValue(target, out var conn))
|
||
{
|
||
LogSystem.LogWarning($"No connection to {target}");
|
||
return false;
|
||
}
|
||
|
||
// 可靠传输=8,不可靠传输=0
|
||
int flags = reliable ? 8 : 0;
|
||
// 如果需要有序传输 k_nSteamNetworkingSend_NoDelay (确保按序处理)
|
||
if (ordered) flags |= 1;
|
||
IntPtr ptr = IntPtr.Zero;
|
||
try
|
||
{
|
||
ptr = Marshal.AllocHGlobal(data.Length);
|
||
Marshal.Copy(data, 0, ptr, data.Length);
|
||
|
||
var result = SteamNetworkingSockets.SendMessageToConnection(conn, ptr, (uint)data.Length, flags, out _);
|
||
if (result != EResult.k_EResultOK)
|
||
{
|
||
LogSystem.LogError($"Failed to send message to {target}: {result}");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
LogSystem.LogError($"Exception while sending message: {e.Message}");
|
||
return false;
|
||
}
|
||
finally
|
||
{
|
||
if (ptr != IntPtr.Zero)
|
||
Marshal.FreeHGlobal(ptr);
|
||
}
|
||
}
|
||
|
||
// 发送消息到指定玩家
|
||
public bool SendToWithOutConnect(CSteamID target, byte[] data, bool reliable = true, bool ordered = true)
|
||
{
|
||
if (data == null || data.Length == 0)
|
||
{
|
||
LogSystem.LogWarning("Trying to send null or empty data");
|
||
return false;
|
||
}
|
||
|
||
// 创建目标身份标识
|
||
var identity = new SteamNetworkingIdentity();
|
||
identity.SetSteamID(target);
|
||
|
||
// 可靠传输=8,不可靠传输=0
|
||
int flags = reliable ? 8 : 0;
|
||
// 如果需要有序传输 k_nSteamNetworkingSend_NoDelay (确保按序处理)
|
||
if (ordered) flags |= 1;
|
||
IntPtr ptr = IntPtr.Zero;
|
||
try
|
||
{
|
||
ptr = Marshal.AllocHGlobal(data.Length);
|
||
Marshal.Copy(data, 0, ptr, data.Length);
|
||
|
||
var result = SteamNetworkingMessages.SendMessageToUser(ref identity, ptr, (uint)data.Length, flags, 0);
|
||
if (result != EResult.k_EResultOK)
|
||
{
|
||
LogSystem.LogError($"Failed to send message to {target}: {result}");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
LogSystem.LogError($"Exception while sending message: {e.Message}");
|
||
return false;
|
||
}
|
||
finally
|
||
{
|
||
if (ptr != IntPtr.Zero)
|
||
Marshal.FreeHGlobal(ptr);
|
||
}
|
||
}
|
||
|
||
// 广播消息给所有连接的玩家
|
||
public void Broadcast(byte[] data, bool reliable = true)
|
||
{
|
||
foreach (var steamID in _connections.Keys)
|
||
{
|
||
SendTo(steamID, data, reliable);
|
||
}
|
||
}
|
||
|
||
// 轮询接收消息
|
||
public void PollMessages()
|
||
{
|
||
using var pooled = THCollectionPool.GetListHandle<CSteamID>(out var peers);
|
||
peers.AddRange(_connections.Keys);
|
||
|
||
// 使用快照遍历,避免处理消息时修改 _connections 导致枚举器失效
|
||
for (int i = 0; i < peers.Count; i++)
|
||
{
|
||
var steamID = peers[i];
|
||
if (!_connections.TryGetValue(steamID, out var connection))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
PollMessagesForConnection(steamID, connection);
|
||
}
|
||
|
||
PollInviteMessages();
|
||
}
|
||
|
||
// 为特定连接轮询消息
|
||
private void PollMessagesForConnection(CSteamID steamID, HSteamNetConnection connection)
|
||
{
|
||
IntPtr[] messages = new IntPtr[32]; // 一次最多处理32条消息
|
||
|
||
int messageCount = SteamNetworkingSockets.ReceiveMessagesOnConnection(connection, messages, 32);
|
||
|
||
for (int i = 0; i < messageCount; i++)
|
||
{
|
||
var messagePtr = messages[i];
|
||
if (messagePtr == IntPtr.Zero) continue;
|
||
|
||
// try
|
||
// {
|
||
// // 获取消息结构
|
||
// var message = Marshal.PtrToStructure<SteamNetworkingMessage_t>(messagePtr);
|
||
//
|
||
// // 复制数据
|
||
// byte[] data = new byte[message.m_cbSize];
|
||
// Marshal.Copy(message.m_pData, data, 0, message.m_cbSize);
|
||
//
|
||
// // 触发接收事件
|
||
// GameNetReceiver.Instance.OnMessageReceived(data);
|
||
// }
|
||
// catch (Exception e)
|
||
// {
|
||
// LogSystem.LogError($"Error processing message from {steamID}: {e.Message}");
|
||
// }
|
||
// finally
|
||
// {
|
||
// // 释放消息 - 这是关键,必须释放消息内存
|
||
// SteamNetworkingMessage_t.Release(messagePtr);
|
||
// }
|
||
|
||
// 获取消息结构
|
||
var message = Marshal.PtrToStructure<SteamNetworkingMessage_t>(messagePtr);
|
||
|
||
// 复制数据
|
||
byte[] data = new byte[message.m_cbSize];
|
||
Marshal.Copy(message.m_pData, data, 0, message.m_cbSize);
|
||
|
||
// 触发接收事件
|
||
GameNetReceiver.Instance.OnMessageReceived(data);
|
||
// 释放消息 - 这是关键,必须释放消息内存
|
||
SteamNetworkingMessage_t.Release(messagePtr);
|
||
}
|
||
}
|
||
|
||
// 非特定连接轮询消息
|
||
public void PollInviteMessages()
|
||
{
|
||
IntPtr[] messages = new IntPtr[10];
|
||
int messageCount = SteamNetworkingMessages.ReceiveMessagesOnChannel(0, messages, 10);
|
||
|
||
for (int i = 0; i < messageCount; i++)
|
||
{
|
||
var messagePtr = messages[i];
|
||
if (messagePtr == IntPtr.Zero) continue;
|
||
|
||
// 获取消息结构
|
||
var message = Marshal.PtrToStructure<SteamNetworkingMessage_t>(messagePtr);
|
||
|
||
// 复制数据
|
||
byte[] data = new byte[message.m_cbSize];
|
||
Marshal.Copy(message.m_pData, data, 0, message.m_cbSize);
|
||
|
||
// 触发接收事件
|
||
GameNetReceiver.Instance.OnMessageReceived(data);
|
||
|
||
// 释放消息 - 这是关键,必须释放消息内存
|
||
SteamNetworkingMessage_t.Release(messagePtr);
|
||
}
|
||
}
|
||
|
||
// 获取连接状态
|
||
public bool IsConnectedTo(CSteamID steamID)
|
||
{
|
||
return _connections.ContainsKey(steamID);
|
||
}
|
||
|
||
// 获取所有连接的玩家
|
||
public IEnumerable<CSteamID> GetConnectedPeers()
|
||
{
|
||
return _connections.Keys;
|
||
}
|
||
|
||
// 获取连接数量
|
||
public int GetConnectionCount()
|
||
{
|
||
return _connections.Count;
|
||
}
|
||
|
||
// 清理资源
|
||
public void Cleanup()
|
||
{
|
||
DisconnectAll();
|
||
|
||
if (_listenSocket != HSteamListenSocket.Invalid)
|
||
{
|
||
SteamNetworkingSockets.CloseListenSocket(_listenSocket);
|
||
_listenSocket = HSteamListenSocket.Invalid;
|
||
}
|
||
|
||
_cbConnectionStatusChanged?.Dispose();
|
||
_cbConnectionStatusChanged = null;
|
||
|
||
_cbSessionRequest?.Dispose();
|
||
_cbSessionRequest = null;
|
||
}
|
||
|
||
// 获取详细的连接信息用于调试
|
||
public void LogDetailedConnectionInfo(CSteamID steamID)
|
||
{
|
||
if (!_connections.TryGetValue(steamID, out var connection))
|
||
{
|
||
LogSystem.LogWarning($"No connection found for {steamID}");
|
||
return;
|
||
}
|
||
|
||
if (SteamNetworkingSockets.GetConnectionInfo(connection, out var info))
|
||
{
|
||
LogSystem.LogInfo("=== 详细连接信息 ===");
|
||
LogSystem.LogInfo($"连接状态: {info.m_eState}");
|
||
LogSystem.LogInfo($"结束原因: {info.m_eEndReason}");
|
||
LogSystem.LogInfo($"用户数据: {info.m_nUserData}");
|
||
LogSystem.LogInfo($"监听套接字: {info.m_hListenSocket}");
|
||
LogSystem.LogInfo($"远程地址: {info.m_addrRemote}");
|
||
LogSystem.LogInfo($"连接描述: {info.m_szConnectionDescription}");
|
||
LogSystem.LogInfo($"结束调试信息: {info.m_szEndDebug}");
|
||
LogSystem.LogInfo("===================");
|
||
}
|
||
}
|
||
}
|
||
}
|