Files
tcg-client/Assets/TcgEngine/Scripts/Network/NetworkMessaging.cs
2025-10-15 11:03:14 +08:00

480 lines
19 KiB
C#
Raw Permalink 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.
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;
}
}
}