480 lines
19 KiB
C#
480 lines
19 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using Unity.Collections;
|
||
using Unity.Netcode;
|
||
using UnityEngine;
|
||
|
||
namespace TcgEngine
|
||
{
|
||
/// <summary>
|
||
/// 发送和接收网络消息的基础类
|
||
/// </summary>
|
||
|
||
public class NetworkMessaging
|
||
{
|
||
private TcgNetwork network;
|
||
|
||
private Dictionary<string, System.Action<ulong, FastBufferReader>> msg_dict = new Dictionary<string, System.Action<ulong, FastBufferReader>>();
|
||
|
||
public NetworkMessaging(TcgNetwork network)
|
||
{
|
||
this.network = network;
|
||
network.onConnect += OnConnect;
|
||
}
|
||
|
||
private void OnConnect()
|
||
{
|
||
foreach (KeyValuePair<string, System.Action<ulong, FastBufferReader>> pair in msg_dict)
|
||
{
|
||
RegisterNetMsg(pair.Key, pair.Value);
|
||
}
|
||
}
|
||
|
||
public void ListenMsg(string type, System.Action<ulong, FastBufferReader> callback)
|
||
{
|
||
msg_dict[type] = callback;
|
||
RegisterNetMsg(type, callback);
|
||
}
|
||
|
||
public void UnListenMsg(string type)
|
||
{
|
||
msg_dict.Remove(type);
|
||
|
||
if (network.NetworkManager.CustomMessagingManager != null)
|
||
network.NetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler(type);
|
||
}
|
||
|
||
private void RegisterNetMsg(string type, System.Action<ulong, FastBufferReader> callback)
|
||
{
|
||
if (IsOnline)
|
||
{
|
||
network.NetworkManager.CustomMessagingManager.RegisterNamedMessageHandler(type, (ulong client_id, FastBufferReader reader) =>
|
||
{
|
||
ReceiveNetMessage(type, client_id, reader);
|
||
});
|
||
}
|
||
}
|
||
|
||
private void ReceiveNetMessage(string type, ulong client_id, FastBufferReader reader)
|
||
{
|
||
bool valid = msg_dict.TryGetValue(type, out System.Action<ulong, FastBufferReader> callback);
|
||
if (valid && IsOnline)
|
||
{
|
||
callback(client_id, reader);
|
||
}
|
||
}
|
||
|
||
//--------- Send Single ----------
|
||
|
||
public void SendEmpty(string type, ulong target, NetworkDelivery delivery)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(0, Allocator.Temp);
|
||
Send(type, target, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
|
||
public void SendBytes(string type, ulong target, byte[] msg, NetworkDelivery delivery)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp);
|
||
writer.WriteBytesSafe(msg, msg.Length);
|
||
Send(type, target, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
|
||
public void SendString(string type, ulong target, string msg, NetworkDelivery delivery)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||
writer.WriteValueSafe(msg);
|
||
Send(type, target, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
|
||
public void SendInt(string type, ulong target, int data, NetworkDelivery delivery)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
Send(type, target, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
|
||
public void SendUInt64(string type, ulong target, ulong data, NetworkDelivery delivery)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(8, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
Send(type, target, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
|
||
public void SendFloat(string type, ulong target, float data, NetworkDelivery delivery)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
Send(type, target, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
|
||
public void SendObject<T>(string type, ulong target, T data, NetworkDelivery delivery) where T : INetworkSerializable
|
||
{
|
||
Debug.Log("=== SendObject 开始 ===");
|
||
Debug.Log("SendObject 步骤1: 参数检查 - type: " + type + " target: " + target + " data: " + data + " delivery: " + delivery);
|
||
|
||
// 增加初始缓冲区大小,特别是对于包含字符串的对象
|
||
int initialSize = 1024; // 从 256 增加到 1024
|
||
Debug.Log("SendObject 步骤2: 创建 FastBufferWriter,初始大小: " + initialSize + ", 最大大小: " + TcgNetwork.MsgSizeMax);
|
||
FastBufferWriter writer = new FastBufferWriter(initialSize, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||
|
||
try
|
||
{
|
||
Debug.Log("SendObject 步骤3: 序列化数据到 writer");
|
||
writer.WriteNetworkSerializable(data);
|
||
Debug.Log("SendObject 步骤4: 序列化完成,writer 当前位置: " + writer.Position + ", 总长度: " + writer.Length);
|
||
|
||
// 检查是否超出最大大小
|
||
if (writer.Length > TcgNetwork.MsgSizeMax)
|
||
{
|
||
Debug.LogError("SendObject 错误: 消息大小 " + writer.Length + " 超出最大限制 " + TcgNetwork.MsgSizeMax);
|
||
writer.Dispose();
|
||
return;
|
||
}
|
||
|
||
Debug.Log("SendObject 步骤5: 调用 Send 方法");
|
||
Send(type, target, writer, delivery);
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
Debug.LogError("SendObject 序列化失败: " + e.Message);
|
||
}
|
||
finally
|
||
{
|
||
Debug.Log("SendObject 步骤6: 释放 writer 资源");
|
||
writer.Dispose();
|
||
}
|
||
Debug.Log("=== SendObject 结束 ===");
|
||
}
|
||
|
||
//--------- Send Multi ----------
|
||
|
||
public void SendEmpty(string type, IReadOnlyList<ulong> targets, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(0, Allocator.Temp);
|
||
Send(type, targets, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendBytes(string type, IReadOnlyList<ulong> targets, byte[] msg, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp);
|
||
writer.WriteBytesSafe(msg, msg.Length);
|
||
Send(type, targets, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendString(string type, IReadOnlyList<ulong> targets, string msg, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||
writer.WriteValueSafe(msg);
|
||
Send(type, targets, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendInt(string type, IReadOnlyList<ulong> targets, int data, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
Send(type, targets, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendUInt64(string type, IReadOnlyList<ulong> targets, ulong data, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(8, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
Send(type, targets, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendFloat(string type, IReadOnlyList<ulong> targets, float data, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
Send(type, targets, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendObject<T>(string type, IReadOnlyList<ulong> targets, T data, NetworkDelivery delivery) where T : INetworkSerializable
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(1024, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||
writer.WriteNetworkSerializable(data);
|
||
Send(type, targets, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
//--------- Send All ----------
|
||
|
||
public void SendEmptyAll(string type, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(0, Allocator.Temp);
|
||
SendAll(type, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendStringAll(string type, string msg, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||
writer.WriteValueSafe(msg);
|
||
SendAll(type, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendIntAll(string type, int data, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
SendAll(type, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendUInt64All(string type, ulong data, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(8, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
SendAll(type, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendFloatAll(string type, float data, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||
writer.WriteValueSafe(data);
|
||
SendAll(type, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendBytesAll(string type, byte[] msg, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp);
|
||
writer.WriteBytesSafe(msg, msg.Length);
|
||
SendAll(type, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
public void SendObjectAll<T>(string type, T data, NetworkDelivery delivery) where T : INetworkSerializable
|
||
{
|
||
if (IsServer)
|
||
{
|
||
FastBufferWriter writer = new FastBufferWriter(1024, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||
writer.WriteNetworkSerializable(data);
|
||
SendAll(type, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
//-------- Generic Send ----------
|
||
|
||
public void Send(string type, ulong target, FastBufferWriter writer, NetworkDelivery delivery)
|
||
{
|
||
Debug.Log("=== Send 方法开始 ===");
|
||
Debug.Log("Send 步骤1: 检查网络状态 - IsOnline: " + IsOnline + ", target: " + target + ", ClientID: " + ClientID);
|
||
|
||
if (IsOnline)
|
||
{
|
||
Debug.Log("Send 步骤2: 在线模式,调用 SendOnline");
|
||
SendOnline(type, target, writer, delivery);
|
||
}
|
||
else if (target == ClientID && ClientID != 0)
|
||
{
|
||
Debug.Log("Send 步骤2: 离线模式且目标是自己,调用 SendOffline");
|
||
SendOffline(type, writer);
|
||
}
|
||
else
|
||
{
|
||
Debug.Log("Send 步骤2: 离线模式但目标不是自己,跳过发送");
|
||
}
|
||
Debug.Log("=== Send 方法结束 ===");
|
||
}
|
||
|
||
public void Send(string type, IReadOnlyList<ulong> targets, FastBufferWriter writer, NetworkDelivery delivery)
|
||
{
|
||
if (IsOnline)
|
||
SendOnline(type, targets, writer, delivery);
|
||
else if (Contains(targets, ClientID))
|
||
SendOffline(type, writer);
|
||
}
|
||
|
||
public void SendAll(string type, FastBufferWriter writer, NetworkDelivery delivery)
|
||
{
|
||
Send(type, ClientList, writer, delivery);
|
||
}
|
||
|
||
private void SendOnline(string type, ulong target, FastBufferWriter writer, NetworkDelivery delivery)
|
||
{
|
||
Debug.Log("=== SendOnline 方法开始 ===");
|
||
Debug.Log("SendOnline 步骤1: 参数验证 - type: " + type + " target: " + target + " delivery: " + delivery);
|
||
Debug.Log("SendOnline 步骤2: 检查 NetworkManager 状态 - 是否为 null: " + (network.NetworkManager == null));
|
||
Debug.Log("SendOnline 步骤3: 检查 CustomMessagingManager 状态 - 是否为 null: " + (network.NetworkManager?.CustomMessagingManager == null));
|
||
Debug.Log("SendOnline 步骤4: 准备发送消息,writer 长度: " + writer.Length);
|
||
|
||
try
|
||
{
|
||
Debug.Log("SendOnline 步骤5: 调用 Unity Netcode 的 SendNamedMessage");
|
||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, target, writer, delivery);
|
||
Debug.Log("SendOnline 步骤6: 消息发送成功");
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
Debug.LogError("SendOnline 步骤6: 消息发送失败 - " + e.Message);
|
||
}
|
||
Debug.Log("=== SendOnline 方法结束 ===");
|
||
}
|
||
|
||
private void SendOnline(string type, IReadOnlyList<ulong> targets, FastBufferWriter writer, NetworkDelivery delivery)
|
||
{
|
||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, targets, writer, delivery);
|
||
}
|
||
|
||
//Just copy the message from writer to reader locally and call the callback immediately
|
||
private void SendOffline(string type, FastBufferWriter writer)
|
||
{
|
||
Debug.Log("=== SendOffline 方法开始 ===");
|
||
Debug.Log("SendOffline 步骤1: 查找消息类型 '" + type + "' 的监听器");
|
||
bool found = msg_dict.TryGetValue(type, out System.Action<ulong, FastBufferReader> callback);
|
||
Debug.Log("SendOffline 步骤2: 监听器查找结果 - 找到: " + found);
|
||
|
||
if (found)
|
||
{
|
||
Debug.Log("SendOffline 步骤3: 创建 FastBufferReader 从 writer 复制数据");
|
||
FastBufferReader reader = new FastBufferReader(writer, Allocator.Temp);
|
||
Debug.Log("SendOffline 步骤4: 调用回调函数,ClientID: " + ClientID + ", reader 长度: " + reader.Length);
|
||
callback?.Invoke(ClientID, reader);
|
||
Debug.Log("SendOffline 步骤5: 释放 reader 资源");
|
||
reader.Dispose();
|
||
Debug.Log("SendOffline 步骤6: 离线消息处理完成");
|
||
}
|
||
else
|
||
{
|
||
Debug.Log("SendOffline 步骤3: 未找到消息类型 '" + type + "' 的监听器,跳过处理");
|
||
}
|
||
Debug.Log("=== SendOffline 方法结束 ===");
|
||
}
|
||
|
||
//--------- Forward msgs ----------
|
||
|
||
//Forward a client message to one client
|
||
//Make sure you finished reading the reader before forwarding
|
||
public void Forward(string type, ulong target, FastBufferReader reader, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer && IsOnline)
|
||
{
|
||
reader.Seek(0); //Reset reader
|
||
reader.ReadValueSafe(out ulong header); //Ignore header
|
||
byte[] bytes = new byte[reader.Length - reader.Position];
|
||
reader.ReadBytesSafe(ref bytes, reader.Length - reader.Position);
|
||
FastBufferWriter writer = new FastBufferWriter(bytes.Length, Allocator.Temp);
|
||
writer.WriteBytesSafe(bytes, bytes.Length);
|
||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, target, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
//Forward a client message to all target clients
|
||
//Make sure you finished reading the reader before forwarding
|
||
public void Forward(string type, IReadOnlyList<ulong> targets, FastBufferReader reader, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer && IsOnline)
|
||
{
|
||
reader.Seek(0); //Reset reader
|
||
reader.ReadValueSafe(out ulong header); //Ignore header
|
||
byte[] bytes = new byte[reader.Length - reader.Position];
|
||
reader.ReadBytesSafe(ref bytes, reader.Length - reader.Position);
|
||
FastBufferWriter writer = new FastBufferWriter(bytes.Length, Allocator.Temp);
|
||
writer.WriteBytesSafe(bytes, bytes.Length);
|
||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, targets, writer, delivery);
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
//Forward a client message to all other clients (other than the source)
|
||
//Make sure you finished reading the reader before forwarding
|
||
public void ForwardAll(string type, ulong source_client, FastBufferReader reader, NetworkDelivery delivery)
|
||
{
|
||
if (IsServer && IsOnline)
|
||
{
|
||
reader.Seek(0); //Reset reader
|
||
reader.ReadValueSafe(out ulong header); //Ignore header
|
||
byte[] bytes = new byte[reader.Length - reader.Position];
|
||
reader.ReadBytesSafe(ref bytes, reader.Length - reader.Position);
|
||
FastBufferWriter writer = new FastBufferWriter(bytes.Length, Allocator.Temp);
|
||
writer.WriteBytesSafe(bytes, bytes.Length);
|
||
|
||
foreach (ulong client in ClientList)
|
||
{
|
||
if (client != source_client && client != ClientID)
|
||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, client, writer, delivery);
|
||
}
|
||
writer.Dispose();
|
||
}
|
||
}
|
||
|
||
private bool Contains(IReadOnlyList<ulong> list, ulong client_id)
|
||
{
|
||
foreach (ulong cid in list)
|
||
{
|
||
if (cid == client_id)
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public IReadOnlyList<ulong> ClientList { get { return network.GetClientsIds(); } }
|
||
public bool IsOnline { get { return network.IsOnline && network.ClientID != 0; } }
|
||
public bool IsServer { get { return network.IsServer; } }
|
||
public ulong ServerID { get { return network.ServerID; } }
|
||
public ulong ClientID { get { return network.ClientID; } }
|
||
|
||
|
||
public static NetworkMessaging Get()
|
||
{
|
||
return TcgNetwork.Get().Messaging;
|
||
}
|
||
}
|
||
}
|