[+] TEngineServer

[+] TEngineServer
This commit is contained in:
ALEXTANG
2023-07-13 17:17:26 +08:00
parent a69f53592e
commit 0c8f3a5f92
790 changed files with 52737 additions and 2533 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1d6d37d54409f584d95bcfea9b9345b3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 457e84e8ec81f254da550c11a78d4353
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
namespace TEngine.Core.Network
{
public enum NetworkProtocolType
{
None = 0,
KCP = 1,
TCP = 2
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74351b44f2b6d4a41969a8159e2808ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
namespace TEngine.Core.Network
{
public enum NetworkTarget
{
None = 0,
Outer = 1,
Inner = 2
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf647911052fccc40b1d4601ac423b5b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
namespace TEngine.Core.Network
{
public enum NetworkType
{
None = 0,
Client = 1,
Server = 2
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8841f1e5b0a30eb4cad8a4e0a099adc8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a19a0ba64b936934ba63f099234b941a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace TEngine.Core
{
public static class NetworkHelper
{
public static string[] GetAddressIPs()
{
var list = new List<string>();
foreach (var networkInterface in NetworkInterface.GetAllNetworkInterfaces())
{
if (networkInterface.NetworkInterfaceType != NetworkInterfaceType.Ethernet)
{
continue;
}
foreach (var add in networkInterface.GetIPProperties().UnicastAddresses)
{
list.Add(add.Address.ToString());
}
}
return list.ToArray();
}
public static IPEndPoint ToIPEndPoint(string host, int port)
{
return new IPEndPoint(IPAddress.Parse(host), port);
}
public static IPEndPoint ToIPEndPoint(string address)
{
var index = address.LastIndexOf(':');
var host = address.Substring(0, index);
var p = address.Substring(index + 1);
var port = int.Parse(p);
return ToIPEndPoint(host, port);
}
public static string IPEndPointToStr(this IPEndPoint self)
{
return $"{self.Address}:{self.Port}";
}
public static void SetSioUdpConnReset(Socket socket)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}
/*
目前这个问题只有Windows下才会出现。
服务器端在发送数据时捕获到了一个异常,
这个异常导致原因应该是远程客户端的UDP监听已停止导致数据发送出错。
按理说UDP是无连接的报这个异常是不合理的
这个异常让整UDP的服务监听也停止了。
这样就因为一个客户端的数据发送无法到达而导致了服务挂了,所有客户端都无法与服务器通信了
想详细了解看下https://blog.csdn.net/sunzhen6251/article/details/124168805*/
const uint IOC_IN = 0x80000000;
const uint IOC_VENDOR = 0x18000000;
const int SIO_UDP_CONNRESET = unchecked((int) (IOC_IN | IOC_VENDOR | 12));
socket.IOControl(SIO_UDP_CONNRESET, new[] {Convert.ToByte(false)}, null);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: adfef17cb18d2624c8b425b5004f9e75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 93c4a9920a37e1b4c9df005d5f1dfa54
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
using System;
using System.IO;
using System.Net;
namespace TEngine.Core.Network
{
public abstract class AClientNetwork : ANetwork
{
public uint ChannelId { get; protected set; }
public abstract event Action OnDispose;
public abstract event Action<uint> OnChangeChannelId;
public abstract event Action<APackInfo> OnReceiveMemoryStream;
protected AClientNetwork(Scene scene, NetworkType networkType, NetworkProtocolType networkProtocolType, NetworkTarget networkTarget) : base(scene, networkType, networkProtocolType, networkTarget) { }
public abstract uint Connect(IPEndPoint remoteEndPoint, Action onConnectComplete, Action onConnectFail, int connectTimeout = 5000);
public override void Dispose()
{
ChannelId = 0;
base.Dispose();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 513303d3661a378438e54a292c1c6d15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,139 @@
using System;
using System.IO;
using TEngine.Core;
#pragma warning disable CS8625
#pragma warning disable CS8618
namespace TEngine.Core.Network
{
public struct MessageCacheInfo
{
public uint RpcId;
public long RouteId;
public long RouteTypeOpCode;
public object Message;
public MemoryStream MemoryStream;
}
public abstract class ANetwork : IDisposable
{
public long Id { get; protected set; }
public Scene Scene { get; protected set; }
public bool IsDisposed { get; protected set; }
public NetworkType NetworkType { get; private set; }
public NetworkTarget NetworkTarget { get; private set; }
public NetworkProtocolType NetworkProtocolType { get; private set; }
public ANetworkMessageScheduler NetworkMessageScheduler { get; protected set; }
protected readonly Func<uint, long, long, MemoryStream, object, MemoryStream> Pack;
private readonly LastMessageInfo _lastMessageInfo = new LastMessageInfo();
protected ANetwork(Scene scene, NetworkType networkType, NetworkProtocolType networkProtocolType, NetworkTarget networkTarget)
{
Scene = scene;
NetworkType = networkType;
NetworkTarget = networkTarget;
NetworkProtocolType = networkProtocolType;
Id = IdFactory.NextRunTimeId();
#if TENGINE_NET
if (networkTarget == NetworkTarget.Inner)
{
Pack = InnerPack;
NetworkMessageScheduler = new InnerMessageScheduler();
return;
}
#endif
Pack = OuterPack;
switch (networkType)
{
case NetworkType.Client:
{
NetworkMessageScheduler = new ClientMessageScheduler();
return;
}
case NetworkType.Server:
{
NetworkMessageScheduler = new OuterMessageScheduler();
return;
}
}
}
#if TENGINE_NET
private MemoryStream InnerPack(uint rpcId, long routeTypeOpCode, long routeId, MemoryStream memoryStream, object message)
{
#if TENGINE_DEVELOP
if (NetworkThread.Instance.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)
{
Log.Error("not in NetworkThread!");
return null;
}
#endif
if (memoryStream != null)
{
return InnerPacketParser.Pack(rpcId, routeId, memoryStream);
}
// 只针对服务器做缓存消息优化(例如群发消息等)、避免多次序列化
if (ReferenceEquals(_lastMessageInfo.Message, message))
{
_lastMessageInfo.MemoryStream.Seek(0, SeekOrigin.Begin);
return _lastMessageInfo.MemoryStream;
}
memoryStream = InnerPacketParser.Pack(rpcId, routeId, message);
_lastMessageInfo.MemoryStream = memoryStream;
_lastMessageInfo.Message = message;
return memoryStream;
}
#endif
private MemoryStream OuterPack(uint rpcId, long routeTypeOpCode, long routeId, MemoryStream memoryStream, object message)
{
#if TENGINE_DEVELOP
if (NetworkThread.Instance.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)
{
Log.Error("not in NetworkThread!");
return null;
}
#endif
if (memoryStream != null)
{
return OuterPacketParser.Pack(rpcId, routeTypeOpCode, memoryStream);
}
// 只针对服务器做缓存消息优化(例如群发消息等)、避免多次序列化
// 客户端没有群发消息的功能、一般客户端都是自己缓存消息、如果这里做了缓存反而不好了
#if TENGINE_NET
if (ReferenceEquals(_lastMessageInfo.Message, message))
{
_lastMessageInfo.MemoryStream.Seek(0, SeekOrigin.Begin);
return _lastMessageInfo.MemoryStream;
}
#endif
memoryStream = OuterPacketParser.Pack(rpcId, routeTypeOpCode, message);
#if TENGINE_NET
_lastMessageInfo.MemoryStream = memoryStream;
_lastMessageInfo.Message = message;
#endif
return memoryStream;
}
public abstract void Send(uint channelId, uint rpcId, long routeTypeOpCode, long routeId, object message);
public abstract void Send(uint channelId, uint rpcId, long routeTypeOpCode, long routeId, MemoryStream memoryStream);
public abstract void RemoveChannel(uint channelId);
public virtual void Dispose()
{
NetworkThread.Instance?.RemoveNetwork(Id);
Id = 0;
Scene = null;
IsDisposed = true;
NetworkType = NetworkType.None;
NetworkTarget = NetworkTarget.None;
NetworkProtocolType = NetworkProtocolType.None;
_lastMessageInfo.Dispose();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8e1b157f4cd9134b84dd17cbb6cb498
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,57 @@
using System;
using System.IO;
using System.Net;
#pragma warning disable CS8625
#pragma warning disable CS8618
namespace TEngine.Core.Network
{
public abstract class ANetworkChannel
{
public uint Id { get; private set; }
public Scene Scene { get; protected set; }
public long NetworkId { get; private set; }
public bool IsDisposed { get; protected set; }
public EndPoint RemoteEndPoint { get; protected set; }
public APacketParser PacketParser { get; protected set; }
public uint LocalConn
{
get
{
return (uint)this.Id;
}
private set
{
this.Id = value;
}
}
public abstract event Action OnDispose;
public abstract event Action<APackInfo> OnReceiveMemoryStream;
protected ANetworkChannel(Scene scene, uint id, long networkId)
{
Id = id;
Scene = scene;
NetworkId = networkId;
}
public virtual void Dispose()
{
NetworkThread.Instance.RemoveChannel(NetworkId, Id);
Id = 0;
Scene = null;
NetworkId = 0;
IsDisposed = true;
RemoteEndPoint = null;
if (PacketParser != null)
{
PacketParser.Dispose();
PacketParser = null;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cef25b06be672c04993353b330cef248
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
namespace TEngine.Core.Network
{
public interface INetworkUpdate
{
void Update();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7eb7bbbac8bc38f429bad42158a0eb39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
using System;
using System.IO;
#pragma warning disable CS8625
#pragma warning disable CS8618
namespace TEngine.Core.Network
{
public class LastMessageInfo : IDisposable
{
public object Message;
public MemoryStream MemoryStream;
public void Dispose()
{
Message = null;
MemoryStream = null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9135b10424d287419b2b9b46caa803d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b9629d3993af22245b83309fcfee436e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
#if TENGINE_NET
namespace TEngine;
public class MachineConfigInfo
{
public uint Id;
public string OuterIP;
public string OuterBindIP;
public string InnerBindIP;
public int ManagementPort;
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c1e5851b16c4a4d49b253c124b953fb3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
namespace TEngine
{
public class SceneConfigInfo
{
public Scene Scene;
public long EntityId;
public uint Id;
public string SceneType;
public string Name;
public string NetworkProtocol;
public uint RouteId;
public uint WorldId;
public int OuterPort;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4fb765098d2e8f34894ec2696a260f48
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,173 @@
#if TENGINE_NET
using TEngine.Core;
using TEngine.Core.Network;
#pragma warning disable CS8603
#pragma warning disable CS8625
#pragma warning disable CS8618
namespace TEngine
{
public sealed class Server
{
public uint Id { get; private set; }
public Scene Scene { get; private set; }
private readonly Dictionary<uint, ConnectInfo> _sessions = new Dictionary<uint, ConnectInfo>();
private sealed class ConnectInfo : IDisposable
{
public Session Session;
public Entity NetworkComponent;
public ConnectInfo(Session session, Entity networkComponent)
{
Session = session;
NetworkComponent = networkComponent;
}
public void Dispose()
{
if (Session != null)
{
Session.Dispose();
Session = null;
}
if (NetworkComponent != null)
{
NetworkComponent.Dispose();
NetworkComponent = null;
}
}
}
public Session GetSession(uint targetServerId)
{
if (_sessions.TryGetValue(targetServerId, out var connectInfo))
{
if (!connectInfo.Session.IsDisposed)
{
return connectInfo.Session;
}
_sessions.Remove(targetServerId);
}
// 同一个Server下、只需要内部走下消息派发就可以
if (Id == targetServerId)
{
var serverNetworkComponent = Scene.GetComponent<ServerNetworkComponent>();
var session = Session.Create(serverNetworkComponent.Network);
_sessions.Add(targetServerId, new ConnectInfo(session, null));
return session;
}
// 不同的Server下需要建立网络连接
var serverConfigInfo = ConfigTableManage.ServerConfig(targetServerId);
if (serverConfigInfo == null)
{
throw new Exception($"The server with ServerId {targetServerId} was not found in the configuration file");
}
var machineConfigInfo = ConfigTableManage.MachineConfig(serverConfigInfo.MachineId);
if (machineConfigInfo == null)
{
throw new Exception($"Server.cs The specified MachineId was not found: {serverConfigInfo.MachineId}");
}
var ipEndPoint = NetworkHelper.ToIPEndPoint($"{machineConfigInfo.InnerBindIP}:{serverConfigInfo.InnerPort}");
var clientNetworkComponent = Entity.Create<ClientNetworkComponent>(Scene);
clientNetworkComponent.Initialize(NetworkProtocolType.KCP, NetworkTarget.Inner);
clientNetworkComponent.Connect(ipEndPoint,null, () =>
{
Log.Error($"Unable to connect to the target server sourceServerId:{Id} targetServerId:{targetServerId}");
});
_sessions.Add(targetServerId, new ConnectInfo(clientNetworkComponent.Session, clientNetworkComponent));
return clientNetworkComponent.Session;
}
public void RemoveSession(uint targetServerId)
{
if (!_sessions.Remove(targetServerId, out var connectInfo))
{
return;
}
connectInfo.Dispose();
}
#region Static
private static readonly Dictionary<uint, Server> Servers = new Dictionary<uint, Server>();
public static async FTask Create(uint routeId)
{
var serverConfigInfo = ConfigTableManage.ServerConfig(routeId);
if (serverConfigInfo == null)
{
Log.Error($"not found server by Id:{routeId}");
return;
}
var machineConfigInfo = ConfigTableManage.MachineConfig(serverConfigInfo.MachineId);
if (machineConfigInfo == null)
{
Log.Error($"not found machine by Id:{serverConfigInfo.MachineId}");
return;
}
var sceneInfos = Scene.GetSceneInfoByRouteId(routeId);
await Create(routeId, machineConfigInfo.InnerBindIP, serverConfigInfo.InnerPort, machineConfigInfo.OuterBindIP, sceneInfos);
// Log.Info($"ServerId:{routeId} is start complete");
}
public static async FTask<Server> Create(uint routeId, string innerBindIp, int innerPort, string outerBindIp, List<SceneConfigInfo> sceneInfos)
{
if (Servers.TryGetValue(routeId, out var server))
{
return server;
}
// 创建一个新的Server、创建一个临时Scene给Server当做Scene使用
server = new Server
{
Id = routeId
};
server.Scene = await Scene.Create($"ServerScene{routeId}", server, new EntityIdStruct(routeId, 0, 0));
// 创建网络、Server下的网络只能是内部网络、外部网络是在Scene中定义
if (!string.IsNullOrEmpty(innerBindIp) && innerPort != 0)
{
var address = NetworkHelper.ToIPEndPoint(innerBindIp, innerPort);
var serverNetworkComponent = server.Scene.AddComponent<ServerNetworkComponent>();
serverNetworkComponent.Initialize(NetworkProtocolType.KCP, NetworkTarget.Inner, address);
}
// 创建Server拥有所有的Scene
foreach (var sceneConfig in sceneInfos)
{
await Scene.Create(server, outerBindIp, sceneConfig);
}
Servers.Add(routeId, server);
return server;
}
public static Server Get(uint routeId)
{
return Servers.TryGetValue(routeId, out var server) ? server : null;
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c108c5f2d1cfef844b1842be027fda0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
#if TENGINE_NET
namespace TEngine;
public class ServerConfigInfo
{
public uint Id;
public uint MachineId;
public int InnerPort;
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9d2ecc96f78db214fa45582d7b146b93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,51 @@
using System.Net.Sockets;
namespace TEngine.Core.Network
{
public static class SocketExtensions
{
public static void SetSocketBufferToOsLimit(this Socket socket)
{
socket.SetReceiveBufferToOSLimit();
socket.SetSendBufferToOSLimit();
}
// 100k attempts of 1 KB increases = default + 100 MB max
public static void SetReceiveBufferToOSLimit(this Socket socket, int stepSize = 1024, int attempts = 100_000)
{
// setting a too large size throws a socket exception.
// so let's keep increasing until we encounter it.
for (int i = 0; i < attempts; ++i)
{
// increase in 1 KB steps
try
{
socket.ReceiveBufferSize += stepSize;
}
catch (SocketException)
{
break;
}
}
}
// 100k attempts of 1 KB increases = default + 100 MB max
public static void SetSendBufferToOSLimit(this Socket socket, int stepSize = 1024, int attempts = 100_000)
{
// setting a too large size throws a socket exception.
// so let's keep increasing until we encounter it.
for (var i = 0; i < attempts; ++i)
{
// increase in 1 KB steps
try
{
socket.SendBufferSize += stepSize;
}
catch (SocketException)
{
break;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4638b4ab890780c419b527a606f0b184
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f9ea43e4953ac874aa8ec1c44059c396
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,57 @@
using System;
using System.Net;
#pragma warning disable CS8625
#pragma warning disable CS8618
namespace TEngine.Core.Network
{
public sealed class ClientNetworkComponent : Entity
{
private AClientNetwork Network { get; set; }
public Session Session { get; private set; }
public void Initialize(NetworkProtocolType networkProtocolType, NetworkTarget networkTarget)
{
switch (networkProtocolType)
{
case NetworkProtocolType.KCP:
{
Network = new KCPClientNetwork(Scene, networkTarget);
return;
}
case NetworkProtocolType.TCP:
{
Network = new TCPClientNetwork(Scene, networkTarget);
return;
}
default:
{
throw new NotSupportedException($"Unsupported NetworkProtocolType:{networkProtocolType}");
}
}
}
public void Connect(IPEndPoint remoteEndPoint, Action onConnectComplete, Action onConnectFail, int connectTimeout = 5000)
{
if (Network == null || Network.IsDisposed)
{
throw new NotSupportedException("Network is null or isDisposed");
}
Network.Connect(remoteEndPoint, onConnectComplete, onConnectFail, connectTimeout);
Session = Session.Create(Network);
}
public override void Dispose()
{
if (Network != null)
{
Network.Dispose();
Network = null;
}
Session = null;
base.Dispose();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8de6a8ca9e15721489a435305757da53
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
using System;
using System.Net;
#pragma warning disable CS8625
#pragma warning disable CS8618
namespace TEngine.Core.Network
{
public sealed class ServerNetworkComponent : Entity, INotSupportedPool
{
public ANetwork Network { get; private set; }
public void Initialize(NetworkProtocolType networkProtocolType, NetworkTarget networkTarget, IPEndPoint address)
{
switch (networkProtocolType)
{
case NetworkProtocolType.KCP:
{
Network = new KCPServerNetwork(Scene, networkTarget, address);
// Log.Info($"NetworkProtocol:KCP IPEndPoint:{address}");
return;
}
case NetworkProtocolType.TCP:
{
Network = new TCPServerNetwork(Scene, networkTarget, address);
// Log.Info($"NetworkProtocol:TCP IPEndPoint:{address}");
return;
}
default:
{
throw new NotSupportedException($"Unsupported NetworkProtocolType:{networkProtocolType}");
}
}
}
public override void Dispose()
{
if (Network != null)
{
Network.Dispose();
Network = null;
}
base.Dispose();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 08a60481ef8b51540b31a673aa1837e3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 313e3a0020362b4408b2b68e276004e6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using TEngine.Core;
#if TENGINE_NET
namespace TEngine.Core.Network;
public sealed class ServerInnerSession : Session
{
public override void Send(object message, uint rpcId = 0, long routeId = 0)
{
if (IsDisposed)
{
return;
}
// 序列化消息到流中
var memoryStream = MemoryStreamHelper.GetRecyclableMemoryStream();
InnerPacketParser.Serialize(message, memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
// 分发消息
var packInfo = InnerPackInfo.Create(rpcId, routeId, ((IMessage)message).OpCode(), 0, memoryStream);
NetworkMessageScheduler.Scheduler(this, packInfo).Coroutine();
}
public override void Send(IRouteMessage routeMessage, uint rpcId = 0, long routeId = 0)
{
if (IsDisposed)
{
return;
}
// 序列化消息到流中
var memoryStream = MemoryStreamHelper.GetRecyclableMemoryStream();
InnerPacketParser.Serialize(routeMessage, memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
// 分发消息
var packInfo = InnerPackInfo.Create(rpcId, routeId, routeMessage.OpCode(), routeMessage.RouteTypeOpCode(), memoryStream);
NetworkMessageScheduler.Scheduler(this, packInfo).Coroutine();
}
public override void Send(MemoryStream memoryStream, uint rpcId = 0, long routeTypeOpCode = 0, long routeId = 0)
{
throw new Exception("The use of this method is not supported");
}
public override FTask<IResponse> Call(IRequest request, long routeId = 0)
{
throw new Exception("The use of this method is not supported");
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 787fbc8b90a182644abe477d98ed8939
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,212 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using TEngine.Core;
#pragma warning disable CS8603
#pragma warning disable CS8601
#pragma warning disable CS8618
namespace TEngine.Core.Network
{
public class Session : Entity, INotSupportedPool, ISupportedMultiEntity
{
private uint _rpcId;
public long NetworkId { get; private set; }
public uint ChannelId { get; private set; }
public long LastReceiveTime { get; private set; }
public ANetworkMessageScheduler NetworkMessageScheduler { get; private set;}
private static readonly Dictionary<long, Session> Sessions = new ();
public readonly Dictionary<long, FTask<IResponse>> RequestCallback = new();
public static void Create(ANetworkMessageScheduler networkMessageScheduler, ANetworkChannel channel)
{
#if TENGINE_DEVELOP
if (ThreadSynchronizationContext.Main.ThreadId != Thread.CurrentThread.ManagedThreadId)
{
throw new NotSupportedException("Session Create not in MainThread");
}
#endif
var session = Entity.Create<Session>(channel.Scene);
session.ChannelId = channel.Id;
session.NetworkId = channel.NetworkId;
session.NetworkMessageScheduler = networkMessageScheduler;
channel.OnDispose += session.Dispose;
channel.OnReceiveMemoryStream += session.OnReceive;
Sessions.Add(session.Id, session);
}
public static Session Create(AClientNetwork network)
{
#if TENGINE_DEVELOP
if (ThreadSynchronizationContext.Main.ThreadId != Thread.CurrentThread.ManagedThreadId)
{
throw new NotSupportedException("Session Create not in MainThread");
}
#endif
var session = Entity.Create<Session>(network.Scene);
session.ChannelId = network.ChannelId;
session.NetworkId = network.Id;
session.NetworkMessageScheduler = network.NetworkMessageScheduler;
network.OnDispose += session.Dispose;
network.OnChangeChannelId += session.OnChangeChannelId;
network.OnReceiveMemoryStream += session.OnReceive;
Sessions.Add(session.Id, session);
return session;
}
#if TENGINE_NET
public static ServerInnerSession Create(ANetwork network)
{
#if TENGINE_DEVELOP
if (ThreadSynchronizationContext.Main.ThreadId != Thread.CurrentThread.ManagedThreadId)
{
throw new NotSupportedException("Session Create not in MainThread");
}
#endif
var session = Entity.Create<ServerInnerSession>(network.Scene);
session.NetworkMessageScheduler = network.NetworkMessageScheduler;
Sessions.Add(session.Id, session);
return session;
}
public static ServerInnerSession CreateServerInner(Scene scene)
{
#if TENGINE_DEVELOP
if (ThreadSynchronizationContext.Main.ThreadId != Thread.CurrentThread.ManagedThreadId)
{
throw new NotSupportedException("Session Create not in MainThread");
}
#endif
var session = Entity.Create<ServerInnerSession>(scene, false);
Sessions.Add(session.Id, session);
return session;
}
#endif
public static bool TryGet(long id, out Session session)
{
return Sessions.TryGetValue(id, out session);
}
public override void Dispose()
{
#if TENGINE_DEVELOP
if (ThreadSynchronizationContext.Main.ThreadId != Thread.CurrentThread.ManagedThreadId)
{
throw new NotSupportedException("Session Create not in MainThread");
}
#endif
if (IsDisposed)
{
return;
}
var id = Id;
var networkId = NetworkId;
var channelId = ChannelId;
foreach (var requestCallback in RequestCallback.Values.ToArray())
{
requestCallback.SetException(new Exception($"session is dispose: {Id}"));
}
if (networkId != 0 && channelId != 0)
{
NetworkThread.Instance.SynchronizationContext.Post(() =>
{
NetworkThread.Instance?.RemoveChannel(networkId, channelId);
});
}
Sessions.Remove(id);
#if NETDEBUG
Log.Debug($"Sessions Dispose Count:{Sessions.Count}");
#endif
base.Dispose();
}
public virtual void Send(object message, uint rpcId = 0, long routeId = 0)
{
if (IsDisposed)
{
return;
}
NetworkThread.Instance.Send(NetworkId, ChannelId, rpcId, 0, routeId, message);
}
public virtual void Send(IRouteMessage routeMessage, uint rpcId = 0, long routeId = 0)
{
if (IsDisposed)
{
return;
}
NetworkThread.Instance.Send(NetworkId, ChannelId, rpcId, routeMessage.RouteTypeOpCode(), routeId, routeMessage);
}
public virtual void Send(MemoryStream memoryStream, uint rpcId = 0, long routeTypeOpCode = 0, long routeId = 0)
{
if (IsDisposed)
{
return;
}
NetworkThread.Instance.SendStream(NetworkId, ChannelId, rpcId, routeTypeOpCode, routeId, memoryStream);
}
public virtual FTask<IResponse> Call(IRequest request, long routeId = 0)
{
if (IsDisposed)
{
return null;
}
var requestCallback = FTask<IResponse>.Create();
unchecked
{
var rpcId = ++_rpcId;
RequestCallback.Add(rpcId, requestCallback);
if (request is IRouteMessage iRouteMessage)
{
Send(iRouteMessage, rpcId, routeId);
}
else
{
Send(request, rpcId, routeId);
}
}
return requestCallback;
}
private void OnReceive(APackInfo packInfo)
{
if (IsDisposed)
{
return;
}
LastReceiveTime = TimeHelper.Now;
try
{
NetworkMessageScheduler.Scheduler(this, packInfo).Coroutine();
}
catch (Exception e)
{
// 如果解析失败,只有一种可能,那就是有人恶意发包。
// 所以这里强制关闭了当前连接。不让对方一直发包。
Dispose();
Log.Error(e);
}
}
private void OnChangeChannelId(uint channelId)
{
ChannelId = channelId;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a7d60d383d04c84888fd48783813ed3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b62e9f6a86604cf469ab9d9f47bddc5a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using System;
namespace TEngine.Core.Network
{
public class ScanException : Exception
{
public ScanException() { }
public ScanException(string msg) : base(msg) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8258e475fd71ff040a40766c65bd34a4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4192fecfffd49194086253fef2b074f7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ab17a7b38d59bc84aafe2d54a2a6c834
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,104 @@
#if TENGINE_NET
namespace TEngine.Core.Network
{
public static class AddressableHelper
{
private static readonly List<SceneConfigInfo> AddressableScenes = new List<SceneConfigInfo>();
static AddressableHelper()
{
var sceneConfigInfos = ConfigTableManage.AllSceneConfig();
foreach (var sceneConfigInfo in sceneConfigInfos)
{
if (sceneConfigInfo.SceneType == "Addressable")
{
AddressableScenes.Add(sceneConfigInfo);
}
}
}
public static async FTask AddAddressable(Scene scene, long addressableId, long routeId)
{
var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count];
var response = await MessageHelper.CallInnerRoute(scene, addressableScene.EntityId,
new I_AddressableAdd_Request
{
AddressableId = addressableId, RouteId = routeId
});
if (response.ErrorCode != 0)
{
Log.Error($"AddAddressable error is {response.ErrorCode}");
}
}
public static async FTask<long> GetAddressableRouteId(Scene scene, long addressableId)
{
var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count];
var response = (I_AddressableGet_Response) await MessageHelper.CallInnerRoute(scene, addressableScene.EntityId,
new I_AddressableGet_Request
{
AddressableId = addressableId
});
if (response.ErrorCode == 0)
{
return response.RouteId;
}
Log.Error($"GetAddressable error is {response.ErrorCode} addressableId:{addressableId}");
return 0;
}
public static async FTask RemoveAddressable(Scene scene, long addressableId)
{
var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count];
var response = await MessageHelper.CallInnerRoute(scene, addressableScene.EntityId,
new I_AddressableRemove_Request
{
AddressableId = addressableId
});
if (response.ErrorCode != 0)
{
Log.Error($"RemoveAddressable error is {response.ErrorCode}");
}
}
public static async FTask LockAddressable(Scene scene, long addressableId)
{
var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count];
var response = await MessageHelper.CallInnerRoute(scene, addressableScene.EntityId,
new I_AddressableLock_Request
{
AddressableId = addressableId
});
if (response.ErrorCode != 0)
{
Log.Error($"LockAddressable error is {response.ErrorCode}");
}
}
public static async FTask UnLockAddressable(Scene scene, long addressableId, long routeId, string source)
{
var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count];
var response = await MessageHelper.CallInnerRoute(scene, addressableScene.EntityId,
new I_AddressableUnLock_Request
{
AddressableId = addressableId,
RouteId = routeId,
Source = source
});
if (response.ErrorCode != 0)
{
Log.Error($"UnLockAddressable error is {response.ErrorCode}");
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e8589a3e288b52f4e92a04053ba0c6bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
using System.Collections.Generic;
namespace TEngine.Core.Network
{
public sealed class AddressableManageComponent : Entity
{
private readonly Dictionary<long, long> _addressable = new();
private readonly Dictionary<long, WaitCoroutineLock> _locks = new();
private readonly CoroutineLockQueueType _addressableLock = new CoroutineLockQueueType("AddressableLock");
public async FTask Add(long addressableId, long routeId)
{
using (await _addressableLock.Lock(addressableId))
{
_addressable[addressableId] = routeId;
Log.Debug($"AddressableManageComponent Add addressableId:{addressableId} routeId:{routeId}");
}
}
public async FTask<long> Get(long addressableId)
{
using (await _addressableLock.Lock(addressableId))
{
_addressable.TryGetValue(addressableId, out var routeId);
return routeId;
}
}
public async FTask Remove(long addressableId)
{
using (await _addressableLock.Lock(addressableId))
{
_addressable.Remove(addressableId);
}
}
public async FTask Lock(long addressableId)
{
var waitCoroutineLock = await _addressableLock.Lock(addressableId);
_locks.Add(addressableId, waitCoroutineLock);
}
public void UnLock(long addressableId, long routeId, string source)
{
if (!_locks.Remove(addressableId, out var coroutineLock))
{
Log.Error($"Addressable unlock not found addressableId: {addressableId} Source:{source}");
return;
}
_addressable.TryGetValue(addressableId, out var oldAddressableId);
if (routeId != 0)
{
_addressable[addressableId] = routeId;
}
coroutineLock.Dispose();
Log.Debug($"Addressable UnLock key: {addressableId} oldAddressableId : {oldAddressableId} routeId: {routeId} Source:{source}");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e946a97e041db3b4f89af34ac9914098
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
#if TENGINE_NET
namespace TEngine.Core.Network
{
/// <summary>
/// 可寻址消息组件、挂载了这个组件可以接收Addressable消息
/// </summary>
public sealed class AddressableMessageComponent : Entity
{
public long AddressableId;
public override void Dispose()
{
if (AddressableId != 0)
{
AddressableHelper.RemoveAddressable(Scene, AddressableId).Coroutine();
AddressableId = 0;
}
base.Dispose();
}
public FTask Register()
{
if (Parent == null)
{
throw new Exception("AddressableRouteComponent must be mounted under a component");
}
AddressableId = Parent.Id;
if (AddressableId == 0)
{
throw new Exception("AddressableRouteComponent.Parent.Id is null");
}
#if TENGINE_DEVELOP
Log.Debug($"AddressableMessageComponent Register addressableId:{AddressableId} RouteId:{Parent.RuntimeId}");
#endif
return AddressableHelper.AddAddressable(Scene, AddressableId, Parent.RuntimeId);
}
public FTask Lock()
{
#if TENGINE_DEVELOP
Log.Debug($"AddressableMessageComponent Lock {Parent.Id}");
#endif
return AddressableHelper.LockAddressable(Scene, Parent.Id);
}
public FTask UnLock(string source)
{
#if TENGINE_DEVELOP
Log.Debug($"AddressableMessageComponent UnLock {Parent.Id} {Parent.RuntimeId}");
#endif
return AddressableHelper.UnLockAddressable(Scene, Parent.Id, Parent.RuntimeId, source);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: be31fb4b0e977f347837b7b6b6b840d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,191 @@
#pragma warning disable CS8603
#pragma warning disable CS8600
#if TENGINE_NET
namespace TEngine.Core.Network;
public sealed class AddressableRouteComponentAwakeSystem : AwakeSystem<AddressableRouteComponent>
{
protected override void Awake(AddressableRouteComponent self)
{
self.Awake();
}
}
/// <summary>
/// 可寻址消息组件、挂载了这个组件可以接收和发送Addressable消息
/// </summary>
public sealed class AddressableRouteComponent : Entity
{
private long _parentId;
private long _addressableRouteId;
public static readonly CoroutineLockQueueType AddressableRouteMessageLock = new CoroutineLockQueueType("AddressableRouteMessageLock");
public override void Dispose()
{
_parentId = 0;
_addressableRouteId = 0;
base.Dispose();
}
public void Awake()
{
if (Parent == null)
{
throw new Exception("AddressableRouteComponent must be mounted under a component");
}
if (Parent.RuntimeId == 0)
{
throw new Exception("AddressableRouteComponent.Parent.RuntimeId is null");
}
_parentId = Parent.Id;
}
public void SetAddressableRouteId(long addressableRouteId)
{
_addressableRouteId = addressableRouteId;
}
public void Send(IAddressableRouteMessage message)
{
Call(message).Coroutine();
}
public void Send(long routeTypeOpCode, Type requestType, MemoryStream message)
{
Call(routeTypeOpCode, requestType, message).Coroutine();
}
public async FTask<IResponse> Call(long routeTypeOpCode, Type requestType, MemoryStream request)
{
if (IsDisposed)
{
return MessageDispatcherSystem.Instance.CreateResponse(requestType, CoreErrorCode.ErrNotFoundRoute);
}
var failCount = 0;
var runtimeId = RuntimeId;
IResponse iRouteResponse = null;
using (await AddressableRouteMessageLock.Lock(_parentId, "AddressableRouteComponent Call MemoryStream"))
{
while (!IsDisposed)
{
if (_addressableRouteId == 0)
{
_addressableRouteId = await AddressableHelper.GetAddressableRouteId(Scene, _parentId);
}
if (_addressableRouteId == 0)
{
return MessageDispatcherSystem.Instance.CreateResponse(requestType, CoreErrorCode.ErrNotFoundRoute);
}
iRouteResponse = await MessageHelper.CallInnerRoute(Scene, _addressableRouteId, routeTypeOpCode, requestType, request);
if (runtimeId != RuntimeId)
{
iRouteResponse.ErrorCode = CoreErrorCode.ErrRouteTimeout;
}
switch (iRouteResponse.ErrorCode)
{
case CoreErrorCode.ErrRouteTimeout:
{
return iRouteResponse;
}
case CoreErrorCode.ErrNotFoundRoute:
{
if (++failCount > 20)
{
Log.Error($"AddressableComponent.Call failCount > 20 route send message fail, routeId: {_addressableRouteId} AddressableRouteComponent:{Id}");
return iRouteResponse;
}
await TimerScheduler.Instance.Core.WaitAsync(500);
if (runtimeId != RuntimeId)
{
iRouteResponse.ErrorCode = CoreErrorCode.ErrRouteTimeout;
}
_addressableRouteId = 0;
continue;
}
default:
{
return iRouteResponse;
}
}
}
}
return iRouteResponse;
}
public async FTask<IResponse> Call(IAddressableRouteMessage request)
{
if (IsDisposed)
{
return MessageDispatcherSystem.Instance.CreateResponse(request, CoreErrorCode.ErrNotFoundRoute);
}
var failCount = 0;
var runtimeId = RuntimeId;
using (await AddressableRouteMessageLock.Lock(_parentId,"AddressableRouteComponent Call"))
{
while (true)
{
if (_addressableRouteId == 0)
{
_addressableRouteId = await AddressableHelper.GetAddressableRouteId(Scene, _parentId);
}
if (_addressableRouteId == 0)
{
return MessageDispatcherSystem.Instance.CreateResponse(request, CoreErrorCode.ErrNotFoundRoute);
}
var iRouteResponse = await MessageHelper.CallInnerRoute(Scene, _addressableRouteId, request);
if (runtimeId != RuntimeId)
{
iRouteResponse.ErrorCode = CoreErrorCode.ErrRouteTimeout;
}
switch (iRouteResponse.ErrorCode)
{
case CoreErrorCode.ErrNotFoundRoute:
{
if (++failCount > 20)
{
Log.Error($"AddressableRouteComponent.Call failCount > 20 route send message fail, routeId: {_addressableRouteId} AddressableRouteComponent:{Id}");
return iRouteResponse;
}
await TimerScheduler.Instance.Core.WaitAsync(500);
if (runtimeId != RuntimeId)
{
iRouteResponse.ErrorCode = CoreErrorCode.ErrRouteTimeout;
}
_addressableRouteId = 0;
continue;
}
case CoreErrorCode.ErrRouteTimeout:
{
return iRouteResponse;
}
default:
{
return iRouteResponse;
}
}
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 897c9af3c45fd8e429f8a851eb1b8aab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 09bf59c6e0e10e644aa18a17e8a305e8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
#if TENGINE_NET
namespace TEngine.Core.Network;
public sealed class I_AddressableAddHandler : RouteRPC<Scene, I_AddressableAdd_Request, I_AddressableAdd_Response>
{
protected override async FTask Run(Scene scene, I_AddressableAdd_Request request, I_AddressableAdd_Response response, Action reply)
{
await scene.GetComponent<AddressableManageComponent>().Add(request.AddressableId, request.RouteId);
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 974e720fa811f47418b83d5b3ffdd41c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
#if TENGINE_NET
namespace TEngine.Core.Network;
public sealed class I_AddressableGetHandler : RouteRPC<Scene, I_AddressableGet_Request, I_AddressableGet_Response>
{
protected override async FTask Run(Scene scene, I_AddressableGet_Request request, I_AddressableGet_Response response, Action reply)
{
response.RouteId = await scene.GetComponent<AddressableManageComponent>().Get(request.AddressableId);
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 24a968aef62bae54f9fef9bc39b94959
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
#if TENGINE_NET
namespace TEngine.Core.Network;
public sealed class I_AddressableLockHandler : RouteRPC<Scene, I_AddressableLock_Request, I_AddressableLock_Response>
{
protected override async FTask Run(Scene scene, I_AddressableLock_Request request, I_AddressableLock_Response response, Action reply)
{
await scene.GetComponent<AddressableManageComponent>().Lock(request.AddressableId);
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 95e84c7e22ea5f047a3c524d8472e967
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
#if TENGINE_NET
namespace TEngine.Core.Network;
public sealed class I_AddressableRemoveHandler : RouteRPC<Scene, I_AddressableRemove_Request, I_AddressableRemove_Response>
{
protected override async FTask Run(Scene scene, I_AddressableRemove_Request request, I_AddressableRemove_Response response, Action reply)
{
await scene.GetComponent<AddressableManageComponent>().Remove(request.AddressableId);
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 660cdf9f50994c94182e3a64c569da85
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
#if TENGINE_NET
namespace TEngine.Core.Network;
public sealed class I_AddressableUnLockHandler : RouteRPC<Scene, I_AddressableUnLock_Request, I_AddressableUnLock_Response>
{
protected override async FTask Run(Scene scene, I_AddressableUnLock_Request request, I_AddressableUnLock_Response response, Action reply)
{
scene.GetComponent<AddressableManageComponent>().UnLock(request.AddressableId, request.RouteId, request.Source);
await FTask.CompletedTask;
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c4b465b4daeb9d7498cf33409ee72662
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 77c1999fe41f3b743a8df80748ece7e4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,265 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TEngine.DataStructure;
using TEngine.Core;
using Type = System.Type;
#pragma warning disable CS8602
#pragma warning disable CS8600
#pragma warning disable CS8618
// ReSharper disable PossibleNullReferenceException
namespace TEngine.Core.Network
{
public sealed class HandlerInfo<T>
{
public T Obj;
public Type Type;
}
public sealed class MessageDispatcherSystem : Singleton<MessageDispatcherSystem>
{
private readonly Dictionary<Type, Type> _responseTypes = new Dictionary<Type, Type>();
private readonly DoubleMapDictionary<uint, Type> _networkProtocols = new DoubleMapDictionary<uint, Type>();
private readonly Dictionary<Type, IMessageHandler> _messageHandlers = new Dictionary<Type, IMessageHandler>();
private readonly OneToManyList<int, Type> _assemblyResponseTypes = new OneToManyList<int, Type>();
private readonly OneToManyList<int, uint> _assemblyNetworkProtocols = new OneToManyList<int, uint>();
private readonly OneToManyList<int, HandlerInfo<IMessageHandler>> _assemblyMessageHandlers = new OneToManyList<int, HandlerInfo<IMessageHandler>>();
#if TENGINE_NET
private readonly Dictionary<Type, IRouteMessageHandler> _routeMessageHandlers = new Dictionary<Type, IRouteMessageHandler>();
private readonly OneToManyList<int, HandlerInfo<IRouteMessageHandler>> _assemblyRouteMessageHandlers= new OneToManyList<int, HandlerInfo<IRouteMessageHandler>>();
#endif
private static readonly CoroutineLockQueueType ReceiveRouteMessageLock = new CoroutineLockQueueType("ReceiveRouteMessageLock");
protected override void OnLoad(int assemblyName)
{
foreach (var type in AssemblyManager.ForEach(assemblyName, typeof(IMessage)))
{
var obj = (IMessage) Activator.CreateInstance(type);
var opCode = obj.OpCode();
_networkProtocols.Add(opCode, type);
var responseType = type.GetProperty("ResponseType");
if (responseType != null)
{
_responseTypes.Add(type, responseType.PropertyType);
_assemblyResponseTypes.Add(assemblyName, type);
}
_assemblyNetworkProtocols.Add(assemblyName, opCode);
}
foreach (var type in AssemblyManager.ForEach(assemblyName, typeof(IMessageHandler)))
{
var obj = (IMessageHandler) Activator.CreateInstance(type);
if (obj == null)
{
throw new Exception($"message handle {type.Name} is null");
}
var key = obj.Type();
_messageHandlers.Add(key, obj);
_assemblyMessageHandlers.Add(assemblyName, new HandlerInfo<IMessageHandler>()
{
Obj = obj, Type = key
});
}
#if TENGINE_NET
foreach (var type in AssemblyManager.ForEach(assemblyName, typeof(IRouteMessageHandler)))
{
var obj = (IRouteMessageHandler) Activator.CreateInstance(type);
if (obj == null)
{
throw new Exception($"message handle {type.Name} is null");
}
var key = obj.Type();
_routeMessageHandlers.Add(key, obj);
_assemblyRouteMessageHandlers.Add(assemblyName, new HandlerInfo<IRouteMessageHandler>()
{
Obj = obj, Type = key
});
}
#endif
}
protected override void OnUnLoad(int assemblyName)
{
if (_assemblyResponseTypes.TryGetValue(assemblyName, out var removeResponseTypes))
{
foreach (var removeResponseType in removeResponseTypes)
{
_responseTypes.Remove(removeResponseType);
}
_assemblyResponseTypes.RemoveByKey(assemblyName);
}
if (_assemblyNetworkProtocols.TryGetValue(assemblyName, out var removeNetworkProtocols))
{
foreach (var removeNetworkProtocol in removeNetworkProtocols)
{
_networkProtocols.RemoveByKey(removeNetworkProtocol);
}
_assemblyNetworkProtocols.RemoveByKey(assemblyName);
}
if (_assemblyMessageHandlers.TryGetValue(assemblyName, out var removeMessageHandlers))
{
foreach (var removeMessageHandler in removeMessageHandlers)
{
_messageHandlers.Remove(removeMessageHandler.Type);
}
_assemblyMessageHandlers.Remove(assemblyName);
}
#if TENGINE_NET
if (_assemblyRouteMessageHandlers.TryGetValue(assemblyName, out var removeRouteMessageHandlers))
{
foreach (var removeRouteMessageHandler in removeRouteMessageHandlers)
{
_routeMessageHandlers.Remove(removeRouteMessageHandler.Type);
}
_assemblyRouteMessageHandlers.Remove(assemblyName);
}
#endif
}
public void MessageHandler(Session session, Type type, object message, uint rpcId, uint protocolCode)
{
if (!_messageHandlers.TryGetValue(type, out var messageHandler))
{
Log.Warning($"Scene:{session.Scene.Id} Found Unhandled Message: {message.GetType()}");
return;
}
messageHandler.Handle(session, rpcId, protocolCode, message).Coroutine();
}
#if TENGINE_NET
public async FTask RouteMessageHandler(Session session, Type type, Entity entity, object message, uint rpcId)
{
if (!_routeMessageHandlers.TryGetValue(type, out var routeMessageHandler))
{
Log.Warning($"Scene:{session.Scene.Id} Found Unhandled RouteMessage: {message.GetType()}");
if (message is IRouteRequest request)
{
FailResponse(session, request, CoreErrorCode.Error_NotFindEntity, rpcId);
}
return;
}
var runtimeId = entity.RuntimeId;
var sessionRuntimeId = session.RuntimeId;
if (entity is Scene)
{
// 如果是Scene的话、就不要加锁了、如果加锁很一不小心就可能会造成死锁
await routeMessageHandler.Handle(session, entity, rpcId, message);
return;
}
using (await ReceiveRouteMessageLock.Lock(runtimeId))
{
if (sessionRuntimeId != session.RuntimeId)
{
return;
}
if (runtimeId != entity.RuntimeId)
{
if (message is IRouteRequest request)
{
FailResponse(session, request, CoreErrorCode.Error_NotFindEntity, rpcId);
}
return;
}
await routeMessageHandler.Handle(session, entity, rpcId, message);
}
}
#endif
public void FailResponse(Session session, IRouteRequest iRouteRequest, int error, uint rpcId)
{
var response = CreateResponse(iRouteRequest, error);
session.Send(response, rpcId);
}
public IRouteResponse CreateRouteResponse()
{
return new RouteResponse();
}
public IResponse CreateResponse(Type requestType, int error)
{
IResponse response;
if (_responseTypes.TryGetValue(requestType, out var responseType))
{
response = (IResponse) Activator.CreateInstance(responseType);
}
else
{
response = new Response();
}
response.ErrorCode = error;
return response;
}
public IResponse CreateResponse(IRequest iRequest, int error)
{
IResponse response;
if (_responseTypes.TryGetValue(iRequest.GetType(), out var responseType))
{
response = (IResponse) Activator.CreateInstance(responseType);
}
else
{
response = new Response();
}
response.ErrorCode = error;
return response;
}
public IRouteResponse CreateResponse(IRouteRequest iRouteRequest, int error)
{
IRouteResponse response;
if (_responseTypes.TryGetValue(iRouteRequest.GetType(), out var responseType))
{
response = (IRouteResponse) Activator.CreateInstance(responseType);
}
else
{
response = new RouteResponse();
}
response.ErrorCode = error;
return response;
}
public uint GetOpCode(Type type)
{
return _networkProtocols.GetKeyByValue(type);
}
public Type GetOpCodeType(uint code)
{
return _networkProtocols.GetValueByKey(code);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d6c1581e1f459cc4295685cafaa63dd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
namespace TEngine.Core.Network
{
public static class Opcode
{
// 外网消息
public const uint OuterMessage = 100000000;
public const uint OuterRequest = 110000000;
// 内网消息
public const uint InnerMessage = 120000000;
public const uint InnerRequest = 130000000;
// 内网Bson消息
public const uint InnerBsonMessage = 140000000;
public const uint InnerBsonRequest = 150000000;
// 回复消息
public const uint OuterResponse = 160000000;
public const uint InnerResponse = 170000000;
public const uint InnerBsonResponse = 180000000;
// 外网路由消息
public const uint OuterRouteMessage = 190000000;
public const uint OuterRouteRequest = 200000000;
// 内网路由消息
public const uint InnerRouteMessage = 210000000;
public const uint InnerRouteRequest = 220000000;
// 内网Bson路由消息
public const uint InnerBsonRouteMessage = 230000000;
public const uint InnerBsonRouteRequest = 240000000;
// 路由回复消息
public const uint OuterRouteResponse = 250000000;
public const uint InnerRouteResponse = 260000000;
public const uint InnerBsonRouteResponse = 270000000;
// 心跳消息
public const uint PingRequest = 1;
public const uint PingResponse = 2;
// 默认回复消息
public const uint DefaultResponse = 3;
// Addressable可寻址消息
public const uint AddressableAddRequest = InnerRouteRequest + 1;
public const uint AddressableAddResponse = InnerRouteResponse + 1;
public const uint AddressableGetRequest = InnerRouteRequest + 2;
public const uint AddressableGetResponse = InnerRouteResponse + 2;
public const uint AddressableRemoveRequest = InnerRouteRequest + 3;
public const uint AddressableRemoveResponse = InnerRouteResponse + 3;
public const uint AddressableLockRequest = InnerRouteRequest + 4;
public const uint AddressableLockResponse = InnerRouteResponse + 4;
public const uint AddressableUnLockRequest = InnerRouteRequest + 5;
public const uint AddressableUnLockResponse = InnerRouteResponse + 5;
// 默认的Route返回消息
public const uint DefaultRouteResponse = InnerRouteResponse + 6;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6b40c482be660ad4090888728af062ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
using ProtoBuf;
namespace TEngine.Core.Network
{
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8516b2b12ce77fb488b1b973adc680f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e639a64f385d7164799d03a031c3fabb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: db5ee92b41263e2478cfb3dbb35e0ccf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
// ReSharper disable InconsistentNaming
using System;
namespace TEngine.Core.Network
{
public interface IMessageHandler
{
public Type Type();
FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message);
}
public abstract class Message<T> : IMessageHandler
{
public Type Type()
{
return typeof(T);
}
public async FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message)
{
try
{
await Run(session, (T) message);
}
catch (Exception e)
{
Log.Error(e);
}
}
protected abstract FTask Run(Session session, T message);
}
public abstract class MessageRPC<TRequest, TResponse> : IMessageHandler where TRequest : IRequest where TResponse : IResponse
{
public Type Type()
{
return typeof(TRequest);
}
public async FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message)
{
if (message is not TRequest request)
{
Log.Error($"消息类型转换错误: {message.GetType().Name} to {typeof(TRequest).Name}");
return;
}
var response = Activator.CreateInstance<TResponse>();
var isReply = false;
void Reply()
{
if (isReply)
{
return;
}
isReply = true;
if (session.IsDisposed)
{
return;
}
session.Send(response, rpcId);
}
try
{
await Run(session, request, response, Reply);
}
catch (Exception e)
{
Log.Error(e);
response.ErrorCode = CoreErrorCode.ErrRpcFail;
}
finally
{
Reply();
}
}
protected abstract FTask Run(Session session, TRequest request, TResponse response, Action reply);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d0e1cb825e8847a479ac69acee8f0bb6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,222 @@
#if TENGINE_NET
// ReSharper disable InconsistentNaming
namespace TEngine.Core.Network
{
public interface IRouteMessageHandler
{
public Type Type();
FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage);
}
public abstract class Route<TEntity, TMessage> : IRouteMessageHandler where TEntity : Entity where TMessage : IRouteMessage
{
public Type Type()
{
return typeof(TMessage);
}
public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage)
{
if (routeMessage is not TMessage ruteMessage)
{
Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TMessage).Name}");
return;
}
if (entity is not TEntity tEntity)
{
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
return;
}
try
{
await Run(tEntity, ruteMessage);
}
catch (Exception e)
{
if (entity is not Scene scene)
{
scene = entity.Scene;
}
Log.Error($"SceneWorld:{session.Scene.World.Id} SceneRouteId:{scene.RouteId} SceneType:{scene.SceneInfo.SceneType} EntityId {tEntity.Id} : Error {e}");
}
}
protected abstract FTask Run(TEntity entity, TMessage message);
}
public abstract class RouteRPC<TEntity, TRouteRequest, TRouteResponse> : IRouteMessageHandler where TEntity : Entity where TRouteRequest : IRouteRequest where TRouteResponse : IRouteResponse
{
public Type Type()
{
return typeof(TRouteRequest);
}
public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage)
{
if (routeMessage is not TRouteRequest tRouteRequest)
{
Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TRouteRequest).Name}");
return;
}
if (entity is not TEntity tEntity)
{
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
return;
}
var isReply = false;
var response = Activator.CreateInstance<TRouteResponse>();
void Reply()
{
if (isReply)
{
return;
}
isReply = true;
if (session.IsDisposed)
{
return;
}
session.Send(response, rpcId);
}
try
{
await Run(tEntity, tRouteRequest, response, Reply);
}
catch (Exception e)
{
if (entity is not Scene scene)
{
scene = entity.Scene;
}
Log.Error($"SceneWorld:{session.Scene.World.Id} SceneRouteId:{scene.RouteId} SceneType:{scene.SceneInfo.SceneType} EntityId {tEntity.Id} : Error {e}");
response.ErrorCode = CoreErrorCode.ErrRpcFail;
}
finally
{
Reply();
}
}
protected abstract FTask Run(TEntity entity, TRouteRequest request, TRouteResponse response, Action reply);
}
public abstract class Addressable<TEntity, TMessage> : IRouteMessageHandler where TEntity : Entity where TMessage : IAddressableRouteMessage
{
public Type Type()
{
return typeof(TMessage);
}
public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage)
{
if (routeMessage is not TMessage ruteMessage)
{
Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TMessage).Name}");
return;
}
if (entity is not TEntity tEntity)
{
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
return;
}
try
{
await Run(tEntity, ruteMessage);
}
catch (Exception e)
{
if (entity is not Scene scene)
{
scene = entity.Scene;
}
Log.Error($"SceneWorld:{session.Scene.World.Id} SceneRouteId:{scene.RouteId} SceneType:{scene.SceneInfo.SceneType} EntityId {tEntity.Id} : Error {e}");
}
finally
{
session.Send(MessageDispatcherSystem.Instance.CreateRouteResponse(), rpcId);
}
}
protected abstract FTask Run(TEntity entity, TMessage message);
}
public abstract class AddressableRPC<TEntity, TRouteRequest, TRouteResponse> : IRouteMessageHandler where TEntity : Entity where TRouteRequest : IAddressableRouteRequest where TRouteResponse : IAddressableRouteResponse
{
public Type Type()
{
return typeof(TRouteRequest);
}
public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage)
{
if (routeMessage is not TRouteRequest tRouteRequest)
{
Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TRouteRequest).Name}");
return;
}
if (entity is not TEntity tEntity)
{
Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}");
return;
}
var isReply = false;
var response = Activator.CreateInstance<TRouteResponse>();
void Reply()
{
if (isReply)
{
return;
}
isReply = true;
if (session.IsDisposed)
{
return;
}
session.Send(response, rpcId);
}
try
{
await Run(tEntity, tRouteRequest, response, Reply);
}
catch (Exception e)
{
if (entity is not Scene scene)
{
scene = entity.Scene;
}
Log.Error($"SceneWorld:{session.Scene.World.Id} SceneRouteId:{scene.RouteId} SceneType:{scene.SceneInfo.SceneType} EntityId {tEntity.Id} : Error {e}");
response.ErrorCode = CoreErrorCode.ErrRpcFail;
}
finally
{
Reply();
}
}
protected abstract FTask Run(TEntity entity, TRouteRequest request, TRouteResponse response, Action reply);
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a6de532c5ce565747817a22793fb85c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4767a374666197f4ab971d74378a5040
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
namespace TEngine.Core.Network
{
public interface IBsonMessage : IMessage
{
}
public interface IBsonRequest : IBsonMessage, IRequest
{
}
public interface IBsonResponse : IBsonMessage, IResponse
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cb1d2907b6893e643b0f5c4644b412d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
namespace TEngine.Core.Network
{
public interface IMessage
{
uint OpCode();
}
public interface IRequest : IMessage
{
}
public interface IResponse : IMessage
{
int ErrorCode { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e0828643e6b72684fb0e4917cef34b97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
namespace TEngine.Core.Network
{
// 普通路由消息
public interface IRouteMessage : IRequest
{
long RouteTypeOpCode();
}
public interface IRouteRequest : IRouteMessage { }
public interface IRouteResponse : IResponse { }
// 普通路由Bson消息
public interface IBsonRouteMessage : IBsonMessage, IRouteMessage { }
public interface IBsonRouteRequest : IBsonRouteMessage, IRouteRequest { }
public interface IBsonRouteResponse : IBsonResponse, IRouteResponse { }
// 可寻址协议
public interface IAddressableRouteMessage : IRouteMessage { }
public interface IAddressableRouteRequest : IRouteRequest { }
public interface IAddressableRouteResponse : IRouteResponse { }
// 可寻址Bson协议
public interface IBsonAddressableRouteMessage : IBsonMessage, IAddressableRouteMessage { }
public interface IBsonAddressableRouteRequest : IBsonRouteMessage, IAddressableRouteRequest { }
public interface IBsonAddressableRouteResponse : IBsonResponse, IAddressableRouteResponse { }
// 自定义Route协议
public interface ICustomRouteMessage : IRouteMessage { }
public interface ICustomRouteRequest : IRouteRequest { }
public interface ICustomRouteResponse : IRouteResponse { }
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0d836956c7e220f4d945807e0fd90c1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e8ff64952cfa44645a9410738b63d26b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
using System;
using System.IO;
using TEngine.Core;
#pragma warning disable CS8600
namespace TEngine.Core.Network
{
public abstract class ANetworkMessageScheduler
{
private readonly PingResponse _pingResponse = new PingResponse();
public async FTask Scheduler(Session session, APackInfo packInfo)
{
Type messageType = null;
var packInfoMemoryStream = packInfo.MemoryStream;
try
{
if (session.IsDisposed)
{
return;
}
if (packInfo.ProtocolCode == Opcode.PingRequest)
{
_pingResponse.Now = TimeHelper.Now;
session.Send(_pingResponse, packInfo.RpcId);
return;
}
messageType = MessageDispatcherSystem.Instance.GetOpCodeType(packInfo.ProtocolCode);
if (messageType == null)
{
throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode{packInfo.ProtocolCode}");
}
switch (packInfo.ProtocolCode)
{
case >= Opcode.OuterRouteMessage:
{
await Handler(session, messageType, packInfo);
return;
}
case < Opcode.OuterResponse:
{
var message = packInfo.Deserialize(messageType);
MessageDispatcherSystem.Instance.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode);
return;
}
default:
{
var aResponse = (IResponse)packInfo.Deserialize(messageType);
#if TENGINE_NET
// 服务器之间发送消息因为走的是MessageHelper、所以接收消息的回调也应该放到MessageHelper里处理
MessageHelper.ResponseHandler(packInfo.RpcId, aResponse);
#else
// 这个一般是客户端Session.Call发送时使用的、目前这个逻辑只有Unity客户端时使用
if (!session.RequestCallback.TryGetValue(packInfo.RpcId, out var action))
{
Log.Error($"not found rpc {packInfo.RpcId}, response message: {aResponse.GetType().Name}");
return;
}
session.RequestCallback.Remove(packInfo.RpcId);
action.SetResult(aResponse);
#endif
return;
}
}
}
catch (Exception e)
{
if (packInfoMemoryStream.CanRead)
{
// ReSharper disable once MethodHasAsyncOverload
packInfoMemoryStream.Dispose();
}
Log.Error($"NetworkMessageScheduler error messageProtocolCode:{packInfo.ProtocolCode} messageType:{messageType} SessionId {session.Id} IsDispose {session.IsDisposed} {e}");
}
finally
{
packInfo.Dispose();
}
}
protected abstract FTask Handler(Session session, Type messageType, APackInfo packInfo);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b71e62d5efece8a408fc90048164af53
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
// using System;
// using System.IO;
//
// namespace TEngine.Core.Network
// {
// public enum NetworkMessageSchedulerHandlerType
// {
// None = 0,
// ClientMessage = 1,
// OuterMessageRoute = 2,
// InnerMessage = 3,
// ServerInnerMessage = 4
// }
//
// public interface INetworkMessageSchedulerHandler
// {
// NetworkMessageSchedulerHandlerType HandlerType();
//
// FTask Handler(Session session, Type messageType, APackInfo packInfo);
// }
// }

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d5653343ec7befa48a924bed253321ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,196 @@
using TEngine.Core;
#pragma warning disable CS8603
#if TENGINE_NET
namespace TEngine.Core.Network;
public static class MessageHelper
{
private static uint _rpcId;
public const long Timeout = 40000;
public static readonly SortedDictionary<uint, MessageSender> RequestCallback = new();
public static readonly Dictionary<uint, MessageSender> TimeoutRouteMessageSenders = new();
/// <summary>
/// 定时检查过期的Call消息事件。
/// </summary>
public struct NetworkMessageUpdate { }
static MessageHelper()
{
TimerScheduler.Instance.Core.RepeatedTimer(10000, new NetworkMessageUpdate());
}
public static void SendInnerServer(Scene scene, uint routeId, IMessage message)
{
scene.Server.GetSession(routeId).Send(message);
}
public static void SendInnerRoute(Scene scene, long entityId, IRouteMessage message)
{
if (entityId == 0)
{
Log.Error($"SendInnerRoute appId == 0");
return;
}
EntityIdStruct entityIdStruct = entityId;
var session = scene.Server.GetSession(entityIdStruct.RouteId);
session.Send(message, 0, entityId);
}
public static void SendInnerRoute(Scene scene, long entityId, long routeTypeOpCode, MemoryStream message)
{
if (entityId == 0)
{
Log.Error($"SendInnerRoute appId == 0");
return;
}
EntityIdStruct entityIdStruct = entityId;
var session = scene.Server.GetSession(entityIdStruct.RouteId);
session.Send(message, 0, routeTypeOpCode, entityId);
}
public static void SendInnerRoute(Scene scene, ICollection<long> routeIdCollection, IRouteMessage message)
{
if (routeIdCollection.Count <= 0)
{
Log.Error($"SendInnerRoute routeId.Count <= 0");
return;
}
foreach (var routeId in routeIdCollection)
{
SendInnerRoute(scene, routeId, message);
}
}
public static void SendAddressable(Scene scene, long addressableId, IRouteMessage message)
{
CallAddressable(scene, addressableId, message).Coroutine();
}
public static async FTask<IResponse> CallInnerRoute(Scene scene, long entityId, long routeTypeOpCode, Type requestType, MemoryStream request)
{
if (entityId == 0)
{
Log.Error($"CallInnerRoute appId == 0");
return null;
}
EntityIdStruct entityIdStruct = entityId;
var rpcId = ++_rpcId;
var session = scene.Server.GetSession(entityIdStruct.RouteId);
var requestCallback = FTask<IResponse>.Create(false);
RequestCallback.Add(rpcId, MessageSender.Create(rpcId, requestType, requestCallback));
session.Send(request, rpcId, routeTypeOpCode, entityId);
return await requestCallback;
}
public static async FTask<IResponse> CallInnerRoute(Scene scene, long entityId, IRouteMessage request)
{
if (entityId == 0)
{
Log.Error($"CallInnerRoute appId == 0");
return null;
}
EntityIdStruct entityIdStruct = entityId;
var rpcId = ++_rpcId;
var session = scene.Server.GetSession(entityIdStruct.RouteId);
var requestCallback = FTask<IResponse>.Create(false);
RequestCallback.Add(rpcId, MessageSender.Create(rpcId, request, requestCallback));
session.Send(request, rpcId, entityId);
return await requestCallback;
}
public static async FTask<IResponse> CallInnerServer(Scene scene, uint targetServerId, IRequest request)
{
var rpcId = ++_rpcId;
var session = scene.Server.GetSession(targetServerId);
var requestCallback = FTask<IResponse>.Create(false);
RequestCallback.Add(rpcId, MessageSender.Create(rpcId, request, requestCallback));
session.Send(request, rpcId);
return await requestCallback;
}
public static async FTask<IResponse> CallAddressable(Scene scene, long addressableId, IRouteMessage request)
{
var failCount = 0;
using (await AddressableRouteComponent.AddressableRouteMessageLock.Lock(addressableId,"CallAddressable"))
{
var addressableRouteId = await AddressableHelper.GetAddressableRouteId(scene, addressableId);
while (true)
{
if (addressableRouteId == 0)
{
addressableRouteId = await AddressableHelper.GetAddressableRouteId(scene, addressableId);
}
if (addressableRouteId == 0)
{
return MessageDispatcherSystem.Instance.CreateResponse(request, CoreErrorCode.ErrNotFoundRoute);
}
var iRouteResponse = await MessageHelper.CallInnerRoute(scene, addressableRouteId, request);
switch (iRouteResponse.ErrorCode)
{
case CoreErrorCode.ErrNotFoundRoute:
{
if (++failCount > 20)
{
Log.Error($"AddressableComponent.Call failCount > 20 route send message fail, routeId: {addressableRouteId} AddressableMessageComponent:{addressableId}");
return iRouteResponse;
}
await TimerScheduler.Instance.Core.WaitAsync(500);
addressableRouteId = 0;
continue;
}
case CoreErrorCode.ErrRouteTimeout:
{
Log.Error($"CallAddressableRoute ErrorCode.ErrRouteTimeout Error:{iRouteResponse.ErrorCode} Message:{request}");
return iRouteResponse;
}
default:
{
return iRouteResponse;
}
}
}
}
}
public static void ResponseHandler(uint rpcId, IResponse response)
{
if (!RequestCallback.Remove(rpcId, out var routeMessageSender))
{
throw new Exception($"not found rpc, response.RpcId:{rpcId} response message: {response.GetType().Name}");
}
ResponseHandler(routeMessageSender, response);
}
private static void ResponseHandler(MessageSender messageSender, IResponse response)
{
if (response.ErrorCode == CoreErrorCode.ErrRouteTimeout)
{
#if TENGINE_DEVELOP
messageSender.Tcs.SetException(new Exception($"Rpc error: request, 注意RouteId消息超时请注意查看是否死锁或者没有reply: RouteId: {messageSender.RouteId} {messageSender.Request.ToJson()}, response: {response}"));
#else
messageSender.Tcs.SetException(new Exception($"Rpc error: request, 注意RouteId消息超时请注意查看是否死锁或者没有reply: RouteId: {messageSender.RouteId} {messageSender.Request}, response: {response}"));
#endif
messageSender.Dispose();
return;
}
messageSender.Tcs.SetResult(response);
messageSender.Dispose();
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e2dce1a84fcf96e4a8dfbe49a155660a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
using System;
using TEngine.Core;
#pragma warning disable CS8625
#pragma warning disable CS8618
namespace TEngine.Core.Network
{
public sealed class MessageSender : IDisposable
{
public uint RpcId { get; private set; }
public long RouteId { get; private set; }
public long CreateTime { get; private set; }
public Type MessageType { get; private set; }
public IMessage Request { get; private set; }
public FTask<IResponse> Tcs { get; private set; }
public void Dispose()
{
RpcId = 0;
RouteId = 0;
CreateTime = 0;
Tcs = null;
Request = null;
MessageType = null;
Pool<MessageSender>.Return(this);
}
public static MessageSender Create(uint rpcId, Type requestType, FTask<IResponse> tcs)
{
var routeMessageSender = Pool<MessageSender>.Rent();
routeMessageSender.Tcs = tcs;
routeMessageSender.RpcId = rpcId;
routeMessageSender.MessageType = requestType;
routeMessageSender.CreateTime = TimeHelper.Now;
return routeMessageSender;
}
public static MessageSender Create(uint rpcId, IRequest request, FTask<IResponse> tcs)
{
var routeMessageSender = Pool<MessageSender>.Rent();
routeMessageSender.Tcs = tcs;
routeMessageSender.RpcId = rpcId;
routeMessageSender.Request = request;
routeMessageSender.CreateTime = TimeHelper.Now;
return routeMessageSender;
}
public static MessageSender Create(uint rpcId, long routeId, IRouteMessage request, FTask<IResponse> tcs)
{
var routeMessageSender = Pool<MessageSender>.Rent();
routeMessageSender.Tcs = tcs;
routeMessageSender.RpcId = rpcId;
routeMessageSender.RouteId = routeId;
routeMessageSender.Request = request;
routeMessageSender.CreateTime = TimeHelper.Now;
return routeMessageSender;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 39b99a8dcf9c7e946a72b1008bbfe1ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,71 @@
#if TENGINE_NET
using TEngine.Core;
namespace TEngine.Core.Network;
public sealed class OnNetworkMessageUpdateCheckTimeout : TimerHandler<MessageHelper.NetworkMessageUpdate>
{
public override void Handler(MessageHelper.NetworkMessageUpdate self)
{
var timeNow = TimeHelper.Now;
foreach (var (rpcId, value) in MessageHelper.RequestCallback)
{
if (timeNow < value.CreateTime + MessageHelper.Timeout)
{
break;
}
MessageHelper.TimeoutRouteMessageSenders.Add(rpcId, value);
}
if (MessageHelper.TimeoutRouteMessageSenders.Count == 0)
{
return;
}
foreach (var (rpcId, routeMessageSender) in MessageHelper.TimeoutRouteMessageSenders)
{
uint responseRpcId = 0;
try
{
switch (routeMessageSender.Request)
{
case IRouteMessage iRouteMessage:
{
// var routeResponse = RouteMessageDispatcher.CreateResponse(iRouteMessage, ErrorCode.ErrRouteTimeout);
// responseRpcId = routeResponse.RpcId;
// routeResponse.RpcId = routeMessageSender.RpcId;
// MessageHelper.ResponseHandler(routeResponse);
break;
}
case IRequest iRequest:
{
var response = MessageDispatcherSystem.Instance.CreateResponse(iRequest, CoreErrorCode.ErrRpcFail);
responseRpcId = routeMessageSender.RpcId;
MessageHelper.ResponseHandler(responseRpcId, response);
Log.Warning($"timeout rpcId:{rpcId} responseRpcId:{responseRpcId} {iRequest.ToJson()}");
break;
}
default:
{
Log.Error(routeMessageSender.Request != null
? $"Unsupported protocol type {routeMessageSender.Request.GetType()} rpcId:{rpcId}"
: $"Unsupported protocol type:{routeMessageSender.MessageType.FullName} rpcId:{rpcId}");
MessageHelper.RequestCallback.Remove(rpcId);
break;
}
}
}
catch (Exception e)
{
Log.Error($"responseRpcId:{responseRpcId} routeMessageSender.RpcId:{routeMessageSender.RpcId} {e}");
}
}
MessageHelper.TimeoutRouteMessageSenders.Clear();
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3152b1d220a7acb45b874cf286c4a341
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1eb9f0783453cf7439a4f31708fde2d6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,160 @@
using TEngine.Core.Network;
using ProtoBuf;
namespace TEngine
{
[ProtoContract]
public sealed class Response : AProto, IResponse
{
public uint OpCode()
{
return Opcode.DefaultResponse;
}
[ProtoMember(90)] public long RpcId { get; set; }
[ProtoMember(91, IsRequired = true)] public int ErrorCode { get; set; }
}
[ProtoContract]
public sealed class RouteResponse : AProto, IRouteResponse
{
public uint OpCode()
{
return Opcode.DefaultRouteResponse;
}
[ProtoMember(90)] public long RpcId { get; set; }
[ProtoMember(91, IsRequired = true)] public int ErrorCode { get; set; }
}
[ProtoContract]
public class PingRequest : AProto, IRequest
{
public uint OpCode()
{
return Opcode.PingRequest;
}
[ProtoIgnore] public PingResponse ResponseType { get; set; }
[ProtoMember(90)] public long RpcId { get; set; }
}
public class PingResponse : AProto, IResponse
{
public uint OpCode()
{
return Opcode.PingResponse;
}
[ProtoMember(90)] public long RpcId { get; set; }
[ProtoMember(91, IsRequired = true)] public int ErrorCode { get; set; }
[ProtoMember(1)] public long Now;
}
/// <summary>
/// 添加一个可寻址地址
/// </summary>
[ProtoContract]
public partial class I_AddressableAdd_Request : AProto, IRouteRequest
{
[ProtoIgnore]
public I_AddressableAdd_Response ResponseType { get; set; }
public uint OpCode() { return Opcode.AddressableAddRequest; }
public long RouteTypeOpCode() { return 1; }
[ProtoMember(1)]
public long AddressableId { get; set; }
[ProtoMember(2)]
public long RouteId { get; set; }
}
[ProtoContract]
public partial class I_AddressableAdd_Response : AProto, IRouteResponse
{
public uint OpCode() { return Opcode.AddressableAddResponse; }
[ProtoMember(91, IsRequired = true)]
public int ErrorCode { get; set; }
}
/// <summary>
/// 查询一个可寻址
/// </summary>
[ProtoContract]
public partial class I_AddressableGet_Request : AProto, IRouteRequest
{
[ProtoIgnore]
public I_AddressableGet_Response ResponseType { get; set; }
public uint OpCode() { return Opcode.AddressableGetRequest; }
public long RouteTypeOpCode() { return 1; }
[ProtoMember(1)]
public long AddressableId { get; set; }
}
[ProtoContract]
public partial class I_AddressableGet_Response : AProto, IRouteResponse
{
public uint OpCode() { return Opcode.AddressableGetResponse; }
[ProtoMember(91, IsRequired = true)]
public int ErrorCode { get; set; }
[ProtoMember(1)]
public long RouteId { get; set; }
}
/// <summary>
/// 删除一个可寻址
/// </summary>
[ProtoContract]
public partial class I_AddressableRemove_Request : AProto, IRouteRequest
{
[ProtoIgnore]
public I_AddressableRemove_Response ResponseType { get; set; }
public uint OpCode() { return Opcode.AddressableRemoveRequest; }
public long RouteTypeOpCode() { return 1; }
[ProtoMember(1)]
public long AddressableId { get; set; }
}
[ProtoContract]
public partial class I_AddressableRemove_Response : AProto, IRouteResponse
{
public uint OpCode() { return Opcode.AddressableRemoveResponse; }
[ProtoMember(91, IsRequired = true)]
public int ErrorCode { get; set; }
}
/// <summary>
/// 锁定一个可寻址
/// </summary>
[ProtoContract]
public partial class I_AddressableLock_Request : AProto, IRouteRequest
{
[ProtoIgnore]
public I_AddressableLock_Response ResponseType { get; set; }
public uint OpCode() { return Opcode.AddressableLockRequest; }
public long RouteTypeOpCode() { return 1; }
[ProtoMember(1)]
public long AddressableId { get; set; }
}
[ProtoContract]
public partial class I_AddressableLock_Response : AProto, IRouteResponse
{
public uint OpCode() { return Opcode.AddressableLockResponse; }
[ProtoMember(91, IsRequired = true)]
public int ErrorCode { get; set; }
}
/// <summary>
/// 解锁一个可寻址
/// </summary>
[ProtoContract]
public partial class I_AddressableUnLock_Request : AProto, IRouteRequest
{
[ProtoIgnore]
public I_AddressableUnLock_Response ResponseType { get; set; }
public uint OpCode() { return Opcode.AddressableUnLockRequest; }
public long RouteTypeOpCode() { return 1; }
[ProtoMember(1)]
public long AddressableId { get; set; }
[ProtoMember(2)]
public long RouteId { get; set; }
[ProtoMember(3)]
public string Source { get; set; }
}
[ProtoContract]
public partial class I_AddressableUnLock_Response : AProto, IRouteResponse
{
public uint OpCode() { return Opcode.AddressableUnLockResponse; }
[ProtoMember(91, IsRequired = true)]
public int ErrorCode { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More