commit 8e45469c834c45822f9e8af877c52ba516c52296
Author: bob <605277374@qq.com>
Date: Mon Jun 30 10:51:37 2025 +0800
饭太稀
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d9b4e5d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,35 @@
+# Specify filepatterns you want git to ignore.
+obj/
+Bin/
+bin/
+Temp/
+Library/
+Logs/
+temp/
+DocFx/
+global.json
+
+# 项目素材
+ResLibrary/
+# Unity项目文件
+examples/**/Unity/*.sln
+examples/**/Unity/*.csproj
+examples/**/Unity/.vsconfig
+
+# Client-Unity
+HybridCLRData/
+AssetBundles/
+UserSettings/
+# 忽略Packages.Unity包下的.meta
+Packages.Unity/**/*.meta
+
+
+# Other
+.idea
+.vs
+.vscode
+*.DS_Store
+# 不排除示例项目的.vscode
+!examples/**/.vscode
+!Tools/**/.vscode
+examples/**/Unity/.vscode
diff --git a/Entity/AssemblyHelper.cs b/Entity/AssemblyHelper.cs
new file mode 100644
index 0000000..cac01c5
--- /dev/null
+++ b/Entity/AssemblyHelper.cs
@@ -0,0 +1,41 @@
+using System.Reflection;
+using System.Runtime.Loader;
+
+namespace Fantasy
+{
+ public static class AssemblyHelper
+ {
+ private const string HotfixDll = "Hotfix";
+ private static AssemblyLoadContext? _assemblyLoadContext = null;
+
+ public static System.Reflection.Assembly[] Assemblies
+ {
+ get
+ {
+ var assemblies = new System.Reflection.Assembly[2];
+ assemblies[0] = LoadEntityAssembly();
+ assemblies[1] = LoadHotfixAssembly();
+ return assemblies;
+ }
+ }
+
+ private static System.Reflection.Assembly LoadEntityAssembly()
+ {
+ return typeof(AssemblyHelper).Assembly;
+ }
+
+ private static System.Reflection.Assembly LoadHotfixAssembly()
+ {
+ if (_assemblyLoadContext != null)
+ {
+ _assemblyLoadContext.Unload();
+ System.GC.Collect();
+ }
+
+ _assemblyLoadContext = new AssemblyLoadContext(HotfixDll, true);
+ var dllBytes = File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, $"{HotfixDll}.dll"));
+ var pdbBytes = File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, $"{HotfixDll}.pdb"));
+ return _assemblyLoadContext.LoadFromStream(new MemoryStream(dllBytes), new MemoryStream(pdbBytes));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Entity/Entity.csproj b/Entity/Entity.csproj
new file mode 100644
index 0000000..5030fc6
--- /dev/null
+++ b/Entity/Entity.csproj
@@ -0,0 +1,24 @@
+
+
+
+ enable
+ enable
+ Linux
+ net8.0;net9.0
+ default
+
+
+
+ TRACE;FANTASY_NET
+
+
+
+ TRACE;FANTASY_NET
+
+
+
+
+
+
+
+
diff --git a/Entity/Generate/ConfigTable/Entity/UnitConfig.cs b/Entity/Generate/ConfigTable/Entity/UnitConfig.cs
new file mode 100644
index 0000000..c0f11d9
--- /dev/null
+++ b/Entity/Generate/ConfigTable/Entity/UnitConfig.cs
@@ -0,0 +1,99 @@
+using System;
+using ProtoBuf;
+using Fantasy;
+using System.Linq;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+using Fantasy.ConfigTable;
+using Fantasy.Serialize;
+// ReSharper disable CollectionNeverUpdated.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
+#pragma warning disable CS0169
+#pragma warning disable CS8618
+#pragma warning disable CS8625
+#pragma warning disable CS8603
+
+namespace Fantasy
+{
+ [ProtoContract]
+ public sealed partial class UnitConfigData : ASerialize, IConfigTable, IProto
+ {
+ [ProtoMember(1)]
+ public List List { get; set; } = new List();
+#if FANTASY_NET
+ [ProtoIgnore]
+ private readonly ConcurrentDictionary _configs = new ConcurrentDictionary();
+#else
+ [ProtoIgnore]
+ private readonly Dictionary _configs = new Dictionary();
+#endif
+ private static UnitConfigData _instance = null;
+
+ public static UnitConfigData Instance
+ {
+ get { return _instance ??= ConfigTableHelper.Load(); }
+ private set => _instance = value;
+ }
+
+ public UnitConfig Get(uint id, bool check = true)
+ {
+ if (_configs.ContainsKey(id))
+ {
+ return _configs[id];
+ }
+
+ if (check)
+ {
+ throw new Exception($"UnitConfig not find {id} Id");
+ }
+
+ return null;
+ }
+ public bool TryGet(uint id, out UnitConfig config)
+ {
+ config = null;
+
+ if (!_configs.ContainsKey(id))
+ {
+ return false;
+ }
+
+ config = _configs[id];
+ return true;
+ }
+ public override void AfterDeserialization()
+ {
+ foreach (var config in List)
+ {
+#if FANTASY_NET
+ _configs.TryAdd(config.Id, config);
+#else
+ _configs.Add(config.Id, config);
+#endif
+ config.AfterDeserialization();
+ }
+
+ EndInit();
+ }
+
+ public override void Dispose()
+ {
+ Instance = null;
+ }
+ }
+
+ [ProtoContract]
+ public sealed partial class UnitConfig : ASerialize, IProto
+ {
+ [ProtoMember(1)]
+ public uint Id { get; set; } // Id
+ [ProtoMember(2)]
+ public string Name { get; set; } // 名称
+ [ProtoMember(3)]
+ public string Model { get; set; } // 数据库类型
+ [ProtoMember(4)]
+ public StringDictionaryConfig Dic { get; set; } // 字典类型
+ }
+}
\ No newline at end of file
diff --git a/Entity/Generate/ConfigTable/Partial/UnitConfigData.cs b/Entity/Generate/ConfigTable/Partial/UnitConfigData.cs
new file mode 100644
index 0000000..36e9c93
--- /dev/null
+++ b/Entity/Generate/ConfigTable/Partial/UnitConfigData.cs
@@ -0,0 +1,10 @@
+namespace Fantasy;
+
+public sealed partial class UnitConfigData
+{
+ public override void EndInit()
+ {
+ Log.Debug("UnitConfigData EndInit");
+ base.EndInit();
+ }
+}
\ No newline at end of file
diff --git a/Entity/Generate/CustomExport/SceneType.cs b/Entity/Generate/CustomExport/SceneType.cs
new file mode 100644
index 0000000..de34ed9
--- /dev/null
+++ b/Entity/Generate/CustomExport/SceneType.cs
@@ -0,0 +1,27 @@
+namespace Fantasy
+{
+ // 生成器自动生成,请不要手动编辑。
+ public static class SceneType
+ {
+ public const int Authentication = 1;
+ public const int Addressable = 2;
+ public const int Gate = 3;
+ public const int Map = 4;
+ public const int CopyDispatcher = 5;
+ public const int CopyManager = 6;
+ public const int Copy = 7;
+ public const int Chat = 8;
+
+ public static readonly Dictionary SceneTypeDic = new Dictionary()
+ {
+ { "Authentication", 1 },
+ { "Addressable", 2 },
+ { "Gate", 3 },
+ { "Map", 4 },
+ { "CopyDispatcher", 5 },
+ { "CopyManager", 6 },
+ { "Copy", 7 },
+ { "Chat", 8 },
+ };
+ }
+}
diff --git a/Entity/Generate/NetworkProtocol/InnerMessage.cs b/Entity/Generate/NetworkProtocol/InnerMessage.cs
new file mode 100644
index 0000000..48aa0d7
--- /dev/null
+++ b/Entity/Generate/NetworkProtocol/InnerMessage.cs
@@ -0,0 +1,333 @@
+using ProtoBuf;
+
+using System.Collections.Generic;
+using MongoDB.Bson.Serialization.Attributes;
+using Fantasy;
+using Fantasy.Network.Interface;
+using Fantasy.Serialize;
+// ReSharper disable InconsistentNaming
+// ReSharper disable RedundantUsingDirective
+// ReSharper disable RedundantOverriddenMember
+// ReSharper disable PartialTypeWithSinglePart
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable CheckNamespace
+#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
+#pragma warning disable CS8618
+
+namespace Fantasy
+{
+ [ProtoContract]
+ public partial class G2A_TestMessage : AMessage, IRouteMessage, IProto
+ {
+ public static G2A_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.G2A_TestMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class G2A_TestRequest : AMessage, IRouteRequest, IProto
+ {
+ public static G2A_TestRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2A_TestResponse ResponseType { get; set; }
+ public uint OpCode() { return InnerOpcode.G2A_TestRequest; }
+ }
+ [ProtoContract]
+ public partial class G2A_TestResponse : AMessage, IRouteResponse, IProto
+ {
+ public static G2A_TestResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.G2A_TestResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class G2M_RequestAddressableId : AMessage, IRouteRequest, IProto
+ {
+ public static G2M_RequestAddressableId Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public M2G_ResponseAddressableId ResponseType { get; set; }
+ public uint OpCode() { return InnerOpcode.G2M_RequestAddressableId; }
+ }
+ [ProtoContract]
+ public partial class M2G_ResponseAddressableId : AMessage, IRouteResponse, IProto
+ {
+ public static M2G_ResponseAddressableId Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ AddressableId = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.M2G_ResponseAddressableId; }
+ [ProtoMember(1)]
+ public long AddressableId { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 通知Chat服务器创建一个RouteId
+ ///
+ [ProtoContract]
+ public partial class G2Chat_CreateRouteRequest : AMessage, IRouteRequest, IProto
+ {
+ public static G2Chat_CreateRouteRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ GateRouteId = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public Chat2G_CreateRouteResponse ResponseType { get; set; }
+ public uint OpCode() { return InnerOpcode.G2Chat_CreateRouteRequest; }
+ [ProtoMember(1)]
+ public long GateRouteId { get; set; }
+ }
+ [ProtoContract]
+ public partial class Chat2G_CreateRouteResponse : AMessage, IRouteResponse, IProto
+ {
+ public static Chat2G_CreateRouteResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ ChatRouteId = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.Chat2G_CreateRouteResponse; }
+ [ProtoMember(1)]
+ public long ChatRouteId { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// Map给另外一个Map发送Unit数据
+ ///
+ public partial class M2M_SendUnitRequest : AMessage, IRouteRequest
+ {
+ public static M2M_SendUnitRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Unit = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [BsonIgnore]
+ public M2M_SendUnitResponse ResponseType { get; set; }
+ public uint OpCode() { return InnerOpcode.M2M_SendUnitRequest; }
+ public Unit Unit { get; set; }
+ }
+ public partial class M2M_SendUnitResponse : AMessage, IRouteResponse
+ {
+ public static M2M_SendUnitResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.M2M_SendUnitResponse; }
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// Gate发送Addressable消息给MAP
+ ///
+ [ProtoContract]
+ public partial class G2M_SendAddressableMessage : AMessage, IAddressableRouteMessage, IProto
+ {
+ public static G2M_SendAddressableMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.G2M_SendAddressableMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class G2M_CreateSubSceneRequest : AMessage, IRouteRequest, IProto
+ {
+ public static G2M_CreateSubSceneRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public M2G_CreateSubSceneResponse ResponseType { get; set; }
+ public uint OpCode() { return InnerOpcode.G2M_CreateSubSceneRequest; }
+ }
+ [ProtoContract]
+ public partial class M2G_CreateSubSceneResponse : AMessage, IRouteResponse, IProto
+ {
+ public static M2G_CreateSubSceneResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ SubSceneRouteId = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.M2G_CreateSubSceneResponse; }
+ [ProtoMember(1)]
+ public long SubSceneRouteId { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class G2SubScene_SentMessage : AMessage, IRouteMessage, IProto
+ {
+ public static G2SubScene_SentMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.G2SubScene_SentMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// Gate通知SubScene创建一个Addressable消息
+ ///
+ [ProtoContract]
+ public partial class G2SubScene_AddressableIdRequest : AMessage, IRouteRequest, IProto
+ {
+ public static G2SubScene_AddressableIdRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public SubScene2G_AddressableIdResponse ResponseType { get; set; }
+ public uint OpCode() { return InnerOpcode.G2SubScene_AddressableIdRequest; }
+ }
+ [ProtoContract]
+ public partial class SubScene2G_AddressableIdResponse : AMessage, IRouteResponse, IProto
+ {
+ public static SubScene2G_AddressableIdResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ AddressableId = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.SubScene2G_AddressableIdResponse; }
+ [ProtoMember(1)]
+ public long AddressableId { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// Chat发送一个漫游消息给Map
+ ///
+ [ProtoContract]
+ public partial class Chat2M_TestMessage : AMessage, IRoamingMessage, IProto
+ {
+ public static Chat2M_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return InnerOpcode.Chat2M_TestMessage; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RoamingType.MapRoamingType;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+}
diff --git a/Entity/Generate/NetworkProtocol/InnerOpcode.cs b/Entity/Generate/NetworkProtocol/InnerOpcode.cs
new file mode 100644
index 0000000..a6128fe
--- /dev/null
+++ b/Entity/Generate/NetworkProtocol/InnerOpcode.cs
@@ -0,0 +1,22 @@
+namespace Fantasy
+{
+ public static partial class InnerOpcode
+ {
+ public const uint G2A_TestMessage = 939534097;
+ public const uint G2A_TestRequest = 1073751825;
+ public const uint G2A_TestResponse = 1207969553;
+ public const uint G2M_RequestAddressableId = 1073751826;
+ public const uint M2G_ResponseAddressableId = 1207969554;
+ public const uint G2Chat_CreateRouteRequest = 1073751827;
+ public const uint Chat2G_CreateRouteResponse = 1207969555;
+ public const uint M2M_SendUnitRequest = 1082140436;
+ public const uint M2M_SendUnitResponse = 1216358164;
+ public const uint G2M_SendAddressableMessage = 1744840465;
+ public const uint G2M_CreateSubSceneRequest = 1073751829;
+ public const uint M2G_CreateSubSceneResponse = 1207969557;
+ public const uint G2SubScene_SentMessage = 939534098;
+ public const uint G2SubScene_AddressableIdRequest = 1073751830;
+ public const uint SubScene2G_AddressableIdResponse = 1207969558;
+ public const uint Chat2M_TestMessage = 2952800017;
+ }
+}
diff --git a/Entity/Generate/NetworkProtocol/OuterMessage.cs b/Entity/Generate/NetworkProtocol/OuterMessage.cs
new file mode 100644
index 0000000..0b19540
--- /dev/null
+++ b/Entity/Generate/NetworkProtocol/OuterMessage.cs
@@ -0,0 +1,787 @@
+using ProtoBuf;
+
+using System.Collections.Generic;
+using MongoDB.Bson.Serialization.Attributes;
+using Fantasy;
+using Fantasy.Network.Interface;
+using Fantasy.Serialize;
+// ReSharper disable InconsistentNaming
+// ReSharper disable RedundantUsingDirective
+// ReSharper disable RedundantOverriddenMember
+// ReSharper disable PartialTypeWithSinglePart
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable CheckNamespace
+#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
+#pragma warning disable CS8618
+
+namespace Fantasy
+{
+ [ProtoContract]
+ public partial class C2G_TestMessage : AMessage, IMessage, IProto
+ {
+ public static C2G_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2G_TestMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2G_TestRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_TestRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_TestResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_TestRequest; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class G2C_TestResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_TestResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_TestResponse; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2G_TestRequestPushMessage : AMessage, IMessage, IProto
+ {
+ public static C2G_TestRequestPushMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2G_TestRequestPushMessage; }
+ }
+ ///
+ /// Gate服务器推送一个消息给客户端
+ ///
+ [ProtoContract]
+ public partial class G2C_PushMessage : AMessage, IMessage, IProto
+ {
+ public static G2C_PushMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_PushMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2G_CreateAddressableRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_CreateAddressableRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_CreateAddressableResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_CreateAddressableRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_CreateAddressableResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_CreateAddressableResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_CreateAddressableResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2M_TestMessage : AMessage, IAddressableRouteMessage, IProto
+ {
+ public static C2M_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2M_TestMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2M_TestRequest : AMessage, IAddressableRouteRequest, IProto
+ {
+ public static C2M_TestRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public M2C_TestResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2M_TestRequest; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class M2C_TestResponse : AMessage, IAddressableRouteResponse, IProto
+ {
+ public static M2C_TestResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.M2C_TestResponse; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 通知Gate服务器创建一个Chat的Route连接
+ ///
+ [ProtoContract]
+ public partial class C2G_CreateChatRouteRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_CreateChatRouteRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_CreateChatRouteResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_CreateChatRouteRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_CreateChatRouteResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_CreateChatRouteResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_CreateChatRouteResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 发送一个Route消息给Chat
+ ///
+ [ProtoContract]
+ public partial class C2Chat_TestMessage : AMessage, ICustomRouteMessage, IProto
+ {
+ public static C2Chat_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2Chat_TestMessage; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.ChatRoute;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 发送一个RPCRoute消息给Chat
+ ///
+ [ProtoContract]
+ public partial class C2Chat_TestMessageRequest : AMessage, ICustomRouteRequest, IProto
+ {
+ public static C2Chat_TestMessageRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public Chat2C_TestMessageResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2Chat_TestMessageRequest; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.ChatRoute;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class Chat2C_TestMessageResponse : AMessage, ICustomRouteResponse, IProto
+ {
+ public static Chat2C_TestMessageResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Chat2C_TestMessageResponse; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 发送一个RPC消息给Map,让Map里的Entity转移到另外一个Map上
+ ///
+ [ProtoContract]
+ public partial class C2M_MoveToMapRequest : AMessage, IAddressableRouteRequest, IProto
+ {
+ public static C2M_MoveToMapRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public M2C_MoveToMapResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2M_MoveToMapRequest; }
+ }
+ [ProtoContract]
+ public partial class M2C_MoveToMapResponse : AMessage, IAddressableRouteResponse, IProto
+ {
+ public static M2C_MoveToMapResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.M2C_MoveToMapResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 发送一个消息给Gate,让Gate发送一个Addressable消息给MAP
+ ///
+ [ProtoContract]
+ public partial class C2G_SendAddressableToMap : AMessage, IMessage, IProto
+ {
+ public static C2G_SendAddressableToMap Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2G_SendAddressableToMap; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 发送一个消息给Chat,让Chat服务器主动推送一个RouteMessage消息给客户端
+ ///
+ [ProtoContract]
+ public partial class C2Chat_TestRequestPushMessage : AMessage, ICustomRouteMessage, IProto
+ {
+ public static C2Chat_TestRequestPushMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2Chat_TestRequestPushMessage; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.ChatRoute;
+ }
+ ///
+ /// Chat服务器主动推送一个消息给客户端
+ ///
+ [ProtoContract]
+ public partial class Chat2C_PushMessage : AMessage, ICustomRouteMessage, IProto
+ {
+ public static Chat2C_PushMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Chat2C_PushMessage; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.ChatRoute;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 客户端发送给Gate服务器通知map服务器创建一个SubScene
+ ///
+ [ProtoContract]
+ public partial class C2G_CreateSubSceneRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_CreateSubSceneRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_CreateSubSceneResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_CreateSubSceneRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_CreateSubSceneResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_CreateSubSceneResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_CreateSubSceneResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 客户端通知Gate服务器给SubScene发送一个消息
+ ///
+ [ProtoContract]
+ public partial class C2G_SendToSubSceneMessage : AMessage, IMessage, IProto
+ {
+ public static C2G_SendToSubSceneMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2G_SendToSubSceneMessage; }
+ }
+ ///
+ /// 客户端通知Gate服务器创建一个SubScene的Address消息
+ ///
+ [ProtoContract]
+ public partial class C2G_CreateSubSceneAddressableRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_CreateSubSceneAddressableRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_CreateSubSceneAddressableResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_CreateSubSceneAddressableRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_CreateSubSceneAddressableResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_CreateSubSceneAddressableResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_CreateSubSceneAddressableResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 客户端向SubScene发送一个测试消息
+ ///
+ [ProtoContract]
+ public partial class C2SubScene_TestMessage : AMessage, IAddressableRouteMessage, IProto
+ {
+ public static C2SubScene_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2SubScene_TestMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 客户端向SubScene发送一个销毁测试消息
+ ///
+ [ProtoContract]
+ public partial class C2SubScene_TestDisposeMessage : AMessage, IAddressableRouteMessage, IProto
+ {
+ public static C2SubScene_TestDisposeMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2SubScene_TestDisposeMessage; }
+ }
+ ///
+ /// 客户端向服务器发送连接消息(Roaming)
+ ///
+ [ProtoContract]
+ public partial class C2G_ConnectRoamingRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_ConnectRoamingRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_ConnectRoamingResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_ConnectRoamingRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_ConnectRoamingResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_ConnectRoamingResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_ConnectRoamingResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 测试一个Chat漫游普通消息
+ ///
+ [ProtoContract]
+ public partial class C2Chat_TestRoamingMessage : AMessage, IRoamingMessage, IProto
+ {
+ public static C2Chat_TestRoamingMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2Chat_TestRoamingMessage; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RoamingType.ChatRoamingType;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 测试一个Map漫游普通消息
+ ///
+ [ProtoContract]
+ public partial class C2Map_TestRoamingMessage : AMessage, IRoamingMessage, IProto
+ {
+ public static C2Map_TestRoamingMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2Map_TestRoamingMessage; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RoamingType.MapRoamingType;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 测试一个Chat漫游RPC消息
+ ///
+ [ProtoContract]
+ public partial class C2Chat_TestRPCRoamingRequest : AMessage, IRoamingRequest, IProto
+ {
+ public static C2Chat_TestRPCRoamingRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public Chat2C_TestRPCRoamingResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2Chat_TestRPCRoamingRequest; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RoamingType.ChatRoamingType;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class Chat2C_TestRPCRoamingResponse : AMessage, IRoamingResponse, IProto
+ {
+ public static Chat2C_TestRPCRoamingResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Chat2C_TestRPCRoamingResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 客户端发送一个漫游消息给Map通知Map主动推送一个消息给客户端
+ ///
+ [ProtoContract]
+ public partial class C2Map_PushMessageToClient : AMessage, IRoamingMessage, IProto
+ {
+ public static C2Map_PushMessageToClient Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2Map_PushMessageToClient; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RoamingType.MapRoamingType;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 漫游端发送一个消息给客户端
+ ///
+ [ProtoContract]
+ public partial class Map2C_PushMessageToClient : AMessage, IRoamingMessage, IProto
+ {
+ public static Map2C_PushMessageToClient Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Map2C_PushMessageToClient; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RoamingType.MapRoamingType;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 测试传送漫游的触发协议
+ ///
+ [ProtoContract]
+ public partial class C2Map_TestTransferRequest : AMessage, IRoamingRequest, IProto
+ {
+ public static C2Map_TestTransferRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public Map2C_TestTransferResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2Map_TestTransferRequest; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RoamingType.MapRoamingType;
+ }
+ [ProtoContract]
+ public partial class Map2C_TestTransferResponse : AMessage, IRoamingResponse, IProto
+ {
+ public static Map2C_TestTransferResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Map2C_TestTransferResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 测试一个Chat发送到Map之间漫游协议
+ ///
+ [ProtoContract]
+ public partial class C2Chat_TestSendMapMessage : AMessage, IRoamingMessage, IProto
+ {
+ public static C2Chat_TestSendMapMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2Chat_TestSendMapMessage; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RoamingType.ChatRoamingType;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+}
diff --git a/Entity/Generate/NetworkProtocol/OuterOpcode.cs b/Entity/Generate/NetworkProtocol/OuterOpcode.cs
new file mode 100644
index 0000000..c37210e
--- /dev/null
+++ b/Entity/Generate/NetworkProtocol/OuterOpcode.cs
@@ -0,0 +1,44 @@
+namespace Fantasy
+{
+ public static partial class OuterOpcode
+ {
+ public const uint C2G_TestMessage = 134227729;
+ public const uint C2G_TestRequest = 268445457;
+ public const uint G2C_TestResponse = 402663185;
+ public const uint C2G_TestRequestPushMessage = 134227730;
+ public const uint G2C_PushMessage = 134227731;
+ public const uint C2G_CreateAddressableRequest = 268445458;
+ public const uint G2C_CreateAddressableResponse = 402663186;
+ public const uint C2M_TestMessage = 1342187281;
+ public const uint C2M_TestRequest = 1476405009;
+ public const uint M2C_TestResponse = 1610622737;
+ public const uint C2G_CreateChatRouteRequest = 268445459;
+ public const uint G2C_CreateChatRouteResponse = 402663187;
+ public const uint C2Chat_TestMessage = 2147493649;
+ public const uint C2Chat_TestMessageRequest = 2281711377;
+ public const uint Chat2C_TestMessageResponse = 2415929105;
+ public const uint C2M_MoveToMapRequest = 1476405010;
+ public const uint M2C_MoveToMapResponse = 1610622738;
+ public const uint C2G_SendAddressableToMap = 134227732;
+ public const uint C2Chat_TestRequestPushMessage = 2147493650;
+ public const uint Chat2C_PushMessage = 2147493651;
+ public const uint C2G_CreateSubSceneRequest = 268445460;
+ public const uint G2C_CreateSubSceneResponse = 402663188;
+ public const uint C2G_SendToSubSceneMessage = 134227733;
+ public const uint C2G_CreateSubSceneAddressableRequest = 268445461;
+ public const uint G2C_CreateSubSceneAddressableResponse = 402663189;
+ public const uint C2SubScene_TestMessage = 1342187282;
+ public const uint C2SubScene_TestDisposeMessage = 1342187283;
+ public const uint C2G_ConnectRoamingRequest = 268445462;
+ public const uint G2C_ConnectRoamingResponse = 402663190;
+ public const uint C2Chat_TestRoamingMessage = 2550146833;
+ public const uint C2Map_TestRoamingMessage = 2550146834;
+ public const uint C2Chat_TestRPCRoamingRequest = 2684364561;
+ public const uint Chat2C_TestRPCRoamingResponse = 2818582289;
+ public const uint C2Map_PushMessageToClient = 2550146835;
+ public const uint Map2C_PushMessageToClient = 2550146836;
+ public const uint C2Map_TestTransferRequest = 2684364562;
+ public const uint Map2C_TestTransferResponse = 2818582290;
+ public const uint C2Chat_TestSendMapMessage = 2550146837;
+ }
+}
diff --git a/Entity/Generate/NetworkProtocol/RoamingType.cs b/Entity/Generate/NetworkProtocol/RoamingType.cs
new file mode 100644
index 0000000..96d932c
--- /dev/null
+++ b/Entity/Generate/NetworkProtocol/RoamingType.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+namespace Fantasy
+{
+ // Roaming协议定义(需要定义10000以上、因为10000以内的框架预留)
+ public static class RoamingType
+ {
+ public const int MapRoamingType = 10001;
+ public const int ChatRoamingType = 10002;
+ public static IEnumerable RoamingTypes
+ {
+ get
+ {
+ yield return 10001;
+ yield return 10002;
+ }
+ }
+ }
+}
diff --git a/Entity/Generate/NetworkProtocol/RouteType.cs b/Entity/Generate/NetworkProtocol/RouteType.cs
new file mode 100644
index 0000000..cdd0df0
--- /dev/null
+++ b/Entity/Generate/NetworkProtocol/RouteType.cs
@@ -0,0 +1,9 @@
+namespace Fantasy
+{
+ // Route协议定义(需要定义1000以上、因为1000以内的框架预留)
+ public static class RouteType
+ {
+ public const int GateRoute = 1001; // Gate
+ public const int ChatRoute = 1002; // Chat
+ }
+}
diff --git a/Entity/Model/Addressable/Unit.cs b/Entity/Model/Addressable/Unit.cs
new file mode 100644
index 0000000..189609d
--- /dev/null
+++ b/Entity/Model/Addressable/Unit.cs
@@ -0,0 +1,8 @@
+using Fantasy.Entitas;
+
+namespace Fantasy;
+
+public sealed class Unit : Entity
+{
+
+}
\ No newline at end of file
diff --git a/Entity/Model/RouteMessage/ChatUnit.cs b/Entity/Model/RouteMessage/ChatUnit.cs
new file mode 100644
index 0000000..4120d1f
--- /dev/null
+++ b/Entity/Model/RouteMessage/ChatUnit.cs
@@ -0,0 +1,19 @@
+using Fantasy.Entitas;
+
+namespace Fantasy;
+
+public sealed class ChatUnit : Entity
+{
+ public long GateRouteId;
+
+ public override void Dispose()
+ {
+ if (IsDisposed)
+ {
+ return;
+ }
+
+ GateRouteId = 0;
+ base.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/Entity/Model/SubScene/GateSubSceneFlagComponent.cs b/Entity/Model/SubScene/GateSubSceneFlagComponent.cs
new file mode 100644
index 0000000..bd7fda7
--- /dev/null
+++ b/Entity/Model/SubScene/GateSubSceneFlagComponent.cs
@@ -0,0 +1,14 @@
+using Fantasy.Entitas;
+
+namespace Fantasy;
+
+public sealed class GateSubSceneFlagComponent : Entity
+{
+ public long SubSceneRouteId;
+
+ public override void Dispose()
+ {
+ SubSceneRouteId = 0;
+ base.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Benchmark/ConsoleLog.cs b/Fantasy/Fantasy.Benchmark/ConsoleLog.cs
new file mode 100644
index 0000000..4fa540f
--- /dev/null
+++ b/Fantasy/Fantasy.Benchmark/ConsoleLog.cs
@@ -0,0 +1,138 @@
+
+#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
+
+namespace Fantasy
+{
+ ///
+ /// 标准的控制台Log
+ ///
+ public sealed class ConsoleLog : ILog
+ {
+
+ ///
+ /// 记录跟踪级别的日志消息。
+ ///
+ /// 日志消息。
+ public void Trace(string message)
+ {
+ System.Console.ForegroundColor = ConsoleColor.White;
+ System.Console.WriteLine(message);
+ }
+
+ ///
+ /// 记录警告级别的日志消息。
+ ///
+ /// 日志消息。
+ public void Warning(string message)
+ {
+ System.Console.ForegroundColor = ConsoleColor.Yellow;
+ System.Console.WriteLine(message);
+ }
+
+ ///
+ /// 记录信息级别的日志消息。
+ ///
+ /// 日志消息。
+ public void Info(string message)
+ {
+ System.Console.ForegroundColor = ConsoleColor.Gray;
+ System.Console.WriteLine(message);
+ }
+
+ ///
+ /// 记录调试级别的日志消息。
+ ///
+ /// 日志消息。
+ public void Debug(string message)
+ {
+ System.Console.ForegroundColor = ConsoleColor.DarkGreen;
+ System.Console.WriteLine(message);
+ }
+
+ ///
+ /// 记录错误级别的日志消息。
+ ///
+ /// 日志消息。
+ public void Error(string message)
+ {
+ System.Console.ForegroundColor = ConsoleColor.DarkRed;
+ System.Console.WriteLine(message);
+ }
+
+ ///
+ /// 记录严重错误级别的日志消息。
+ ///
+ /// 日志消息。
+ public void Fatal(string message)
+ {
+ System.Console.ForegroundColor = ConsoleColor.Red;
+ System.Console.WriteLine(message);
+ }
+
+ ///
+ /// 记录跟踪级别的格式化日志消息。
+ ///
+ /// 日志消息模板。
+ /// 格式化参数。
+ public void Trace(string message, params object[] args)
+ {
+ System.Console.ForegroundColor = ConsoleColor.White;
+ System.Console.WriteLine(message, args);
+ }
+
+ ///
+ /// 记录警告级别的格式化日志消息。
+ ///
+ /// 日志消息模板。
+ /// 格式化参数。
+ public void Warning(string message, params object[] args)
+ {
+ System.Console.ForegroundColor = ConsoleColor.Yellow;
+ System.Console.WriteLine(message, args);
+ }
+
+ ///
+ /// 记录信息级别的格式化日志消息。
+ ///
+ /// 日志消息模板。
+ /// 格式化参数。
+ public void Info(string message, params object[] args)
+ {
+ System.Console.ForegroundColor = ConsoleColor.Gray;
+ System.Console.WriteLine(message, args);
+ }
+
+ ///
+ /// 记录调试级别的格式化日志消息。
+ ///
+ /// 日志消息模板。
+ /// 格式化参数。
+ public void Debug(string message, params object[] args)
+ {
+ System.Console.ForegroundColor = ConsoleColor.DarkGreen;
+ System.Console.WriteLine(message, args);
+ }
+
+ ///
+ /// 记录错误级别的格式化日志消息。
+ ///
+ /// 日志消息模板。
+ /// 格式化参数。
+ public void Error(string message, params object[] args)
+ {
+ System.Console.ForegroundColor = ConsoleColor.DarkRed;
+ System.Console.WriteLine(message, args);
+ }
+
+ ///
+ /// 记录严重错误级别的格式化日志消息。
+ ///
+ /// 日志消息模板。
+ /// 格式化参数。
+ public void Fatal(string message, params object[] args)
+ {
+ System.Console.ForegroundColor = ConsoleColor.Red;
+ System.Console.WriteLine(message, args);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Benchmark/Fantasy.Benchmark.csproj b/Fantasy/Fantasy.Benchmark/Fantasy.Benchmark.csproj
new file mode 100644
index 0000000..d44402a
--- /dev/null
+++ b/Fantasy/Fantasy.Benchmark/Fantasy.Benchmark.csproj
@@ -0,0 +1,33 @@
+
+
+
+ Exe
+ enable
+ enable
+ net8.0;net9.0
+ default
+
+
+
+ TRACE;FANTASY_CONSOLE
+ true
+
+
+
+ TRACE;FANTASY_CONSOLE
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Fantasy/Fantasy.Benchmark/NetworkBenchmark.cs b/Fantasy/Fantasy.Benchmark/NetworkBenchmark.cs
new file mode 100644
index 0000000..18e3ea1
--- /dev/null
+++ b/Fantasy/Fantasy.Benchmark/NetworkBenchmark.cs
@@ -0,0 +1,45 @@
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Jobs;
+using BenchmarkDotNet.Running;
+using Fantasy.Async;
+using Fantasy.InnerMessage;
+using Fantasy.Network;
+using Fantasy.Platform.Console;
+
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
+
+namespace Fantasy.Benchmark;
+[SimpleJob(RuntimeMoniker.Net80, baseline: true)]
+public class NetworkBenchmark
+{
+ private static Scene _scene;
+ private static Session _session;
+ private readonly BenchmarkRequest _benchmarkRequest = new BenchmarkRequest();
+
+ public static async FTask Initialize()
+ {
+ // 注册日志实例到框架中
+ Log.Register(new ConsoleLog());
+ // 初始化框架
+ await Entry.Initialize();
+ // 执行StartUpdate方法
+ Entry.StartUpdate();
+ _scene = await Entry.CreateScene();
+ // 创建远程连接
+ _session = _scene.Connect("127.0.0.1:20000", NetworkProtocolType.WebSocket,
+ () =>
+ {
+ Log.Debug("连接到目标服务器成功");
+ var summary = BenchmarkRunner.Run();
+ Console.WriteLine(summary);
+ },
+ () => { Log.Debug("无法连接到目标服务器"); },
+ () => { Log.Debug("与服务器断开连接"); }, false);
+ }
+
+ [Benchmark]
+ public async FTask Call()
+ {
+ await _session.Call(_benchmarkRequest);
+ }
+}
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Benchmark/Program.cs b/Fantasy/Fantasy.Benchmark/Program.cs
new file mode 100644
index 0000000..30d8cf3
--- /dev/null
+++ b/Fantasy/Fantasy.Benchmark/Program.cs
@@ -0,0 +1,2 @@
+Fantasy.Benchmark.NetworkBenchmark.Initialize().Coroutine();
+Console.ReadKey();
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Benchmark/README.md b/Fantasy/Fantasy.Benchmark/README.md
new file mode 100644
index 0000000..8315cc4
--- /dev/null
+++ b/Fantasy/Fantasy.Benchmark/README.md
@@ -0,0 +1,6 @@
+# Fantasy.Benchmark
+使用 Fantasy.Benchmark 工具,我们能够快速评估框架网络的处理性能。目前,该工具提供的基准测试主要集中在 RPC(远程过程调用)消息 方面。这一项测试能够有效测量系统在处理远程调用时的响应时间、吞吐量和资源利用率,帮助开发者优化网络通信性能,确保在高负载情况下系统依然能够稳定运行
+## 操作步骤
+- 1.打开位于 Examples/Server/Server.sln 的解决方案文件。
+- 2.在解决方案中选择并启动 Main 项目。
+- 3.接着,启动 Fantasy.Benchmark 应用程序,并耐心等待其测试结果的生成。
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net.sln b/Fantasy/Fantasy.Net/Fantasy.Net.sln
new file mode 100644
index 0000000..1abdc06
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net.sln
@@ -0,0 +1,16 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Net", "Fantasy.Net\Fantasy.Net.csproj", "{636FBF87-A6D2-4A31-86FF-F4157F558C95}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {636FBF87-A6D2-4A31-86FF-F4157F558C95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {636FBF87-A6D2-4A31-86FF-F4157F558C95}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {636FBF87-A6D2-4A31-86FF-F4157F558C95}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {636FBF87-A6D2-4A31-86FF-F4157F558C95}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy-Net.targets b/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy-Net.targets
new file mode 100644
index 0000000..5426ed6
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy-Net.targets
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj b/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj
new file mode 100644
index 0000000..732718c
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj
@@ -0,0 +1,61 @@
+
+
+
+ Fantasy-Net
+ 2024.2.26
+ Fantasy-Net
+ qq362946
+ qq362946
+ ../../nupkg
+ false
+
+ Fantasy is a high-performance network development framework based on .NET, supporting mainstream protocols. It is designed for development teams or individuals needing a quick start, scalability, and a distributed, cross-platform solution at the commercial level. Fantasy aims to provide easy-to-use tools while ensuring high system performance and scalability.
+ Copyright 2026 qq362946
+ LICENSE
+ README.md
+ https://www.code-fantasy.com/
+ https://github.com/qq362946/Fantasy
+ git
+ Net, c#, Server, Game, GameServer, Fantasy , Network
+ icon.png
+ enable
+ enable
+ Fantasy-Net
+ net8.0;net9.0
+ default
+
+
+
+ TRACE;FANTASY_NET
+ true
+ true
+ bin\Debug\net8.0\Fantasy.Net.xml
+
+
+
+ TRACE;FANTASY_NET
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/LICENSE b/Fantasy/Fantasy.Net/Fantasy.Net/LICENSE
new file mode 100644
index 0000000..24a69b2
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/LICENSE
@@ -0,0 +1,14 @@
+MIT License
+
+Copyright (c) 2023 qq362946
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+However, the following entity is explicitly prohibited from using, copying, modifying, or distributing the Software or any of its portions:
+
+泰课在线(https://www.taikr.com/)
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/README.md b/Fantasy/Fantasy.Net/Fantasy.Net/README.md
new file mode 100644
index 0000000..582e668
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/README.md
@@ -0,0 +1,34 @@
+# Fantasy
+#### 框架支持TCP\KCP\WebSocket\http(支持Unity发布成H5)三种网络协议,采用的Protobuf/MemoryPack/Bson做为消息的序列化方案。
+#### Fantasy是基于.NET的高性能网络开发框架,支持主流协议,前后端分离,适合需要快速上手、可扩展、分布式全平台商业级解决方案的开发团队或个人。它旨在提供易用工具,同时保证系统的高性能和扩展性。
+## 导航
+* [Fantasy介绍网站](https://www.code-fantasy.com/)
+* [Fantasy的API文档](https://www.code-fantasy.com/doc/api/Fantasy.html)
+* [入门视频观看地址](https://space.bilibili.com/382126312)
+## 快速上手
+* 01.快速入门
+ * [1.1.获得Fantasy](https://www.code-fantasy.com/top/download-fantasy/)
+ * [1.2.安装Fantasy](https://www.code-fantasy.com/top/creating-your-app/)
+ * [1.3.Fantasy的网络](https://www.code-fantasy.com/top/use-network/)
+ * [1.4.Fantasy的配置文件](https://www.code-fantasy.com/top/config-file/)
+ * [1.5.Fantasy的命令行参数](https://www.code-fantasy.com/top/command-line-parameter/)
+ * [1.6.Fantasy的导表工具](https://www.code-fantasy.com/top/guidance/)
+ * [1.7.如何升级到最新版](https://www.code-fantasy.com/top/upgrade/)
+* 02.网络通信
+ * [2.1.客户端服务器之间发送消息](https://www.code-fantasy.com/network/session/)
+ * [2.2.服务器之间发送消息](https://www.code-fantasy.com/network/networkmessagingomponent/)
+ * [2.3.定义通信协议](https://www.code-fantasy.com/network/network-protocols/)
+ * [2.4.Route通信协议](https://www.code-fantasy.com/network/network-route/)
+ * [2.5.Addressable通信协议](https://www.code-fantasy.com/network/network-addressable/)
+* 03.系统组件
+ * [3.1.ECS系统](https://www.code-fantasy.com/core/ecs/)
+ * [3.2.事件系统](https://www.code-fantasy.com/core/event/)
+ * [3.3.任务系统](https://www.code-fantasy.com/core/task/)
+ * [3.4.异步协程锁](https://www.code-fantasy.com/core/lock/)
+ * [3.5.数据库](https://www.code-fantasy.com/core/db/)
+* [更新日志](https://www.code-fantasy.com/changelog/)
+* [API文档](https://www.code-fantasy.com/doc/api/Fantasy.html)
+* [常见问题](https://www.code-fantasy.com/question/)
+
+## 交流与讨论:
+__讨论QQ群 : Fantasy服务器开发交流群 569888673 __
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblyInfo.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblyInfo.cs
new file mode 100644
index 0000000..3957539
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblyInfo.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Fantasy.DataStructure.Collection;
+
+// ReSharper disable CollectionNeverQueried.Global
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
+
+namespace Fantasy.Assembly
+{
+ ///
+ /// AssemblyInfo提供有关程序集和类型的信息
+ ///
+ public sealed class AssemblyInfo
+ {
+ ///
+ /// 唯一标识
+ ///
+ public readonly long AssemblyIdentity;
+ ///
+ /// 获取或设置与此程序集相关联的 实例。
+ ///
+ public System.Reflection.Assembly Assembly { get; private set; }
+ ///
+ /// 程序集类型集合,获取一个列表,包含从程序集加载的所有类型。
+ ///
+ public readonly List AssemblyTypeList = new List();
+ ///
+ /// 程序集类型分组集合,获取一个分组列表,将接口类型映射到实现这些接口的类型。
+ ///
+ public readonly OneToManyList AssemblyTypeGroupList = new OneToManyList();
+
+ ///
+ /// 初始化 类的新实例。
+ ///
+ ///
+ public AssemblyInfo(long assemblyIdentity)
+ {
+ AssemblyIdentity = assemblyIdentity;
+ }
+
+ ///
+ /// 从指定的程序集加载类型信息并进行分类。
+ ///
+ /// 要加载信息的程序集。
+ public void Load(System.Reflection.Assembly assembly)
+ {
+ Assembly = assembly;
+ var assemblyTypes = assembly.GetTypes().ToList();
+
+ foreach (var type in assemblyTypes)
+ {
+ if (type.IsAbstract || type.IsInterface)
+ {
+ continue;
+ }
+
+ var interfaces = type.GetInterfaces();
+
+ foreach (var interfaceType in interfaces)
+ {
+ AssemblyTypeGroupList.Add(interfaceType, type);
+ }
+ }
+
+ AssemblyTypeList.AddRange(assemblyTypes);
+ }
+
+ ///
+ /// 重新加载程序集的类型信息。
+ ///
+ ///
+ public void ReLoad(System.Reflection.Assembly assembly)
+ {
+ Unload();
+ Load(assembly);
+ }
+
+ ///
+ /// 卸载程序集的类型信息。
+ ///
+ public void Unload()
+ {
+ AssemblyTypeList.Clear();
+ AssemblyTypeGroupList.Clear();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblySystem.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblySystem.cs
new file mode 100644
index 0000000..deb9da6
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblySystem.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Security.Cryptography;
+using System.Text;
+using Fantasy.Async;
+using Fantasy.Helper;
+#pragma warning disable CS8604 // Possible null reference argument.
+#pragma warning disable CS8602 // Dereference of a possibly null reference.
+#pragma warning disable CS8603
+#pragma warning disable CS8618
+namespace Fantasy.Assembly
+{
+ ///
+ /// 管理程序集加载和卸载的帮助类。
+ ///
+ public static class AssemblySystem
+ {
+#if FANTASY_WEBGL
+ private static readonly List AssemblySystems = new List();
+ private static readonly Dictionary AssemblyList = new Dictionary();
+#else
+ private static readonly ConcurrentQueue AssemblySystems = new ConcurrentQueue();
+ private static readonly ConcurrentDictionary AssemblyList = new ConcurrentDictionary();
+#endif
+ ///
+ /// 初始化 AssemblySystem。(仅限内部)
+ ///
+ ///
+ internal static async FTask InnerInitialize(params System.Reflection.Assembly[] assemblies)
+ {
+ await LoadAssembly(typeof(AssemblySystem).Assembly);
+ foreach (var assembly in assemblies)
+ {
+ await LoadAssembly(assembly);
+ }
+ }
+
+ ///
+ /// 加载指定的程序集,并触发相应的事件。
+ ///
+ /// 要加载的程序集。
+ /// 如果当前Domain中已经存在同名的Assembly,使用Domain中的程序集。
+ public static async FTask LoadAssembly(System.Reflection.Assembly assembly, bool isCurrentDomain = true)
+ {
+ if (isCurrentDomain)
+ {
+ var currentDomainAssemblies = System.AppDomain.CurrentDomain.GetAssemblies();
+ var currentAssembly = currentDomainAssemblies.FirstOrDefault(d => d.GetName().Name == assembly.GetName().Name);
+ if (currentAssembly != null)
+ {
+ assembly = currentAssembly;
+ }
+ }
+
+ var assemblyIdentity = AssemblyIdentity(assembly);
+
+ if (AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo))
+ {
+ assemblyInfo.ReLoad(assembly);
+ foreach (var assemblySystem in AssemblySystems)
+ {
+ await assemblySystem.ReLoad(assemblyIdentity);
+ }
+ }
+ else
+ {
+ assemblyInfo = new AssemblyInfo(assemblyIdentity);
+ assemblyInfo.Load(assembly);
+ AssemblyList.TryAdd(assemblyIdentity, assemblyInfo);
+ foreach (var assemblySystem in AssemblySystems)
+ {
+ await assemblySystem.Load(assemblyIdentity);
+ }
+ }
+ }
+
+ ///
+ /// 卸载程序集
+ ///
+ ///
+ public static async FTask UnLoadAssembly(System.Reflection.Assembly assembly)
+ {
+ var assemblyIdentity = AssemblyIdentity(assembly);
+
+ if (!AssemblyList.Remove(assemblyIdentity, out var assemblyInfo))
+ {
+ return;
+ }
+
+ assemblyInfo.Unload();
+ foreach (var assemblySystem in AssemblySystems)
+ {
+ await assemblySystem.OnUnLoad(assemblyIdentity);
+ }
+ }
+
+ ///
+ /// 将AssemblySystem接口的object注册到程序集管理中心
+ ///
+ ///
+ public static async FTask Register(object obj)
+ {
+ if (obj is not IAssembly assemblySystem)
+ {
+ return;
+ }
+#if FANTASY_WEBGL
+ AssemblySystems.Add(assemblySystem);
+#else
+ AssemblySystems.Enqueue(assemblySystem);
+#endif
+ foreach (var (assemblyIdentity, _) in AssemblyList)
+ {
+ await assemblySystem.Load(assemblyIdentity);
+ }
+ }
+
+ ///
+ /// 程序集管理中心卸载注册的Load、ReLoad、UnLoad的接口
+ ///
+ ///
+ public static void UnRegister(object obj)
+ {
+ if (obj is not IAssembly assemblySystem)
+ {
+ return;
+ }
+#if FANTASY_WEBGL
+ AssemblySystems.Remove(assemblySystem);
+#else
+ var count = AssemblySystems.Count;
+
+ for (var i = 0; i < count; i++)
+ {
+ if (!AssemblySystems.TryDequeue(out var removeAssemblySystem))
+ {
+ continue;
+ }
+
+ if (removeAssemblySystem == assemblySystem)
+ {
+ break;
+ }
+
+ AssemblySystems.Enqueue(removeAssemblySystem);
+ }
+#endif
+ }
+
+ ///
+ /// 获取所有已加载程序集中的所有类型。
+ ///
+ /// 所有已加载程序集中的类型。
+ public static IEnumerable ForEach()
+ {
+ foreach (var (_, assemblyInfo) in AssemblyList)
+ {
+ foreach (var type in assemblyInfo.AssemblyTypeList)
+ {
+ yield return type;
+ }
+ }
+ }
+
+ ///
+ /// 获取指定程序集中的所有类型。
+ ///
+ /// 程序集唯一标识。
+ /// 指定程序集中的类型。
+ public static IEnumerable ForEach(long assemblyIdentity)
+ {
+ if (!AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo))
+ {
+ yield break;
+ }
+
+ foreach (var type in assemblyInfo.AssemblyTypeList)
+ {
+ yield return type;
+ }
+ }
+
+ ///
+ /// 获取所有已加载程序集中实现指定类型的所有类型。
+ ///
+ /// 要查找的基类或接口类型。
+ /// 所有已加载程序集中实现指定类型的类型。
+ public static IEnumerable ForEach(Type findType)
+ {
+ foreach (var (_, assemblyInfo) in AssemblyList)
+ {
+ if (!assemblyInfo.AssemblyTypeGroupList.TryGetValue(findType, out var assemblyLoad))
+ {
+ continue;
+ }
+
+ foreach (var type in assemblyLoad)
+ {
+ yield return type;
+ }
+ }
+ }
+
+ ///
+ /// 获取指定程序集中实现指定类型的所有类型。
+ ///
+ /// 程序集唯一标识。
+ /// 要查找的基类或接口类型。
+ /// 指定程序集中实现指定类型的类型。
+ public static IEnumerable ForEach(long assemblyIdentity, Type findType)
+ {
+ if (!AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo))
+ {
+ yield break;
+ }
+
+ if (!assemblyInfo.AssemblyTypeGroupList.TryGetValue(findType, out var assemblyLoad))
+ {
+ yield break;
+ }
+
+ foreach (var type in assemblyLoad)
+ {
+ yield return type;
+ }
+ }
+
+ ///
+ /// 获取指定程序集的实例。
+ ///
+ /// 程序集名称。
+ /// 指定程序集的实例,如果未加载则返回 null。
+ public static System.Reflection.Assembly GetAssembly(long assemblyIdentity)
+ {
+ return !AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo) ? null : assemblyInfo.Assembly;
+ }
+
+ ///
+ /// 获取当前框架注册的Assembly
+ ///
+ ///
+ public static IEnumerable ForEachAssembly
+ {
+ get
+ {
+ foreach (var (_, assemblyInfo) in AssemblyList)
+ {
+ yield return assemblyInfo.Assembly;
+ }
+ }
+ }
+
+ ///
+ /// 根据Assembly的强命名计算唯一标识。
+ ///
+ ///
+ ///
+ private static long AssemblyIdentity(System.Reflection.Assembly assembly)
+ {
+ return HashCodeHelper.ComputeHash64(assembly.GetName().Name);
+ }
+
+ ///
+ /// 释放资源,卸载所有加载的程序集。
+ ///
+ public static void Dispose()
+ {
+ DisposeAsync().Coroutine();
+ }
+
+ private static async FTask DisposeAsync()
+ {
+ foreach (var (_, assemblyInfo) in AssemblyList.ToArray())
+ {
+ await UnLoadAssembly(assemblyInfo.Assembly);
+ }
+
+ AssemblyList.Clear();
+ AssemblySystems.Clear();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/IAssembly.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/IAssembly.cs
new file mode 100644
index 0000000..185e037
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/IAssembly.cs
@@ -0,0 +1,27 @@
+using System;
+using Fantasy.Async;
+
+namespace Fantasy.Assembly
+{
+ ///
+ /// 实现这个接口、会再程序集首次加载、卸载、重载的时候调用
+ ///
+ public interface IAssembly : IDisposable
+ {
+ ///
+ /// 程序集加载时调用
+ ///
+ /// 程序集标识
+ public FTask Load(long assemblyIdentity);
+ ///
+ /// 程序集重新加载的时候调用
+ ///
+ /// 程序集标识
+ public FTask ReLoad(long assemblyIdentity);
+ ///
+ /// 卸载的时候调用
+ ///
+ /// 程序集标识
+ public FTask OnUnLoad(long assemblyIdentity);
+ }
+}
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs
new file mode 100644
index 0000000..8532547
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs
@@ -0,0 +1,25 @@
+using Fantasy.Async;
+using Fantasy.InnerMessage;
+using Fantasy.Network.Interface;
+
+#if FANTASY_NET
+namespace Fantasy.Network.Benchmark.Handler;
+
+///
+/// BenchmarkRequestHandler
+///
+public sealed class BenchmarkRequestHandler : MessageRPC
+{
+ ///
+ /// Run方法
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected override async FTask Run(Session session, BenchmarkRequest request, BenchmarkResponse response, Action reply)
+ {
+ await FTask.CompletedTask;
+ }
+}
+#endif
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/DataBaseType.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/DataBaseType.cs
new file mode 100644
index 0000000..2fb03ec
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/DataBaseType.cs
@@ -0,0 +1,20 @@
+// ReSharper disable CheckNamespace
+// ReSharper disable InconsistentNaming
+#if FANTASY_NET
+namespace Fantasy.DataBase;
+
+///
+/// 数据库类型
+///
+public enum DataBaseType
+{
+ ///
+ /// 默认
+ ///
+ None = 0,
+ ///
+ /// MongoDB
+ ///
+ MongoDB = 1
+}
+#endif
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/IDataBase.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/IDataBase.cs
new file mode 100644
index 0000000..6a2fe8b
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/IDataBase.cs
@@ -0,0 +1,210 @@
+#if FANTASY_NET
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using Fantasy.Async;
+using Fantasy.Entitas;
+using MongoDB.Driver;
+// ReSharper disable InconsistentNaming
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
+
+#pragma warning disable CS8625
+
+namespace Fantasy.DataBase
+{
+ ///
+ /// 数据库设置助手
+ ///
+ public static class DataBaseSetting
+ {
+ ///
+ /// 初始化自定义委托,当设置了这个委托后,就不会自动创建MongoClient,需要自己在委托里创建MongoClient。
+ ///
+ public static Func? MongoDBCustomInitialize;
+ }
+
+ ///
+ /// MongoDB自定义连接参数
+ ///
+ public sealed class DataBaseCustomConfig
+ {
+ ///
+ /// 当前Scene
+ ///
+ public Scene Scene;
+ ///
+ /// 连接字符串
+ ///
+ public string ConnectionString;
+ ///
+ /// 数据库名字
+ ///
+ public string DBName;
+ }
+
+ ///
+ /// 表示用于执行各种数据库操作的数据库接口。
+ ///
+ public interface IDataBase : IDisposable
+ {
+ ///
+ /// 获得当前数据的类型
+ ///
+ public DataBaseType GetDataBaseType { get;}
+ ///
+ /// 获得对应数据的操作实例
+ ///
+ /// 如MongoDB就是IMongoDatabase
+ public object GetDataBaseInstance { get;}
+ ///
+ /// 初始化数据库连接。
+ ///
+ IDataBase Initialize(Scene scene, string connectionString, string dbName);
+ ///
+ /// 在指定的集合中检索类型 的实体数量。
+ ///
+ FTask Count(string collection = null) where T : Entity;
+ ///
+ /// 在指定的集合中检索满足给定筛选条件的类型 的实体数量。
+ ///
+ FTask Count(Expression> filter, string collection = null) where T : Entity;
+ ///
+ /// 检查指定集合中是否存在类型 的实体。
+ ///
+ FTask Exist(string collection = null) where T : Entity;
+ ///
+ /// 检查指定集合中是否存在满足给定筛选条件的类型 的实体。
+ ///
+ FTask Exist(Expression> filter, string collection = null) where T : Entity;
+ ///
+ /// 从指定集合中检索指定 ID 的类型 的实体,不锁定。
+ ///
+ FTask QueryNotLock(long id, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 从指定集合中检索指定 ID 的类型 的实体。
+ ///
+ FTask Query(long id, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 按页查询满足给定筛选条件的类型 的实体数量和日期。
+ ///
+ FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 按页查询满足给定筛选条件的类型 的实体数量和日期。
+ ///
+ FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 分页查询指定集合中满足给定筛选条件的类型 的实体列表。
+ ///
+ FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 分页查询指定集合中满足给定筛选条件的类型 的实体列表,仅返回指定列的数据。
+ ///
+ FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表,按指定字段排序。
+ ///
+ FTask> QueryByPageOrderBy(Expression> filter, int pageIndex, int pageSize, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 检索满足给定筛选条件的类型 的第一个实体,从指定集合中。
+ ///
+ FTask First(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 查询指定集合中满足给定 JSON 查询字符串的类型 的第一个实体,仅返回指定列的数据。
+ ///
+ FTask First(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表,按指定字段排序。
+ ///
+ FTask> QueryOrderBy(Expression> filter, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表。
+ ///
+ FTask> Query(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 查询指定集合中满足给定筛选条件的类型 实体列表,仅返回指定字段的数据。
+ ///
+ FTask> Query(Expression> filter, Expression>[] cols, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 查询指定 ID 的多个集合,将结果存储在给定的实体列表中。
+ ///
+ FTask Query(long id, List collectionNames, List result, bool isDeserialize = false);
+ ///
+ /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表。
+ ///
+ FTask> QueryJson(string json, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表,仅返回指定列的数据。
+ ///
+ FTask> QueryJson(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表,通过指定的任务 ID 进行标识。
+ ///
+ FTask> QueryJson(long taskId, string json, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 查询指定集合中满足给定筛选条件的类型 实体列表,仅返回指定列的数据。
+ ///
+ FTask> Query(Expression> filter, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity;
+ ///
+ /// 保存类型 实体到指定集合中,如果集合不存在将自动创建。
+ ///
+ FTask Save(T entity, string collection = null) where T : Entity, new();
+ ///
+ /// 保存一组实体到数据库中,根据实体列表的 ID 进行区分和存储。
+ ///
+ FTask Save(long id, List entities);
+ ///
+ /// 通过事务会话将类型 实体保存到指定集合中,如果集合不存在将自动创建。
+ ///
+ FTask Save(object transactionSession, T entity, string collection = null) where T : Entity;
+ ///
+ /// 向指定集合中插入一个类型 实体,如果集合不存在将自动创建。
+ ///
+ FTask Insert(T entity, string collection = null) where T : Entity, new();
+ ///
+ /// 批量插入一组类型 实体到指定集合中,如果集合不存在将自动创建。
+ ///
+ FTask InsertBatch(IEnumerable list, string collection = null) where T : Entity, new();
+ ///
+ /// 通过事务会话,批量插入一组类型 实体到指定集合中,如果集合不存在将自动创建。
+ ///
+ FTask InsertBatch(object transactionSession, IEnumerable list, string collection = null) where T : Entity, new();
+ ///
+ /// 通过事务会话,根据指定的 ID 从数据库中删除指定类型 实体。
+ ///
+ FTask Remove(object transactionSession, long id, string collection = null) where T : Entity, new();
+ ///
+ /// 根据指定的 ID 从数据库中删除指定类型 实体。
+ ///
+ FTask Remove(long id, string collection = null) where T : Entity, new();
+ ///
+ /// 通过事务会话,根据给定的筛选条件从数据库中删除指定类型 实体。
+ ///
+ FTask Remove(long coroutineLockQueueKey, object transactionSession, Expression> filter, string collection = null) where T : Entity, new();
+ ///
+ /// 根据给定的筛选条件从数据库中删除指定类型 实体。
+ ///
+ FTask Remove(long coroutineLockQueueKey, Expression> filter, string collection = null) where T : Entity, new();
+ ///
+ /// 根据给定的筛选条件计算指定集合中类型 实体某个属性的总和。
+ ///
+ FTask Sum(Expression> filter, Expression> sumExpression, string collection = null) where T : Entity;
+ ///
+ /// 在指定的集合中创建索引,以提高类型 实体的查询性能。
+ ///
+ FTask CreateIndex(string collection, params object[] keys) where T : Entity;
+ ///
+ /// 在默认集合中创建索引,以提高类型 实体的查询性能。
+ ///
+ FTask CreateIndex(params object[] keys) where T : Entity;
+ ///
+ /// 创建指定类型 的数据库,用于存储实体。
+ ///
+ FTask CreateDB() where T : Entity;
+ ///
+ /// 根据指定类型创建数据库,用于存储实体。
+ ///
+ FTask CreateDB(Type type);
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs
new file mode 100644
index 0000000..49948f4
--- /dev/null
+++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs
@@ -0,0 +1,1081 @@
+#if FANTASY_NET
+using System.Linq.Expressions;
+using Fantasy.Async;
+using Fantasy.DataStructure.Collection;
+using Fantasy.Entitas;
+using Fantasy.Helper;
+using Fantasy.Serialize;
+using MongoDB.Bson;
+using MongoDB.Driver;
+#pragma warning disable CS8602 // Dereference of a possibly null reference.
+#pragma warning disable CS8603 // Possible null reference return.
+#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
+
+namespace Fantasy.DataBase
+{
+ ///
+ /// 使用 MongoDB 数据库的实现。
+ ///
+ public sealed class MongoDataBase : IDataBase
+ {
+ private const int DefaultTaskSize = 1024;
+ private Scene _scene;
+ private MongoClient _mongoClient;
+ private ISerialize _serializer;
+ private IMongoDatabase _mongoDatabase;
+ private CoroutineLock _dataBaseLock;
+ private readonly HashSet _collections = new HashSet();
+ ///
+ /// 获得当前数据的类型
+ ///
+ public DataBaseType GetDataBaseType { get; } = DataBaseType.MongoDB;
+ ///
+ /// 获得对应数据的操作实例
+ ///
+ public object GetDataBaseInstance => _mongoDatabase;
+ ///
+ /// 初始化 MongoDB 数据库连接并记录所有集合名。
+ ///
+ /// 场景对象。
+ /// 数据库连接字符串。
+ /// 数据库名称。
+ /// 初始化后的数据库实例。
+ public IDataBase Initialize(Scene scene, string connectionString, string dbName)
+ {
+ _scene = scene;
+ _mongoClient = DataBaseSetting.MongoDBCustomInitialize != null
+ ? DataBaseSetting.MongoDBCustomInitialize(new DataBaseCustomConfig()
+ {
+ Scene = scene, ConnectionString = connectionString, DBName = dbName
+ })
+ : new MongoClient(connectionString);
+ _mongoDatabase = _mongoClient.GetDatabase(dbName);
+ _dataBaseLock = scene.CoroutineLockComponent.Create(GetType().TypeHandle.Value.ToInt64());
+ // 记录所有集合名
+ _collections.UnionWith(_mongoDatabase.ListCollectionNames().ToList());
+ _serializer = SerializerManager.GetSerializer(FantasySerializerType.Bson);
+ return this;
+ }
+
+ ///
+ /// 销毁释放资源。
+ ///
+ public void Dispose()
+ {
+ // 优先释放协程锁。
+ _dataBaseLock.Dispose();
+ // 清理资源。
+ _scene = null;
+ _serializer = null;
+ _mongoDatabase = null;
+ _dataBaseLock = null;
+ _collections.Clear();
+ _mongoClient.Dispose();
+ }
+
+ #region Other
+
+ ///
+ /// 对满足条件的文档中的某个数值字段进行求和操作。
+ ///
+ /// 实体类型。
+ /// 用于筛选文档的表达式。
+ /// 要对其进行求和的字段表达式。
+ /// 集合名称,可选。如果未指定,将使用实体类型的名称。
+ /// 满足条件的文档中指定字段的求和结果。
+ public async FTask Sum(Expression> filter, Expression> sumExpression, string collection = null) where T : Entity
+ {
+ var member = (MemberExpression)((UnaryExpression)sumExpression.Body).Operand;
+ var projection = new BsonDocument("_id", "null").Add("Result", new BsonDocument("$sum", $"${member.Member.Name}"));
+ var data = await GetCollection(collection).Aggregate().Match(filter).Group(projection).FirstOrDefaultAsync();
+ return data == null ? 0 : Convert.ToInt64(data["Result"]);
+ }
+
+ #endregion
+
+ #region GetCollection
+
+ ///
+ /// 获取指定集合中的 MongoDB 文档的 IMongoCollection 对象。
+ ///
+ /// 实体类型。
+ /// 集合名称,可选。如果未指定,将使用实体类型的名称。
+ /// IMongoCollection 对象。
+ private IMongoCollection GetCollection(string collection = null)
+ {
+ return _mongoDatabase.GetCollection(collection ?? typeof(T).Name);
+ }
+
+ ///
+ /// 获取指定集合中的 MongoDB 文档的 IMongoCollection 对象,其中实体类型为 Entity。
+ ///
+ /// 集合名称。
+ /// IMongoCollection 对象。
+ private IMongoCollection GetCollection(string name)
+ {
+ return _mongoDatabase.GetCollection(name);
+ }
+
+ #endregion
+
+ #region Count
+
+ ///
+ /// 统计指定集合中满足条件的文档数量。
+ ///
+ /// 实体类型。
+ /// 集合名称,可选。如果未指定,将使用实体类型的名称。
+ /// 满足条件的文档数量。
+ public async FTask Count(string collection = null) where T : Entity
+ {
+ return await GetCollection(collection).CountDocumentsAsync(d => true);
+ }
+
+ ///
+ /// 统计指定集合中满足条件的文档数量。
+ ///
+ /// 实体类型。
+ /// 用于筛选文档的表达式。
+ /// 集合名称,可选。如果未指定,将使用实体类型的名称。
+ /// 满足条件的文档数量。
+ public async FTask Count(Expression> filter, string collection = null) where T : Entity
+ {
+ return await GetCollection(collection).CountDocumentsAsync(filter);
+ }
+
+ #endregion
+
+ #region Exist
+
+ ///
+ /// 判断指定集合中是否存在文档。
+ ///
+ /// 实体类型。
+ /// 集合名称,可选。如果未指定,将使用实体类型的名称。
+ /// 如果存在文档则返回 true,否则返回 false。
+ public async FTask Exist(string collection = null) where T : Entity
+ {
+ return await Count(collection) > 0;
+ }
+
+ ///
+ /// 判断指定集合中是否存在满足条件的文档。
+ ///
+ /// 实体类型。
+ /// 用于筛选文档的表达式。
+ /// 集合名称,可选。如果未指定,将使用实体类型的名称。
+ /// 如果存在满足条件的文档则返回 true,否则返回 false。
+ public async FTask Exist(Expression> filter, string collection = null) where T : Entity
+ {
+ return await Count(filter, collection) > 0;
+ }
+
+ #endregion
+
+ #region Query
+
+ ///
+ /// 在不加数据库锁定的情况下,查询指定 ID 的文档。
+ ///
+ /// 文档实体类型。
+ /// 要查询的文档 ID。
+ /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。
+ /// 集合名称。
+ /// 查询到的文档。
+ public async FTask QueryNotLock(long id, bool isDeserialize = false, string collection = null) where T : Entity
+ {
+ var cursor = await GetCollection(collection).FindAsync(d => d.Id == id);
+ var v = await cursor.FirstOrDefaultAsync();
+
+ if (isDeserialize && v != null)
+ {
+ v.Deserialize(_scene);
+ }
+
+ return v;
+ }
+
+ ///
+ /// 查询指定 ID 的文档,并加数据库锁定以确保数据一致性。
+ ///
+ /// 文档实体类型。
+ /// 要查询的文档 ID。
+ /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。
+ /// 集合名称。
+ /// 查询到的文档。
+ public async FTask Query(long id, bool isDeserialize = false, string collection = null) where T : Entity
+ {
+ using (await _dataBaseLock.Wait(id))
+ {
+ var cursor = await GetCollection(collection).FindAsync(d => d.Id == id);
+ var v = await cursor.FirstOrDefaultAsync();
+
+ if (isDeserialize && v != null)
+ {
+ v.Deserialize(_scene);
+ }
+
+ return v;
+ }
+ }
+
+ ///
+ /// 通过分页查询并返回满足条件的文档数量和日期列表(不加锁)。
+ ///
+ /// 文档实体类型。
+ /// 查询过滤条件。
+ /// 页码。
+ /// 每页大小。
+ /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。
+ /// 集合名称。
+ /// 满足条件的文档数量和日期列表。
+ public async FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity
+ {
+ using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize))
+ {
+ var count = await Count(filter);
+ var dates = await QueryByPage(filter, pageIndex, pageSize, isDeserialize, collection);
+ return ((int)count, dates);
+ }
+ }
+
+ ///