@@ -59,7 +59,7 @@ message G2Map_EnterMapRequest // IRouteRequest,Map2G_EnterMapResponse
|
||||
{
|
||||
string RoomCode = 1; //房间代码
|
||||
int64 AccountId = 2; //账号id
|
||||
int32 MapId = 3; //地图id
|
||||
int32 MapId =3; //地图id
|
||||
}
|
||||
|
||||
/// 请求进入房间响应
|
||||
@@ -67,7 +67,7 @@ message Map2G_EnterMapResponse // IRouteResponse
|
||||
{
|
||||
string RoomCode = 1; //房间代码
|
||||
int32 MapId = 2; //地图id
|
||||
repeated MapUnitInfo Units = 3; //房间玩家列表
|
||||
repeated MapUnitInfo Units = 2; //房间玩家列表
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ message FishInfo
|
||||
{
|
||||
uint32 ConfigId = 1; //配置id
|
||||
int64 Id = 2; //物品id
|
||||
int32 Weight = 3; //重量
|
||||
int32 Weight =3; //重量
|
||||
int64 GetTime = 4; //获得时间
|
||||
int64 ExpirationTime = 5; //失效时间
|
||||
}
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
using System.Runtime.Loader;
|
||||
using Fantasy.Generated;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
|
||||
namespace Fantasy
|
||||
namespace NB
|
||||
{
|
||||
public static class AssemblyHelper
|
||||
{
|
||||
private const string HotfixDll = "Hotfix";
|
||||
private static AssemblyLoadContext? _assemblyLoadContext = null;
|
||||
|
||||
public static void Initialize()
|
||||
|
||||
public static System.Reflection.Assembly[] Assemblies
|
||||
{
|
||||
LoadEntityAssembly();
|
||||
LoadHotfixAssembly();
|
||||
get
|
||||
{
|
||||
var assemblies = new System.Reflection.Assembly[2];
|
||||
assemblies[0] = LoadEntityAssembly();
|
||||
assemblies[1] = LoadHotfixAssembly();
|
||||
return assemblies;
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadEntityAssembly()
|
||||
private static System.Reflection.Assembly LoadEntityAssembly()
|
||||
{
|
||||
// .NET 运行时采用延迟加载机制,如果代码中不使用程序集的类型,程序集不会被加载
|
||||
// 执行一下,触发运行时强制加载从而自动注册到框架中
|
||||
Entity_AssemblyMarker.EnsureLoaded();
|
||||
return typeof(AssemblyHelper).Assembly;
|
||||
}
|
||||
|
||||
public static System.Reflection.Assembly LoadHotfixAssembly()
|
||||
private static System.Reflection.Assembly LoadHotfixAssembly()
|
||||
{
|
||||
if (_assemblyLoadContext != null)
|
||||
{
|
||||
@@ -30,20 +33,9 @@ namespace Fantasy
|
||||
}
|
||||
|
||||
_assemblyLoadContext = new AssemblyLoadContext(HotfixDll, true);
|
||||
var dllBytes = File.ReadAllBytes(Path.Combine(AppContext.BaseDirectory, $"{HotfixDll}.dll"));
|
||||
var pdbBytes = File.ReadAllBytes(Path.Combine(AppContext.BaseDirectory, $"{HotfixDll}.pdb"));
|
||||
var assembly = _assemblyLoadContext.LoadFromStream(new MemoryStream(dllBytes), new MemoryStream(pdbBytes));
|
||||
// 强制触发 ModuleInitializer 执行
|
||||
// AssemblyLoadContext.LoadFromStream 只加载程序集到内存,不会自动触发 ModuleInitializer
|
||||
// 必须访问程序集中的类型才能触发初始化,这里通过反射调用生成的 AssemblyMarker
|
||||
// 注意:此方法仅用于热重载场景(JIT),Native AOT 不支持动态加载
|
||||
var markerType = assembly.GetType("Fantasy.Generated.Hotfix_AssemblyMarker");
|
||||
if (markerType != null)
|
||||
{
|
||||
var method = markerType.GetMethod("EnsureLoaded");
|
||||
method?.Invoke(null, null);
|
||||
}
|
||||
return assembly;
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,33 +9,31 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DefineConstants>TRACE;FANTASY_NET</DefineConstants>
|
||||
<DefineConstants>TRACE;FANTASY_NET</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DefineConstants>TRACE;FANTASY_NET</DefineConstants>
|
||||
<DefineConstants>TRACE;FANTASY_NET</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Fantasy\Fantasy.Net\Fantasy.Net\Fantasy.Net.csproj"/>
|
||||
<ProjectReference Include="..\Fantasy\Fantasy.Net\Fantasy.SourceGenerator\Fantasy.SourceGenerator.csproj" OutputItemType="Analyzer"
|
||||
ReferenceOutputAssembly="false"/>
|
||||
<ProjectReference Include="..\Fantasy\Fantasy.Packages\Fantasy.ConfigTable\Net\Fantasy.ConfigTable.csproj"/>
|
||||
<ProjectReference Include="..\ThirdParty\ThirdParty.csproj"/>
|
||||
<ProjectReference Include="..\Fantasy\Fantasy.Net\Fantasy.Net\Fantasy.Net.csproj" />
|
||||
<ProjectReference Include="..\Fantasy\Fantasy.Packages\Fantasy.ConfigTable\Net\Fantasy.ConfigTable.csproj" />
|
||||
<ProjectReference Include="..\ThirdParty\ThirdParty.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.12.1"/>
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.1"/>
|
||||
<PackageReference Include="ToolGood.Words" Version="3.1.0.2"/>
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.12.1" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.1" />
|
||||
<PackageReference Include="ToolGood.Words" Version="3.1.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Game\Shop\"/>
|
||||
<Folder Include="Generate\ConfigTable\Entity\"/>
|
||||
<Folder Include="Generate\ConfigTable\Partial\"/>
|
||||
<Folder Include="Social\Entity\"/>
|
||||
<Folder Include="Social\Mail\"/>
|
||||
<Folder Include="Game\Shop\" />
|
||||
<Folder Include="Generate\ConfigTable\Entity\" />
|
||||
<Folder Include="Generate\ConfigTable\Partial\" />
|
||||
<Folder Include="Social\Entity\" />
|
||||
<Folder Include="Social\Mail\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class BaitConfig : ASerialize, IConfigTable
|
||||
public sealed partial class BaitConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class BasicConfig : ASerialize, IConfigTable
|
||||
public sealed partial class BasicConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class BobberConfig : ASerialize, IConfigTable
|
||||
public sealed partial class BobberConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class FeederConfig : ASerialize, IConfigTable
|
||||
public sealed partial class FeederConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class FishConfig : ASerialize, IConfigTable
|
||||
public sealed partial class FishConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class HookConfig : ASerialize, IConfigTable
|
||||
public sealed partial class HookConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class InitConfig : ASerialize, IConfigTable
|
||||
public sealed partial class InitConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class ItemConfig : ASerialize, IConfigTable
|
||||
public sealed partial class ItemConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class LineConfig : ASerialize, IConfigTable
|
||||
public sealed partial class LineConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class LureConfig : ASerialize, IConfigTable
|
||||
public sealed partial class LureConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class ReelConfig : ASerialize, IConfigTable
|
||||
public sealed partial class ReelConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
85
Entity/Generate/ConfigTable/Entity/RingConfig.cs
Normal file
85
Entity/Generate/ConfigTable/Entity/RingConfig.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using ProtoBuf;
|
||||
using Fantasy;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using Fantasy.Serialize;
|
||||
using Fantasy.ConfigTable;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class RingConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
public uint Id { get; set; } // Id
|
||||
[ProtoMember(2)]
|
||||
public string Model { get; set; } // 模型
|
||||
[ProtoMember(3)]
|
||||
public string Icon { get; set; } // 图标
|
||||
[ProtoIgnore]
|
||||
public uint Key => Id;
|
||||
|
||||
#region Static
|
||||
|
||||
private static ConfigContext<RingConfig> Context => ConfigTableHelper.Table<RingConfig>();
|
||||
|
||||
public static RingConfig Get(uint key)
|
||||
{
|
||||
return Context.Get(key);
|
||||
}
|
||||
|
||||
public static RingConfig Get(Predicate<RingConfig> match)
|
||||
{
|
||||
return Context.Get(match);
|
||||
}
|
||||
|
||||
public static RingConfig Fist()
|
||||
{
|
||||
return Context.Fist();
|
||||
}
|
||||
|
||||
public static RingConfig Last()
|
||||
{
|
||||
return Context.Last();
|
||||
}
|
||||
|
||||
public static RingConfig Fist(Predicate<RingConfig> match)
|
||||
{
|
||||
return Context.Fist(match);
|
||||
}
|
||||
|
||||
public static RingConfig Last(Predicate<RingConfig> match)
|
||||
{
|
||||
return Context.Last(match);
|
||||
}
|
||||
|
||||
public static int Count()
|
||||
{
|
||||
return Context.Count();
|
||||
}
|
||||
|
||||
public static int Count(Func<RingConfig, bool> predicate)
|
||||
{
|
||||
return Context.Count(predicate);
|
||||
}
|
||||
|
||||
public static List<RingConfig> GetList()
|
||||
{
|
||||
return Context.GetList();
|
||||
}
|
||||
|
||||
public static List<RingConfig> GetList(Predicate<RingConfig> match)
|
||||
{
|
||||
return Context.GetList(match);
|
||||
}
|
||||
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
|
||||
{
|
||||
ConfigTableHelper.ParseLine<RingConfig>(arr);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class RodConfig : ASerialize, IConfigTable
|
||||
public sealed partial class RodConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
@@ -11,7 +11,7 @@ using Fantasy.ConfigTable;
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class RodRingConfig : ASerialize, IConfigTable
|
||||
public sealed partial class RodRingConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
|
||||
89
Entity/Generate/ConfigTable/Entity/WeightConfig.cs
Normal file
89
Entity/Generate/ConfigTable/Entity/WeightConfig.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using ProtoBuf;
|
||||
using Fantasy;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using Fantasy.Serialize;
|
||||
using Fantasy.ConfigTable;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
[ProtoContract]
|
||||
public sealed partial class WeightConfig : ASerialize, IProto, IConfigTable
|
||||
{
|
||||
|
||||
[ProtoMember(1)]
|
||||
public uint Id { get; set; } // Id
|
||||
[ProtoMember(2)]
|
||||
public string Model { get; set; } // 模型
|
||||
[ProtoMember(3)]
|
||||
public string Icon { get; set; } // 图标
|
||||
[ProtoMember(4)]
|
||||
public uint Type { get; set; } // 类型
|
||||
[ProtoMember(5)]
|
||||
public uint Weight { get; set; } // 重量(克)
|
||||
[ProtoIgnore]
|
||||
public uint Key => Id;
|
||||
|
||||
#region Static
|
||||
|
||||
private static ConfigContext<WeightConfig> Context => ConfigTableHelper.Table<WeightConfig>();
|
||||
|
||||
public static WeightConfig Get(uint key)
|
||||
{
|
||||
return Context.Get(key);
|
||||
}
|
||||
|
||||
public static WeightConfig Get(Predicate<WeightConfig> match)
|
||||
{
|
||||
return Context.Get(match);
|
||||
}
|
||||
|
||||
public static WeightConfig Fist()
|
||||
{
|
||||
return Context.Fist();
|
||||
}
|
||||
|
||||
public static WeightConfig Last()
|
||||
{
|
||||
return Context.Last();
|
||||
}
|
||||
|
||||
public static WeightConfig Fist(Predicate<WeightConfig> match)
|
||||
{
|
||||
return Context.Fist(match);
|
||||
}
|
||||
|
||||
public static WeightConfig Last(Predicate<WeightConfig> match)
|
||||
{
|
||||
return Context.Last(match);
|
||||
}
|
||||
|
||||
public static int Count()
|
||||
{
|
||||
return Context.Count();
|
||||
}
|
||||
|
||||
public static int Count(Func<WeightConfig, bool> predicate)
|
||||
{
|
||||
return Context.Count(predicate);
|
||||
}
|
||||
|
||||
public static List<WeightConfig> GetList()
|
||||
{
|
||||
return Context.GetList();
|
||||
}
|
||||
|
||||
public static List<WeightConfig> GetList(Predicate<WeightConfig> match)
|
||||
{
|
||||
return Context.GetList(match);
|
||||
}
|
||||
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
|
||||
{
|
||||
ConfigTableHelper.ParseLine<WeightConfig>(arr);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Fantasy;
|
||||
@@ -17,12 +16,12 @@ using Fantasy.Serialize;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色基础信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class RoleBaseInfo : AMessage
|
||||
public partial class RoleBaseInfo : AMessage, IProto
|
||||
{
|
||||
public static RoleBaseInfo Create(Scene scene)
|
||||
{
|
||||
@@ -54,7 +53,7 @@ namespace Fantasy
|
||||
public VipInfo VipInfo { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class KeyValueInt64 : AMessage
|
||||
public partial class KeyValueInt64 : AMessage, IProto
|
||||
{
|
||||
public static KeyValueInt64 Create(Scene scene)
|
||||
{
|
||||
@@ -77,7 +76,7 @@ namespace Fantasy
|
||||
/// 角色信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class RoleInfo : AMessage
|
||||
public partial class RoleInfo : AMessage, IProto
|
||||
{
|
||||
public static RoleInfo Create(Scene scene)
|
||||
{
|
||||
@@ -124,7 +123,7 @@ namespace Fantasy
|
||||
/// 角色信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class RoleSimpleInfo : AMessage
|
||||
public partial class RoleSimpleInfo : AMessage, IProto
|
||||
{
|
||||
public static RoleSimpleInfo Create(Scene scene)
|
||||
{
|
||||
@@ -162,7 +161,7 @@ namespace Fantasy
|
||||
/// VIP信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class VipInfo : AMessage
|
||||
public partial class VipInfo : AMessage, IProto
|
||||
{
|
||||
public static VipInfo Create(Scene scene)
|
||||
{
|
||||
@@ -188,7 +187,7 @@ namespace Fantasy
|
||||
/// 奖励信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class AwardInfo : AMessage
|
||||
public partial class AwardInfo : AMessage, IProto
|
||||
{
|
||||
public static AwardInfo Create(Scene scene)
|
||||
{
|
||||
@@ -211,7 +210,7 @@ namespace Fantasy
|
||||
/// 玩家当前使用钓组信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class ItemBindInfo : AMessage
|
||||
public partial class ItemBindInfo : AMessage, IProto
|
||||
{
|
||||
public static ItemBindInfo Create(Scene scene)
|
||||
{
|
||||
@@ -234,7 +233,7 @@ namespace Fantasy
|
||||
/// 物品信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class ItemInfo : AMessage
|
||||
public partial class ItemInfo : AMessage, IProto
|
||||
{
|
||||
public static ItemInfo Create(Scene scene)
|
||||
{
|
||||
@@ -269,7 +268,7 @@ namespace Fantasy
|
||||
/// fish信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class FishInfo : AMessage
|
||||
public partial class FishInfo : AMessage, IProto
|
||||
{
|
||||
public static FishInfo Create(Scene scene)
|
||||
{
|
||||
@@ -298,7 +297,7 @@ namespace Fantasy
|
||||
public long ExpirationTime { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class ActivityInfo : AMessage
|
||||
public partial class ActivityInfo : AMessage, IProto
|
||||
{
|
||||
public static ActivityInfo Create(Scene scene)
|
||||
{
|
||||
@@ -327,7 +326,7 @@ namespace Fantasy
|
||||
/// 技能情况
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class SkillInfo : AMessage
|
||||
public partial class SkillInfo : AMessage, IProto
|
||||
{
|
||||
public static SkillInfo Create(Scene scene)
|
||||
{
|
||||
@@ -350,4 +349,3 @@ namespace Fantasy
|
||||
public int Exp { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Fantasy;
|
||||
@@ -17,7 +16,7 @@ using Fantasy.Serialize;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// /////////// ******** 物品信息 *******/////////////
|
||||
/// </summary>
|
||||
@@ -25,7 +24,7 @@ namespace Fantasy
|
||||
/// 请求背包列表
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2Game_GetItemsRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2Game_GetItemsRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2Game_GetItemsRequest Create(Scene scene)
|
||||
{
|
||||
@@ -47,7 +46,7 @@ namespace Fantasy
|
||||
/// 请求背包列表响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Game2C_GetItemsResponse : AMessage, ICustomRouteResponse
|
||||
public partial class Game2C_GetItemsResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static Game2C_GetItemsResponse Create(Scene scene)
|
||||
{
|
||||
@@ -74,7 +73,7 @@ namespace Fantasy
|
||||
/// 请求使用物品
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2Game_UseItemRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2Game_UseItemRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2Game_UseItemRequest Create(Scene scene)
|
||||
{
|
||||
@@ -96,7 +95,7 @@ namespace Fantasy
|
||||
/// 请求使用物品响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Game2C_UseItemResponse : AMessage, ICustomRouteResponse
|
||||
public partial class Game2C_UseItemResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static Game2C_UseItemResponse Create(Scene scene)
|
||||
{
|
||||
@@ -117,7 +116,7 @@ namespace Fantasy
|
||||
/// 物品变化
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Game2C_ItemChange : AMessage, ICustomRouteMessage
|
||||
public partial class Game2C_ItemChange : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Game2C_ItemChange Create(Scene scene)
|
||||
{
|
||||
@@ -149,7 +148,7 @@ namespace Fantasy
|
||||
/// 请求安装或取下配件
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2Game_RigChangeRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2Game_RigChangeRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2Game_RigChangeRequest Create(Scene scene)
|
||||
{
|
||||
@@ -180,7 +179,7 @@ namespace Fantasy
|
||||
/// 请求安装配件响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Game2C_RigChangeResponse : AMessage, ICustomRouteResponse
|
||||
public partial class Game2C_RigChangeResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static Game2C_RigChangeResponse Create(Scene scene)
|
||||
{
|
||||
@@ -207,7 +206,7 @@ namespace Fantasy
|
||||
/// 请求鱼护列表
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2Game_GetFishsRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2Game_GetFishsRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2Game_GetFishsRequest Create(Scene scene)
|
||||
{
|
||||
@@ -229,7 +228,7 @@ namespace Fantasy
|
||||
/// 请求鱼护列表响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Game2C_GetFishsResponse : AMessage, ICustomRouteResponse
|
||||
public partial class Game2C_GetFishsResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static Game2C_GetFishsResponse Create(Scene scene)
|
||||
{
|
||||
@@ -253,7 +252,7 @@ namespace Fantasy
|
||||
/// 鱼护变化
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Game2C_FishChange : AMessage, ICustomRouteMessage
|
||||
public partial class Game2C_FishChange : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Game2C_FishChange Create(Scene scene)
|
||||
{
|
||||
@@ -282,7 +281,7 @@ namespace Fantasy
|
||||
/// 请求出售
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2Game_SellFishRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2Game_SellFishRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2Game_SellFishRequest Create(Scene scene)
|
||||
{
|
||||
@@ -307,7 +306,7 @@ namespace Fantasy
|
||||
/// 请求出售响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Game2C_SellFishResponse : AMessage, ICustomRouteResponse
|
||||
public partial class Game2C_SellFishResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static Game2C_SellFishResponse Create(Scene scene)
|
||||
{
|
||||
@@ -334,7 +333,7 @@ namespace Fantasy
|
||||
/// 请求购买
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2Game_BuyRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2Game_BuyRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2Game_BuyRequest Create(Scene scene)
|
||||
{
|
||||
@@ -356,7 +355,7 @@ namespace Fantasy
|
||||
/// 请求购买响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Game2C_BuyResponse : AMessage, ICustomRouteResponse
|
||||
public partial class Game2C_BuyResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static Game2C_BuyResponse Create(Scene scene)
|
||||
{
|
||||
@@ -377,4 +376,3 @@ namespace Fantasy
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Fantasy;
|
||||
@@ -17,12 +16,12 @@ using Fantasy.Serialize;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// 通知游戏服角色进入该游戏服
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class G2Common_EnterRequest : AMessage, IRouteRequest
|
||||
public partial class G2Common_EnterRequest : AMessage, IRouteRequest, IProto
|
||||
{
|
||||
public static G2Common_EnterRequest Create(Scene scene)
|
||||
{
|
||||
@@ -48,7 +47,7 @@ namespace Fantasy
|
||||
public int RouteType { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class G2Common_EnterResponse : AMessage, IRouteResponse
|
||||
public partial class G2Common_EnterResponse : AMessage, IRouteResponse, IProto
|
||||
{
|
||||
public static G2Common_EnterResponse Create(Scene scene)
|
||||
{
|
||||
@@ -72,7 +71,7 @@ namespace Fantasy
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class G2Common_ExitRequest : AMessage, IRouteRequest
|
||||
public partial class G2Common_ExitRequest : AMessage, IRouteRequest, IProto
|
||||
{
|
||||
public static G2Common_ExitRequest Create(Scene scene)
|
||||
{
|
||||
@@ -95,7 +94,7 @@ namespace Fantasy
|
||||
public long GateRouteId { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class Common2G_ExitResponse : AMessage, IRouteResponse
|
||||
public partial class Common2G_ExitResponse : AMessage, IRouteResponse, IProto
|
||||
{
|
||||
public static Common2G_ExitResponse Create(Scene scene)
|
||||
{
|
||||
@@ -116,7 +115,7 @@ namespace Fantasy
|
||||
/// 获取玩家基础信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2G_GetPlayerBasicInfoRequest : AMessage, IRouteRequest
|
||||
public partial class S2G_GetPlayerBasicInfoRequest : AMessage, IRouteRequest, IProto
|
||||
{
|
||||
public static S2G_GetPlayerBasicInfoRequest Create(Scene scene)
|
||||
{
|
||||
@@ -139,7 +138,7 @@ namespace Fantasy
|
||||
/// 获取玩家基础信息响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class G2S_GetPlayerBasicInfoResponse : AMessage, IRouteResponse
|
||||
public partial class G2S_GetPlayerBasicInfoResponse : AMessage, IRouteResponse, IProto
|
||||
{
|
||||
public static G2S_GetPlayerBasicInfoResponse Create(Scene scene)
|
||||
{
|
||||
@@ -160,7 +159,7 @@ namespace Fantasy
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class S2G_ChatMessage : AMessage, IRouteMessage
|
||||
public partial class S2G_ChatMessage : AMessage, IRouteMessage, IProto
|
||||
{
|
||||
public static S2G_ChatMessage Create(Scene scene)
|
||||
{
|
||||
@@ -184,7 +183,7 @@ namespace Fantasy
|
||||
/// 创建聊天频道
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Club2Chat_CreateChannel : AMessage, IRouteMessage
|
||||
public partial class Club2Chat_CreateChannel : AMessage, IRouteMessage, IProto
|
||||
{
|
||||
public static Club2Chat_CreateChannel Create(Scene scene)
|
||||
{
|
||||
@@ -205,7 +204,7 @@ namespace Fantasy
|
||||
/// 请求进入房间
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class G2Map_EnterMapRequest : AMessage, IRouteRequest
|
||||
public partial class G2Map_EnterMapRequest : AMessage, IRouteRequest, IProto
|
||||
{
|
||||
public static G2Map_EnterMapRequest Create(Scene scene)
|
||||
{
|
||||
@@ -234,7 +233,7 @@ namespace Fantasy
|
||||
/// 请求进入房间响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2G_EnterMapResponse : AMessage, IRouteResponse
|
||||
public partial class Map2G_EnterMapResponse : AMessage, IRouteResponse, IProto
|
||||
{
|
||||
public static Map2G_EnterMapResponse Create(Scene scene)
|
||||
{
|
||||
@@ -264,7 +263,7 @@ namespace Fantasy
|
||||
/// 请求离开房间
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class G2Map_ExitRoomRequest : AMessage, IRouteRequest
|
||||
public partial class G2Map_ExitRoomRequest : AMessage, IRouteRequest, IProto
|
||||
{
|
||||
public static G2Map_ExitRoomRequest Create(Scene scene)
|
||||
{
|
||||
@@ -290,7 +289,7 @@ namespace Fantasy
|
||||
/// 请求离开房间响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2G_ExiRoomResponse : AMessage, IRouteResponse
|
||||
public partial class Map2G_ExiRoomResponse : AMessage, IRouteResponse, IProto
|
||||
{
|
||||
public static Map2G_ExiRoomResponse Create(Scene scene)
|
||||
{
|
||||
@@ -308,4 +307,3 @@ namespace Fantasy
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Fantasy;
|
||||
@@ -17,12 +16,12 @@ using Fantasy.Serialize;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求创建房间
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2Map_CreateRoomRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2Map_CreateRoomRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2Map_CreateRoomRequest Create(Scene scene)
|
||||
{
|
||||
@@ -47,7 +46,7 @@ namespace Fantasy
|
||||
/// 请求创建房间成功
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2C_CreateRoomResponse : AMessage, ICustomRouteResponse
|
||||
public partial class Map2C_CreateRoomResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static Map2C_CreateRoomResponse Create(Scene scene)
|
||||
{
|
||||
@@ -74,7 +73,7 @@ namespace Fantasy
|
||||
/// 请求网关离开房间(离开房间,但是不离开地图)
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2G_ExitRoomRequest : AMessage, IRequest
|
||||
public partial class C2G_ExitRoomRequest : AMessage, IRequest, IProto
|
||||
{
|
||||
public static C2G_ExitRoomRequest Create(Scene scene)
|
||||
{
|
||||
@@ -97,7 +96,7 @@ namespace Fantasy
|
||||
/// 请求网关进入离开响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class G2C_ExitRoomResponse : AMessage, IResponse
|
||||
public partial class G2C_ExitRoomResponse : AMessage, IResponse, IProto
|
||||
{
|
||||
public static G2C_ExitRoomResponse Create(Scene scene)
|
||||
{
|
||||
@@ -121,7 +120,7 @@ namespace Fantasy
|
||||
/// 请求网关进入地图
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2G_EnterMapRequest : AMessage, IRequest
|
||||
public partial class C2G_EnterMapRequest : AMessage, IRequest, IProto
|
||||
{
|
||||
public static C2G_EnterMapRequest Create(Scene scene)
|
||||
{
|
||||
@@ -147,7 +146,7 @@ namespace Fantasy
|
||||
/// 请求网关进入房间响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class G2C_EnterMapResponse : AMessage, IResponse
|
||||
public partial class G2C_EnterMapResponse : AMessage, IResponse, IProto
|
||||
{
|
||||
public static G2C_EnterMapResponse Create(Scene scene)
|
||||
{
|
||||
@@ -177,7 +176,7 @@ namespace Fantasy
|
||||
/// 通知客户端切换地图
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2C_ChangeMap : AMessage, ICustomRouteMessage
|
||||
public partial class Map2C_ChangeMap : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Map2C_ChangeMap Create(Scene scene)
|
||||
{
|
||||
@@ -200,4 +199,3 @@ namespace Fantasy
|
||||
public int Node { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Fantasy;
|
||||
@@ -17,9 +16,9 @@ using Fantasy.Serialize;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
{
|
||||
[ProtoContract]
|
||||
public partial class Vector3Info : AMessage
|
||||
public partial class Vector3Info : AMessage, IProto
|
||||
{
|
||||
public static Vector3Info Create(Scene scene)
|
||||
{
|
||||
@@ -42,7 +41,7 @@ namespace Fantasy
|
||||
public float z { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class Vector2Info : AMessage
|
||||
public partial class Vector2Info : AMessage, IProto
|
||||
{
|
||||
public static Vector2Info Create(Scene scene)
|
||||
{
|
||||
@@ -62,7 +61,7 @@ namespace Fantasy
|
||||
public float y { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class QuaternionInfo : AMessage
|
||||
public partial class QuaternionInfo : AMessage, IProto
|
||||
{
|
||||
public static QuaternionInfo Create(Scene scene)
|
||||
{
|
||||
@@ -91,7 +90,7 @@ namespace Fantasy
|
||||
/// 玩家当前使用钓组信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class GearInfo : AMessage
|
||||
public partial class GearInfo : AMessage, IProto
|
||||
{
|
||||
public static GearInfo Create(Scene scene)
|
||||
{
|
||||
@@ -120,7 +119,7 @@ namespace Fantasy
|
||||
public List<KeyValueInt64> Propertys = new List<KeyValueInt64>();
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class UnitStateInfo : AMessage
|
||||
public partial class UnitStateInfo : AMessage, IProto
|
||||
{
|
||||
public static UnitStateInfo Create(Scene scene)
|
||||
{
|
||||
@@ -140,7 +139,7 @@ namespace Fantasy
|
||||
public List<KeyValueInt64> Propertys = new List<KeyValueInt64>();
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class MapUnitInfo : AMessage
|
||||
public partial class MapUnitInfo : AMessage, IProto
|
||||
{
|
||||
public static MapUnitInfo Create(Scene scene)
|
||||
{
|
||||
@@ -175,4 +174,3 @@ namespace Fantasy
|
||||
public List<KeyValueInt64> Propertys = new List<KeyValueInt64>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Fantasy;
|
||||
@@ -17,9 +16,9 @@ using Fantasy.Serialize;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
{
|
||||
[ProtoContract]
|
||||
public partial class C2A_LoginRequest : AMessage, IRequest
|
||||
public partial class C2A_LoginRequest : AMessage, IRequest, IProto
|
||||
{
|
||||
public static C2A_LoginRequest Create(Scene scene)
|
||||
{
|
||||
@@ -48,7 +47,7 @@ namespace Fantasy
|
||||
public int Region { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class A2C_LoginResponse : AMessage, IResponse
|
||||
public partial class A2C_LoginResponse : AMessage, IResponse, IProto
|
||||
{
|
||||
public static A2C_LoginResponse Create(Scene scene)
|
||||
{
|
||||
@@ -72,7 +71,7 @@ namespace Fantasy
|
||||
/// 客户端登录到Gate服务器
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2G_LoginRequest : AMessage, IRequest
|
||||
public partial class C2G_LoginRequest : AMessage, IRequest, IProto
|
||||
{
|
||||
public static C2G_LoginRequest Create(Scene scene)
|
||||
{
|
||||
@@ -92,7 +91,7 @@ namespace Fantasy
|
||||
public string ToKen { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class G2C_LoginResponse : AMessage, IResponse
|
||||
public partial class G2C_LoginResponse : AMessage, IResponse, IProto
|
||||
{
|
||||
public static G2C_LoginResponse Create(Scene scene)
|
||||
{
|
||||
@@ -116,7 +115,7 @@ namespace Fantasy
|
||||
/// 通知客户端重复登录
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class G2C_RepeatLogin : AMessage, IMessage
|
||||
public partial class G2C_RepeatLogin : AMessage, IMessage, IProto
|
||||
{
|
||||
public static G2C_RepeatLogin Create(Scene scene)
|
||||
{
|
||||
@@ -131,7 +130,7 @@ namespace Fantasy
|
||||
public uint OpCode() { return OuterOpcode.G2C_RepeatLogin; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class C2Game_GetRoleInfoRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2Game_GetRoleInfoRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2Game_GetRoleInfoRequest Create(Scene scene)
|
||||
{
|
||||
@@ -150,7 +149,7 @@ namespace Fantasy
|
||||
public int RouteType => Fantasy.RouteType.GameRoute;
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class Game2C_GetRoleInfoResponse : AMessage, ICustomRouteResponse
|
||||
public partial class Game2C_GetRoleInfoResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static Game2C_GetRoleInfoResponse Create(Scene scene)
|
||||
{
|
||||
@@ -174,4 +173,3 @@ namespace Fantasy
|
||||
public uint ErrorCode { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Fantasy;
|
||||
@@ -17,12 +16,12 @@ using Fantasy.Serialize;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户进入地图
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2C_RoleEnterRoomNotify : AMessage, ICustomRouteMessage
|
||||
public partial class Map2C_RoleEnterRoomNotify : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Map2C_RoleEnterRoomNotify Create(Scene scene)
|
||||
{
|
||||
@@ -45,7 +44,7 @@ namespace Fantasy
|
||||
/// 用户离开地图
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2C_RoleExitRoomNotify : AMessage, ICustomRouteMessage
|
||||
public partial class Map2C_RoleExitRoomNotify : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Map2C_RoleExitRoomNotify Create(Scene scene)
|
||||
{
|
||||
@@ -65,7 +64,7 @@ namespace Fantasy
|
||||
public long Id { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class C2Map_RolePropertyChange : AMessage, ICustomRouteMessage
|
||||
public partial class C2Map_RolePropertyChange : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static C2Map_RolePropertyChange Create(Scene scene)
|
||||
{
|
||||
@@ -88,7 +87,7 @@ namespace Fantasy
|
||||
/// 玩家状态变化同步
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2C_RoleStateNotify : AMessage, ICustomRouteMessage
|
||||
public partial class Map2C_RoleStateNotify : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Map2C_RoleStateNotify Create(Scene scene)
|
||||
{
|
||||
@@ -114,7 +113,7 @@ namespace Fantasy
|
||||
/// 玩家钓组变化
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2C_RoleGearChangeNotify : AMessage, ICustomRouteMessage
|
||||
public partial class Map2C_RoleGearChangeNotify : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Map2C_RoleGearChangeNotify Create(Scene scene)
|
||||
{
|
||||
@@ -137,7 +136,7 @@ namespace Fantasy
|
||||
public List<GearInfo> Gears = new List<GearInfo>();
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class Map2C_RolePropertyChangeNotify : AMessage, ICustomRouteMessage
|
||||
public partial class Map2C_RolePropertyChangeNotify : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Map2C_RolePropertyChangeNotify Create(Scene scene)
|
||||
{
|
||||
@@ -160,7 +159,7 @@ namespace Fantasy
|
||||
public List<KeyValueInt64> Propertys = new List<KeyValueInt64>();
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class C2Map_Move : AMessage, ICustomRouteMessage
|
||||
public partial class C2Map_Move : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static C2Map_Move Create(Scene scene)
|
||||
{
|
||||
@@ -195,7 +194,7 @@ namespace Fantasy
|
||||
public long Timestamp { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class C2Map_Look : AMessage, ICustomRouteMessage
|
||||
public partial class C2Map_Look : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static C2Map_Look Create(Scene scene)
|
||||
{
|
||||
@@ -221,7 +220,7 @@ namespace Fantasy
|
||||
/// 玩家移动推送
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2C_MoveNotify : AMessage, ICustomRouteMessage
|
||||
public partial class Map2C_MoveNotify : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Map2C_MoveNotify Create(Scene scene)
|
||||
{
|
||||
@@ -262,7 +261,7 @@ namespace Fantasy
|
||||
/// 玩家旋转推送
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class Map2C_LookeNotify : AMessage, ICustomRouteMessage
|
||||
public partial class Map2C_LookeNotify : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static Map2C_LookeNotify Create(Scene scene)
|
||||
{
|
||||
@@ -288,4 +287,3 @@ namespace Fantasy
|
||||
public long Timestamp { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Fantasy;
|
||||
@@ -17,7 +16,7 @@ using Fantasy.Serialize;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Fantasy
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// /////////// ******** 私聊/邮件 *******/////////////
|
||||
/// </summary>
|
||||
@@ -25,7 +24,7 @@ namespace Fantasy
|
||||
/// 会话信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class ConversationInfo : AMessage
|
||||
public partial class ConversationInfo : AMessage, IProto
|
||||
{
|
||||
public static ConversationInfo Create(Scene scene)
|
||||
{
|
||||
@@ -45,7 +44,7 @@ namespace Fantasy
|
||||
public List<MailInfo> List = new List<MailInfo>();
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class MailInfo : AMessage
|
||||
public partial class MailInfo : AMessage, IProto
|
||||
{
|
||||
public static MailInfo Create(Scene scene)
|
||||
{
|
||||
@@ -83,7 +82,7 @@ namespace Fantasy
|
||||
/// 请求会话列表
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_GetConversationsRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_GetConversationsRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_GetConversationsRequest Create(Scene scene)
|
||||
{
|
||||
@@ -105,7 +104,7 @@ namespace Fantasy
|
||||
/// 请求会话列表响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_GetConversationsResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_GetConversationsResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_GetConversationsResponse Create(Scene scene)
|
||||
{
|
||||
@@ -129,7 +128,7 @@ namespace Fantasy
|
||||
/// 发送邮件消息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_SendMailRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_SendMailRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_SendMailRequest Create(Scene scene)
|
||||
{
|
||||
@@ -160,7 +159,7 @@ namespace Fantasy
|
||||
/// 发送邮件消息响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_SendMailResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_SendMailResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_SendMailResponse Create(Scene scene)
|
||||
{
|
||||
@@ -181,7 +180,7 @@ namespace Fantasy
|
||||
/// 发送删除会话消息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_DeleteMailRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_DeleteMailRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_DeleteMailRequest Create(Scene scene)
|
||||
{
|
||||
@@ -206,7 +205,7 @@ namespace Fantasy
|
||||
/// 发送删除会话消息响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_DeleteMailResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_DeleteMailResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_DeleteMailResponse Create(Scene scene)
|
||||
{
|
||||
@@ -230,7 +229,7 @@ namespace Fantasy
|
||||
/// 新邮件推送
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_HaveMail : AMessage, ICustomRouteMessage
|
||||
public partial class S2C_HaveMail : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static S2C_HaveMail Create(Scene scene)
|
||||
{
|
||||
@@ -253,7 +252,7 @@ namespace Fantasy
|
||||
public string Key { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class S2C_MailState : AMessage, ICustomRouteMessage
|
||||
public partial class S2C_MailState : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static S2C_MailState Create(Scene scene)
|
||||
{
|
||||
@@ -279,7 +278,7 @@ namespace Fantasy
|
||||
/// /////////// ******** 频道聊天 *******/////////////
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class ChatUserInfo : AMessage
|
||||
public partial class ChatUserInfo : AMessage, IProto
|
||||
{
|
||||
public static ChatUserInfo Create(Scene scene)
|
||||
{
|
||||
@@ -299,7 +298,7 @@ namespace Fantasy
|
||||
public long Name { get; set; }
|
||||
}
|
||||
[ProtoContract]
|
||||
public partial class ChatMessageInfo : AMessage
|
||||
public partial class ChatMessageInfo : AMessage, IProto
|
||||
{
|
||||
public static ChatMessageInfo Create(Scene scene)
|
||||
{
|
||||
@@ -331,7 +330,7 @@ namespace Fantasy
|
||||
/// 创建频道
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_CreateChannelRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_CreateChannelRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_CreateChannelRequest Create(Scene scene)
|
||||
{
|
||||
@@ -356,7 +355,7 @@ namespace Fantasy
|
||||
/// 创建频道响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_CreateChannelResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_CreateChannelResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_CreateChannelResponse Create(Scene scene)
|
||||
{
|
||||
@@ -380,7 +379,7 @@ namespace Fantasy
|
||||
/// 请求进入频道
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_JoinChannelRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_JoinChannelRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_JoinChannelRequest Create(Scene scene)
|
||||
{
|
||||
@@ -405,7 +404,7 @@ namespace Fantasy
|
||||
/// 进入频道响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_JoinChannelResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_JoinChannelResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_JoinChannelResponse Create(Scene scene)
|
||||
{
|
||||
@@ -426,7 +425,7 @@ namespace Fantasy
|
||||
/// 发送消息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_SendMessageRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_SendMessageRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_SendMessageRequest Create(Scene scene)
|
||||
{
|
||||
@@ -454,7 +453,7 @@ namespace Fantasy
|
||||
/// 发送消息响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_SendMessageResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_SendMessageResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_SendMessageResponse Create(Scene scene)
|
||||
{
|
||||
@@ -475,7 +474,7 @@ namespace Fantasy
|
||||
/// 推送消息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_Message : AMessage, ICustomRouteMessage
|
||||
public partial class S2C_Message : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static S2C_Message Create(Scene scene)
|
||||
{
|
||||
@@ -498,7 +497,7 @@ namespace Fantasy
|
||||
/// /////////// ******** 工会 *******/////////////
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class ClubInfo : AMessage
|
||||
public partial class ClubInfo : AMessage, IProto
|
||||
{
|
||||
public static ClubInfo Create(Scene scene)
|
||||
{
|
||||
@@ -530,7 +529,7 @@ namespace Fantasy
|
||||
/// 请求创建工会
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_CreateClubRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_CreateClubRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_CreateClubRequest Create(Scene scene)
|
||||
{
|
||||
@@ -555,7 +554,7 @@ namespace Fantasy
|
||||
/// 创建工会响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_CreateClubResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_CreateClubResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_CreateClubResponse Create(Scene scene)
|
||||
{
|
||||
@@ -579,7 +578,7 @@ namespace Fantasy
|
||||
/// 请求工会信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_GetClubInfoRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_GetClubInfoRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_GetClubInfoRequest Create(Scene scene)
|
||||
{
|
||||
@@ -604,7 +603,7 @@ namespace Fantasy
|
||||
/// 响应工会信息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_GetClubInfoResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_GetClubInfoResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_GetClubInfoResponse Create(Scene scene)
|
||||
{
|
||||
@@ -628,7 +627,7 @@ namespace Fantasy
|
||||
/// 请求工会成员列表
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_GetMemberListRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_GetMemberListRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_GetMemberListRequest Create(Scene scene)
|
||||
{
|
||||
@@ -653,7 +652,7 @@ namespace Fantasy
|
||||
/// 响应工会成员列表
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_GetMemberListResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_GetMemberListResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_GetMemberListResponse Create(Scene scene)
|
||||
{
|
||||
@@ -677,7 +676,7 @@ namespace Fantasy
|
||||
/// 获取工会列表请求
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_GetClubListRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_GetClubListRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_GetClubListRequest Create(Scene scene)
|
||||
{
|
||||
@@ -699,7 +698,7 @@ namespace Fantasy
|
||||
/// 获取工会列表响应
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_GetClubListResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_GetClubListResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_GetClubListResponse Create(Scene scene)
|
||||
{
|
||||
@@ -723,7 +722,7 @@ namespace Fantasy
|
||||
/// 请求加入工会
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_JoinClubRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_JoinClubRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_JoinClubRequest Create(Scene scene)
|
||||
{
|
||||
@@ -748,7 +747,7 @@ namespace Fantasy
|
||||
/// 响应加入工会
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_JoinClubResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_JoinClubResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_JoinClubResponse Create(Scene scene)
|
||||
{
|
||||
@@ -772,7 +771,7 @@ namespace Fantasy
|
||||
/// 请求退出工会
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_LeaveClubRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_LeaveClubRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_LeaveClubRequest Create(Scene scene)
|
||||
{
|
||||
@@ -797,7 +796,7 @@ namespace Fantasy
|
||||
/// 响应退出工会
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_LeaveClubResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_LeaveClubResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_LeaveClubResponse Create(Scene scene)
|
||||
{
|
||||
@@ -821,7 +820,7 @@ namespace Fantasy
|
||||
/// 请求解散工会
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_DissolveClubRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_DissolveClubRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_DissolveClubRequest Create(Scene scene)
|
||||
{
|
||||
@@ -846,7 +845,7 @@ namespace Fantasy
|
||||
/// 响应解散工会
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_DissolveClubResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_DissolveClubResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_DissolveClubResponse Create(Scene scene)
|
||||
{
|
||||
@@ -870,7 +869,7 @@ namespace Fantasy
|
||||
/// 请求操作申请
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class C2S_DisposeJoinRequest : AMessage, ICustomRouteRequest
|
||||
public partial class C2S_DisposeJoinRequest : AMessage, ICustomRouteRequest, IProto
|
||||
{
|
||||
public static C2S_DisposeJoinRequest Create(Scene scene)
|
||||
{
|
||||
@@ -901,7 +900,7 @@ namespace Fantasy
|
||||
/// 响应操作申请
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_DisposeJoinResponse : AMessage, ICustomRouteResponse
|
||||
public partial class S2C_DisposeJoinResponse : AMessage, ICustomRouteResponse, IProto
|
||||
{
|
||||
public static S2C_DisposeJoinResponse Create(Scene scene)
|
||||
{
|
||||
@@ -931,7 +930,7 @@ namespace Fantasy
|
||||
/// 推送消息
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public partial class S2C_ClubChange : AMessage, ICustomRouteMessage
|
||||
public partial class S2C_ClubChange : AMessage, ICustomRouteMessage, IProto
|
||||
{
|
||||
public static S2C_ClubChange Create(Scene scene)
|
||||
{
|
||||
@@ -954,4 +953,3 @@ namespace Fantasy
|
||||
public int ChangeType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,34 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!-- 自动为引用 Fantasy.Net 的项目添加 FANTASY_NET 预编译符号 -->
|
||||
<PropertyGroup>
|
||||
<DefineConstants>$(DefineConstants);FANTASY_NET</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<!-- <!– 物理复制 Excel 配置文件到项目根目录 –>-->
|
||||
<!-- <Target Name="CopyExcelFilesToProject" BeforeTargets="PrepareForBuild">-->
|
||||
<!-- <ItemGroup>-->
|
||||
<!-- <ExcelFilesToCopy Include="$(MSBuildThisFileDirectory)..\build\MachineConfig.xlsx" />-->
|
||||
<!-- <ExcelFilesToCopy Include="$(MSBuildThisFileDirectory)..\build\SceneConfig.xlsx" />-->
|
||||
<!-- <ExcelFilesToCopy Include="$(MSBuildThisFileDirectory)..\build\ProcessConfig.xlsx" />-->
|
||||
<!-- <ExcelFilesToCopy Include="$(MSBuildThisFileDirectory)..\build\WorldConfig.xlsx" />-->
|
||||
<!-- </ItemGroup>-->
|
||||
<!-- <Copy SourceFiles="@(ExcelFilesToCopy)" DestinationFolder="$(MSBuildProjectDirectory)/ServerConfig" SkipUnchangedFiles="true" />-->
|
||||
<!-- </Target>-->
|
||||
<!-- <!– 物理复制 NLog 配置文件到项目根目录 –>-->
|
||||
<!-- <Target Name="CopyNLogFilesToProject" BeforeTargets="PrepareForBuild">-->
|
||||
<!-- <ItemGroup>-->
|
||||
<!-- <!– 定义源文件路径,指向 NuGet 包中的文件 –>-->
|
||||
<!-- <FilesToCopy Include="$(MSBuildThisFileDirectory)..\build\NLog.config" />-->
|
||||
<!-- <FilesToCopy Include="$(MSBuildThisFileDirectory)..\build\NLog.xsd" />-->
|
||||
<!-- </ItemGroup>-->
|
||||
<!-- <!– 使用 Copy 任务将文件复制到项目物理根目录 –>-->
|
||||
<!-- <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(MSBuildProjectDirectory)" SkipUnchangedFiles="true" /> -->
|
||||
<!-- <!– 将复制的文件添加到解决方案中,并设置复制到输出目录 –>-->
|
||||
<!-- <ItemGroup>-->
|
||||
<!-- <!– 使用 Include 确保文件在解决方案中显示 –>-->
|
||||
<!-- <None Include="NLog.config">-->
|
||||
<!-- <!– 确保复制到输出目录,并设置复制模式 –>-->
|
||||
<!-- <CopyToOutputDirectory>Always</CopyToOutputDirectory>-->
|
||||
<!-- </None>-->
|
||||
<!-- <None Include="NLog.xsd">-->
|
||||
<!-- <!– 确保复制到输出目录,并设置复制模式 –>-->
|
||||
<!-- <CopyToOutputDirectory>Always</CopyToOutputDirectory>-->
|
||||
<!-- </None>-->
|
||||
<!-- </ItemGroup>-->
|
||||
<!-- </Target>-->
|
||||
</Project>
|
||||
|
||||
@@ -30,9 +30,6 @@
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DocumentationFile>bin\Debug\net8.0\Fantasy.Net.xml</DocumentationFile>
|
||||
<!-- 启用 Source Generator 文件输出(可选,用于调试) -->
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
@@ -60,21 +57,4 @@
|
||||
<PackageReference Include="System.IO.Pipelines" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Source Generator Reference -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Fantasy.SourceGenerator\Fantasy.SourceGenerator.csproj"
|
||||
OutputItemType="Analyzer"
|
||||
ReferenceOutputAssembly="false"
|
||||
SetTargetFramework="TargetFramework=netstandard2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- 将 Source Generator 打包到 NuGet -->
|
||||
<ItemGroup>
|
||||
<!-- 获取 Fantasy.SourceGenerator 的输出 DLL -->
|
||||
<None Include="..\Fantasy.SourceGenerator\bin\$(Configuration)\netstandard2.0\Fantasy.SourceGenerator.dll"
|
||||
Pack="true"
|
||||
PackagePath="analyzers/dotnet/cs"
|
||||
Visible="false" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// AssemblyInfo提供有关程序集和类型的信息
|
||||
/// </summary>
|
||||
public sealed class AssemblyInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 唯一标识
|
||||
/// </summary>
|
||||
public readonly long AssemblyIdentity;
|
||||
/// <summary>
|
||||
/// 获取或设置与此程序集相关联的 <see cref="Assembly"/> 实例。
|
||||
/// </summary>
|
||||
public System.Reflection.Assembly Assembly { get; private set; }
|
||||
/// <summary>
|
||||
/// 程序集类型集合,获取一个列表,包含从程序集加载的所有类型。
|
||||
/// </summary>
|
||||
public readonly List<Type> AssemblyTypeList = new List<Type>();
|
||||
/// <summary>
|
||||
/// 程序集类型分组集合,获取一个分组列表,将接口类型映射到实现这些接口的类型。
|
||||
/// </summary>
|
||||
public readonly OneToManyList<Type, Type> AssemblyTypeGroupList = new OneToManyList<Type, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 <see cref="AssemblyInfo"/> 类的新实例。
|
||||
/// </summary>
|
||||
/// <param name="assemblyIdentity"></param>
|
||||
public AssemblyInfo(long assemblyIdentity)
|
||||
{
|
||||
AssemblyIdentity = assemblyIdentity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从指定的程序集加载类型信息并进行分类。
|
||||
/// </summary>
|
||||
/// <param name="assembly">要加载信息的程序集。</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新加载程序集的类型信息。
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
public void ReLoad(System.Reflection.Assembly assembly)
|
||||
{
|
||||
Unload();
|
||||
Load(assembly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载程序集的类型信息。
|
||||
/// </summary>
|
||||
public void Unload()
|
||||
{
|
||||
AssemblyTypeList.Clear();
|
||||
AssemblyTypeGroupList.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Fantasy.Async;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序集生命周期管理类
|
||||
/// 管理所有注册的程序集生命周期回调,在程序集加载、卸载时触发相应的回调方法
|
||||
/// </summary>
|
||||
public static class AssemblyLifecycle
|
||||
{
|
||||
#if FANTASY_WEBGL
|
||||
/// <summary>
|
||||
/// 程序集生命周期回调集合(WebGL 单线程版本)
|
||||
/// </summary>
|
||||
private static readonly Dictionary<IAssemblyLifecycle, byte> AssemblyLifecycles = new Dictionary<IAssemblyLifecycle, byte>();
|
||||
#else
|
||||
/// <summary>
|
||||
/// 程序集生命周期回调集合(线程安全版本)
|
||||
/// 使用 ConcurrentDictionary 当作 Set 使用,Value 无实际意义
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<IAssemblyLifecycle, byte> AssemblyLifecycles = new ConcurrentDictionary<IAssemblyLifecycle, byte>();
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 触发程序集加载事件
|
||||
/// 遍历所有已注册的生命周期回调,调用其 OnLoad 方法
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象</param>
|
||||
/// <returns>异步任务</returns>
|
||||
internal static async FTask OnLoad(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
foreach (var (assemblyLifecycle, _) in AssemblyLifecycles)
|
||||
{
|
||||
await assemblyLifecycle.OnLoad(assemblyManifest);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发程序集卸载事件
|
||||
/// 遍历所有已注册的生命周期回调,调用其 OnUnload 方法,并清理程序集清单
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象</param>
|
||||
/// <returns>异步任务</returns>
|
||||
internal static async FTask OnUnLoad(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
foreach (var (assemblyLifecycle, _) in AssemblyLifecycles)
|
||||
{
|
||||
await assemblyLifecycle.OnUnload(assemblyManifest);
|
||||
}
|
||||
assemblyManifest.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加程序集生命周期回调
|
||||
/// 添加后会立即对所有已加载的程序集触发 Load 回调
|
||||
/// </summary>
|
||||
/// <param name="assemblyLifecycle">实现 IAssemblyLifecycle 接口的生命周期回调对象</param>
|
||||
internal static async FTask Add(IAssemblyLifecycle assemblyLifecycle)
|
||||
{
|
||||
#if FANTASY_WEBGL
|
||||
AssemblyLifecycles.Add(assemblyLifecycle, 0);
|
||||
#else
|
||||
AssemblyLifecycles.TryAdd(assemblyLifecycle, 0);
|
||||
#endif
|
||||
foreach (var (_, assemblyManifest) in AssemblyManifest.Manifests)
|
||||
{
|
||||
await assemblyLifecycle.OnLoad(assemblyManifest);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除程序集生命周期回调
|
||||
/// 移除后该回调将不再接收程序集的加载、卸载、重载事件
|
||||
/// </summary>
|
||||
/// <param name="assemblyLifecycle">要移除的生命周期回调对象</param>
|
||||
internal static void Remove(IAssemblyLifecycle assemblyLifecycle)
|
||||
{
|
||||
AssemblyLifecycles.Remove(assemblyLifecycle, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放所有程序集生命周期回调
|
||||
/// 清空所有已注册的生命周期回调集合
|
||||
/// </summary>
|
||||
public static void Dispose()
|
||||
{
|
||||
AssemblyLifecycles.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Entitas;
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||
#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 CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序集清单类
|
||||
/// 封装程序集的元数据和各种系统注册器,用于统一管理程序集的生命周期和系统注册
|
||||
/// </summary>
|
||||
public sealed class AssemblyManifest
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序集唯一标识符
|
||||
/// 通过程序集名称的哈希值生成
|
||||
/// </summary>
|
||||
public long AssemblyManifestId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序集实例
|
||||
/// </summary>
|
||||
public System.Reflection.Assembly Assembly { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// ProtoBuf 序列化类型注册器
|
||||
/// </summary>
|
||||
internal INetworkProtocolRegistrar NetworkProtocolRegistrar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件系统注册器
|
||||
/// </summary>
|
||||
internal IEventSystemRegistrar EventSystemRegistrar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体系统注册器
|
||||
/// </summary>
|
||||
internal IEntitySystemRegistrar EntitySystemRegistrar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息分发器注册器
|
||||
/// </summary>
|
||||
internal IMessageHandlerResolver MessageHandlerResolver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体类型集合注册器
|
||||
/// </summary>
|
||||
internal IEntityTypeCollectionRegistrar EntityTypeCollectionRegistrar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 网络协议 OpCode 解析器接口
|
||||
/// </summary>
|
||||
internal INetworkProtocolOpCodeResolver NetworkProtocolOpCodeResolver { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 网络协议 Response 解析器接口
|
||||
/// </summary>
|
||||
internal INetworkProtocolResponseTypeResolver NetworkProtocolResponseTypeResolver { get; set; }
|
||||
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// 分表注册器
|
||||
/// </summary>
|
||||
internal ISeparateTableRegistrar SeparateTableRegistrar { get; set; }
|
||||
#endif
|
||||
#if FANTASY_WEBGL
|
||||
/// <summary>
|
||||
/// 程序集清单集合(WebGL 单线程版本)
|
||||
/// Key: 程序集唯一标识, Value: 程序集清单对象
|
||||
/// </summary>
|
||||
private static readonly Dictionary<long, AssemblyManifest> Manifests = new Dictionary<long, AssemblyManifest>();
|
||||
#else
|
||||
/// <summary>
|
||||
/// 程序集清单集合(线程安全版本)
|
||||
/// Key: 程序集唯一标识, Value: 程序集清单对象
|
||||
/// </summary>
|
||||
internal static readonly ConcurrentDictionary<long, AssemblyManifest> Manifests = new ConcurrentDictionary<long, AssemblyManifest>();
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 清理程序集清单内部资源
|
||||
/// 释放所有注册器并清空引用
|
||||
/// </summary>
|
||||
internal void Clear()
|
||||
{
|
||||
EventSystemRegistrar?.Dispose();
|
||||
|
||||
Assembly = null;
|
||||
NetworkProtocolRegistrar = null;
|
||||
EventSystemRegistrar = null;
|
||||
EntitySystemRegistrar = null;
|
||||
MessageHandlerResolver = null;
|
||||
EntityTypeCollectionRegistrar = null;
|
||||
#if FANTASY_NET
|
||||
SeparateTableRegistrar = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
#region static
|
||||
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// 注册程序集清单
|
||||
/// 此方法由 Source Generator 生成的 ModuleInitializer 自动调用
|
||||
/// 直接创建并缓存完整的 AssemblyManifest
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifestId">程序集唯一标识(通过程序集名称哈希生成)</param>
|
||||
/// <param name="assembly">程序集实例</param>
|
||||
/// <param name="networkProtocolRegistrar">网络协议注册器</param>
|
||||
/// <param name="eventSystemRegistrar">事件系统注册器</param>
|
||||
/// <param name="entitySystemRegistrar">实体系统注册器</param>
|
||||
/// <param name="messageHandlerResolver">消息分发器注册器</param>
|
||||
/// <param name="entityTypeCollectionRegistrar">实体类型集合注册器</param>
|
||||
/// <param name="separateTableRegistrar">分表注册器</param>
|
||||
/// <param name="networkProtocolOpCodeResolver">网络协议 OpCode 解析器接口</param>
|
||||
/// <param name="networkProtocolResponseTypeResolver">网络协议 Response 解析器接口</param>
|
||||
public static void Register(
|
||||
long assemblyManifestId,
|
||||
System.Reflection.Assembly assembly,
|
||||
INetworkProtocolRegistrar networkProtocolRegistrar,
|
||||
IEventSystemRegistrar eventSystemRegistrar,
|
||||
IEntitySystemRegistrar entitySystemRegistrar,
|
||||
IMessageHandlerResolver messageHandlerResolver,
|
||||
IEntityTypeCollectionRegistrar entityTypeCollectionRegistrar,
|
||||
ISeparateTableRegistrar separateTableRegistrar,
|
||||
INetworkProtocolOpCodeResolver networkProtocolOpCodeResolver,
|
||||
INetworkProtocolResponseTypeResolver networkProtocolResponseTypeResolver)
|
||||
{
|
||||
var manifest = new AssemblyManifest
|
||||
{
|
||||
Assembly = assembly,
|
||||
AssemblyManifestId = assemblyManifestId,
|
||||
NetworkProtocolRegistrar = networkProtocolRegistrar,
|
||||
EventSystemRegistrar = eventSystemRegistrar,
|
||||
EntitySystemRegistrar = entitySystemRegistrar,
|
||||
MessageHandlerResolver = messageHandlerResolver,
|
||||
EntityTypeCollectionRegistrar = entityTypeCollectionRegistrar,
|
||||
SeparateTableRegistrar = separateTableRegistrar,
|
||||
NetworkProtocolOpCodeResolver = networkProtocolOpCodeResolver,
|
||||
NetworkProtocolResponseTypeResolver = networkProtocolResponseTypeResolver
|
||||
};
|
||||
|
||||
Manifests.TryAdd(assemblyManifestId, manifest);
|
||||
AssemblyLifecycle.OnLoad(manifest).Coroutine();
|
||||
}
|
||||
#endif
|
||||
#if FANTASY_UNITY
|
||||
/// <summary>
|
||||
/// 注册程序集清单
|
||||
/// 此方法由 Source Generator 生成的 ModuleInitializer 自动调用
|
||||
/// 直接创建并缓存完整的 AssemblyManifest
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifestId">程序集唯一标识(通过程序集名称哈希生成)</param>
|
||||
/// <param name="assembly">程序集实例</param>
|
||||
/// <param name="networkProtocolRegistrar">网络协议注册器</param>
|
||||
/// <param name="eventSystemRegistrar">事件系统注册器</param>
|
||||
/// <param name="entitySystemRegistrar">实体系统注册器</param>
|
||||
/// <param name="messageHandlerResolver">消息分发器注册器</param>
|
||||
/// <param name="entityTypeCollectionRegistrar">实体类型集合注册器</param>
|
||||
/// <param name="networkProtocolOpCodeResolver">网络协议 OpCode 解析器接口</param>
|
||||
/// <param name="networkProtocolResponseTypeResolver">网络协议 Response 解析器接口</param>
|
||||
public static void Register(
|
||||
long assemblyManifestId,
|
||||
System.Reflection.Assembly assembly,
|
||||
INetworkProtocolRegistrar networkProtocolRegistrar,
|
||||
IEventSystemRegistrar eventSystemRegistrar,
|
||||
IEntitySystemRegistrar entitySystemRegistrar,
|
||||
IMessageHandlerResolver messageHandlerResolver,
|
||||
IEntityTypeCollectionRegistrar entityTypeCollectionRegistrar,
|
||||
INetworkProtocolOpCodeResolver networkProtocolOpCodeResolver,
|
||||
INetworkProtocolResponseTypeResolver networkProtocolResponseTypeResolver)
|
||||
{
|
||||
var manifest = new AssemblyManifest
|
||||
{
|
||||
Assembly = assembly,
|
||||
AssemblyManifestId = assemblyManifestId,
|
||||
NetworkProtocolRegistrar = networkProtocolRegistrar,
|
||||
EventSystemRegistrar = eventSystemRegistrar,
|
||||
EntitySystemRegistrar = entitySystemRegistrar,
|
||||
MessageHandlerResolver = messageHandlerResolver,
|
||||
EntityTypeCollectionRegistrar = entityTypeCollectionRegistrar,
|
||||
NetworkProtocolOpCodeResolver = networkProtocolOpCodeResolver,
|
||||
NetworkProtocolResponseTypeResolver = networkProtocolResponseTypeResolver
|
||||
};
|
||||
#if FANTASY_WEBGL
|
||||
Manifests[assemblyManifestId] = manifest;
|
||||
#else
|
||||
Manifests.TryAdd(assemblyManifestId, manifest);
|
||||
#endif
|
||||
AssemblyLifecycle.OnLoad(manifest).Coroutine();
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 取消注册指定程序集的清单
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifestId">程序集唯一标识</param>
|
||||
public static void Unregister(long assemblyManifestId)
|
||||
{
|
||||
#if FANTASY_WEBGL
|
||||
if (Manifests.TryGetValue(assemblyManifestId, out var manifest))
|
||||
{
|
||||
AssemblyLifecycle.OnUnLoad(manifest).Coroutine();
|
||||
Manifests.Remove(assemblyManifestId);
|
||||
}
|
||||
#else
|
||||
if (Manifests.TryRemove(assemblyManifestId, out var manifest))
|
||||
{
|
||||
AssemblyLifecycle.OnUnLoad(manifest).Coroutine();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前框架注册的所有程序集清单
|
||||
/// 通过迭代器模式返回所有已注册的程序集清单对象
|
||||
/// </summary>
|
||||
public static IEnumerable<AssemblyManifest> GetAssemblyManifest
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var (_, assemblyManifest) in Manifests)
|
||||
{
|
||||
yield return assemblyManifest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放所有程序集清单资源
|
||||
/// 卸载所有已注册的程序集,触发卸载事件,清理所有注册器和生命周期回调
|
||||
/// </summary>
|
||||
/// <returns>异步任务</returns>
|
||||
public static async FTask Dispose()
|
||||
{
|
||||
foreach (var (_, assemblyManifest) in Manifests)
|
||||
{
|
||||
await AssemblyLifecycle.OnUnLoad(assemblyManifest);
|
||||
assemblyManifest.Clear();
|
||||
}
|
||||
|
||||
Manifests.Clear();
|
||||
AssemblyLifecycle.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 管理程序集加载和卸载的帮助类。
|
||||
/// </summary>
|
||||
public static class AssemblySystem
|
||||
{
|
||||
#if FANTASY_WEBGL
|
||||
private static readonly List<IAssembly> AssemblySystems = new List<IAssembly>();
|
||||
private static readonly Dictionary<long, AssemblyInfo> AssemblyList = new Dictionary<long, AssemblyInfo>();
|
||||
#else
|
||||
private static readonly ConcurrentQueue<IAssembly> AssemblySystems = new ConcurrentQueue<IAssembly>();
|
||||
private static readonly ConcurrentDictionary<long, AssemblyInfo> AssemblyList = new ConcurrentDictionary<long, AssemblyInfo>();
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 初始化 AssemblySystem。(仅限内部)
|
||||
/// </summary>
|
||||
/// <param name="assemblies"></param>
|
||||
internal static async FTask InnerInitialize(params System.Reflection.Assembly[] assemblies)
|
||||
{
|
||||
await LoadAssembly(typeof(AssemblySystem).Assembly);
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
await LoadAssembly(assembly);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载指定的程序集,并触发相应的事件。
|
||||
/// </summary>
|
||||
/// <param name="assembly">要加载的程序集。</param>
|
||||
/// <param name="isCurrentDomain">如果当前Domain中已经存在同名的Assembly,使用Domain中的程序集。</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载程序集
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将AssemblySystem接口的object注册到程序集管理中心
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 程序集管理中心卸载注册的Load、ReLoad、UnLoad的接口
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有已加载程序集中的所有类型。
|
||||
/// </summary>
|
||||
/// <returns>所有已加载程序集中的类型。</returns>
|
||||
public static IEnumerable<Type> ForEach()
|
||||
{
|
||||
foreach (var (_, assemblyInfo) in AssemblyList)
|
||||
{
|
||||
foreach (var type in assemblyInfo.AssemblyTypeList)
|
||||
{
|
||||
yield return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定程序集中的所有类型。
|
||||
/// </summary>
|
||||
/// <param name="assemblyIdentity">程序集唯一标识。</param>
|
||||
/// <returns>指定程序集中的类型。</returns>
|
||||
public static IEnumerable<Type> ForEach(long assemblyIdentity)
|
||||
{
|
||||
if (!AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var type in assemblyInfo.AssemblyTypeList)
|
||||
{
|
||||
yield return type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有已加载程序集中实现指定类型的所有类型。
|
||||
/// </summary>
|
||||
/// <param name="findType">要查找的基类或接口类型。</param>
|
||||
/// <returns>所有已加载程序集中实现指定类型的类型。</returns>
|
||||
public static IEnumerable<Type> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定程序集中实现指定类型的所有类型。
|
||||
/// </summary>
|
||||
/// <param name="assemblyIdentity">程序集唯一标识。</param>
|
||||
/// <param name="findType">要查找的基类或接口类型。</param>
|
||||
/// <returns>指定程序集中实现指定类型的类型。</returns>
|
||||
public static IEnumerable<Type> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定程序集的实例。
|
||||
/// </summary>
|
||||
/// <param name="assemblyIdentity">程序集名称。</param>
|
||||
/// <returns>指定程序集的实例,如果未加载则返回 null。</returns>
|
||||
public static System.Reflection.Assembly GetAssembly(long assemblyIdentity)
|
||||
{
|
||||
return !AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo) ? null : assemblyInfo.Assembly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前框架注册的Assembly
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<System.Reflection.Assembly> ForEachAssembly
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var (_, assemblyInfo) in AssemblyList)
|
||||
{
|
||||
yield return assemblyInfo.Assembly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据Assembly的强命名计算唯一标识。
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <returns></returns>
|
||||
private static long AssemblyIdentity(System.Reflection.Assembly assembly)
|
||||
{
|
||||
return HashCodeHelper.ComputeHash64(assembly.GetName().Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源,卸载所有加载的程序集。
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using Fantasy.Async;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 实现这个接口、会再程序集首次加载、卸载、重载的时候调用
|
||||
/// </summary>
|
||||
public interface IAssembly : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序集加载时调用
|
||||
/// </summary>
|
||||
/// <param name="assemblyIdentity">程序集标识</param>
|
||||
public FTask Load(long assemblyIdentity);
|
||||
/// <summary>
|
||||
/// 程序集重新加载的时候调用
|
||||
/// </summary>
|
||||
/// <param name="assemblyIdentity">程序集标识</param>
|
||||
public FTask ReLoad(long assemblyIdentity);
|
||||
/// <summary>
|
||||
/// 卸载的时候调用
|
||||
/// </summary>
|
||||
/// <param name="assemblyIdentity">程序集标识</param>
|
||||
public FTask OnUnLoad(long assemblyIdentity);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using Fantasy.Async;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序集生命周期回调接口
|
||||
/// 实现此接口的类型可以接收程序集的加载、卸载、重载事件通知
|
||||
/// 通过 AssemblySystem.Add() 注册后,在程序集状态变化时会自动调用对应的生命周期方法
|
||||
/// </summary>
|
||||
internal interface IAssemblyLifecycle
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序集加载或重载时调用
|
||||
/// 当新的程序集被加载到框架中时触发此回调,重新加载已存在的程序集时也会调用
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象,包含程序集的元数据和注册器</param>
|
||||
/// <returns>异步任务</returns>
|
||||
FTask OnLoad(AssemblyManifest assemblyManifest);
|
||||
|
||||
/// <summary>
|
||||
/// 程序集卸载时调用
|
||||
/// 当程序集从框架中卸载时触发此回调,应在此方法中清理该程序集相关的资源
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象,包含程序集的元数据和注册器</param>
|
||||
/// <returns>异步任务</returns>
|
||||
FTask OnUnload(AssemblyManifest assemblyManifest);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Entitas.Interface;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体系统注册器接口
|
||||
/// 由 Source Generator 自动生成实现类,用于在程序集加载时注册实体系统
|
||||
/// </summary>
|
||||
public interface IEntitySystemRegistrar
|
||||
{
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// 注册该程序集中的所有实体系统
|
||||
/// </summary>
|
||||
/// <param name="awakeSystems">Awake 系统容器</param>
|
||||
/// <param name="updateSystems">Update 系统容器</param>
|
||||
/// <param name="destroySystems">Destroy 系统容器</param>
|
||||
/// <param name="deserializeSystems">Deserialize 系统容器</param>
|
||||
void RegisterSystems(
|
||||
Dictionary<long, Action<Entity>> awakeSystems,
|
||||
Dictionary<long, Action<Entity>> updateSystems,
|
||||
Dictionary<long, Action<Entity>> destroySystems,
|
||||
Dictionary<long, Action<Entity>> deserializeSystems);
|
||||
|
||||
/// <summary>
|
||||
/// 取消注册该程序集中的所有实体系统(热重载卸载时调用)
|
||||
/// </summary>
|
||||
/// <param name="awakeSystems">Awake 系统容器</param>
|
||||
/// <param name="updateSystems">Update 系统容器</param>
|
||||
/// <param name="destroySystems">Destroy 系统容器</param>
|
||||
/// <param name="deserializeSystems">Deserialize 系统容器</param>
|
||||
void UnRegisterSystems(
|
||||
Dictionary<long, Action<Entity>> awakeSystems,
|
||||
Dictionary<long, Action<Entity>> updateSystems,
|
||||
Dictionary<long, Action<Entity>> destroySystems,
|
||||
Dictionary<long, Action<Entity>> deserializeSystems);
|
||||
#endif
|
||||
#if FANTASY_UNITY
|
||||
/// <summary>
|
||||
/// 注册该程序集中的所有实体系统
|
||||
/// </summary>
|
||||
/// <param name="awakeSystems">Awake 系统容器</param>
|
||||
/// <param name="updateSystems">Update 系统容器</param>
|
||||
/// <param name="destroySystems">Destroy 系统容器</param>
|
||||
/// <param name="deserializeSystems">Deserialize 系统容器</param>
|
||||
/// <param name="lateUpdateSystems">LateUpdate 系统容器</param>
|
||||
void RegisterSystems(
|
||||
Dictionary<long, Action<Entity>> awakeSystems,
|
||||
Dictionary<long, Action<Entity>> updateSystems,
|
||||
Dictionary<long, Action<Entity>> destroySystems,
|
||||
Dictionary<long, Action<Entity>> deserializeSystems,
|
||||
Dictionary<long, Action<Entity>> lateUpdateSystems);
|
||||
|
||||
/// <summary>
|
||||
/// 取消注册该程序集中的所有实体系统(热重载卸载时调用)
|
||||
/// </summary>
|
||||
/// <param name="awakeSystems">Awake 系统容器</param>
|
||||
/// <param name="updateSystems">Update 系统容器</param>
|
||||
/// <param name="destroySystems">Destroy 系统容器</param>
|
||||
/// <param name="deserializeSystems">Deserialize 系统容器</param>
|
||||
/// <param name="lateUpdateSystems">LateUpdate 系统容器</param>
|
||||
void UnRegisterSystems(
|
||||
Dictionary<long, Action<Entity>> awakeSystems,
|
||||
Dictionary<long, Action<Entity>> updateSystems,
|
||||
Dictionary<long, Action<Entity>> destroySystems,
|
||||
Dictionary<long, Action<Entity>> deserializeSystems,
|
||||
Dictionary<long, Action<Entity>> lateUpdateSystems);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体类型集合注册器接口
|
||||
/// 由 Source Generator 自动生成实现类,用于收集和提供程序集中定义的所有实体类型
|
||||
/// </summary>
|
||||
public interface IEntityTypeCollectionRegistrar
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取该程序集中定义的所有实体类型
|
||||
/// 返回继承自 Entity 的所有类型列表
|
||||
/// </summary>
|
||||
/// <returns>实体类型列表</returns>
|
||||
List<Type> GetEntityTypes();
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Event;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件系统注册器接口
|
||||
/// 由 Source Generator 自动生成实现类,用于在程序集加载时注册事件系统
|
||||
/// </summary>
|
||||
public interface IEventSystemRegistrar : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册该程序集中的所有事件系统
|
||||
/// </summary>
|
||||
/// <param name="events">同步事件容器</param>
|
||||
/// <param name="asyncEvents">异步事件容器</param>
|
||||
/// <param name="sphereEvents">领域事件容器</param>
|
||||
void RegisterSystems(
|
||||
OneToManyList<RuntimeTypeHandle, IEvent> events,
|
||||
OneToManyList<RuntimeTypeHandle, IEvent> asyncEvents,
|
||||
OneToManyList<RuntimeTypeHandle, IEvent> sphereEvents);
|
||||
|
||||
/// <summary>
|
||||
/// 取消注册该程序集中的所有事件系统(热重载卸载时调用)
|
||||
/// </summary>
|
||||
/// <param name="events">同步事件容器</param>
|
||||
/// <param name="asyncEvents">异步事件容器</param>
|
||||
/// <param name="sphereEvents">领域事件容器</param>
|
||||
void UnRegisterSystems(
|
||||
OneToManyList<RuntimeTypeHandle, IEvent> events,
|
||||
OneToManyList<RuntimeTypeHandle, IEvent> asyncEvents,
|
||||
OneToManyList<RuntimeTypeHandle, IEvent> sphereEvents);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Fantasy.DataStructure.Dictionary;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Network;
|
||||
using Fantasy.Network.Interface;
|
||||
using Fantasy.Async;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息分发器注册器接口
|
||||
/// 由 Source Generator 自动生成实现类,用于在程序集加载时注册网络消息处理器
|
||||
/// </summary>
|
||||
public interface IMessageHandlerResolver
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
int GetMessageHandlerCount();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="session"></param>
|
||||
/// <param name="rpcId"></param>
|
||||
/// <param name="protocolCode"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
bool MessageHandler(Session session, uint rpcId, uint protocolCode, object message);
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
int GetRouteMessageHandlerCount();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="session"></param>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="rpcId"></param>
|
||||
/// <param name="protocolCode"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
FTask<bool> RouteMessageHandler(Session session, Entity entity, uint rpcId, uint protocolCode, object message);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络协议 OpCode 解析器接口
|
||||
/// 用于通过生成的 switch 表达式实现高性能的 OpCode 到 Type 的解析
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 此接口由 SourceGenerator 自动生成的类实现。
|
||||
/// 每个包含网络协议的程序集都会生成自己的解析器实现。
|
||||
/// 生成的实现使用 switch 表达式而不是字典查找,以获得更好的性能。
|
||||
/// </remarks>
|
||||
public interface INetworkProtocolOpCodeResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取当前OpCode数量
|
||||
/// </summary>
|
||||
/// <returns>返回对应的OpCode数量</returns>
|
||||
int GetOpCodeCount();
|
||||
/// <summary>
|
||||
/// 获取当前RouteType数量
|
||||
/// </summary>
|
||||
/// <returns>返回对应的RouteType数量</returns>
|
||||
int GetCustomRouteTypeCount();
|
||||
/// <summary>
|
||||
/// 根据指定的 OpCode 获取对应的 Type
|
||||
/// </summary>
|
||||
/// <param name="opCode">网络协议操作码</param>
|
||||
/// <returns>OpCode 对应的类型;如果未找到则返回 null</returns>
|
||||
Type GetOpCodeType(uint opCode);
|
||||
/// <summary>
|
||||
/// 根据指定的 OpCode 获取对应的 CustomRouteType
|
||||
/// </summary>
|
||||
/// <param name="opCode">网络协议操作码</param>
|
||||
/// <returns>OpCode 对应的CustomRouteType;如果未找到则返回 null</returns>
|
||||
int? GetCustomRouteType(uint opCode);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// NetworkProtocol 类型注册器接口
|
||||
/// 由 Source Generator 自动生成实现类,用于收集和提供程序集中需要 NetworkProtocol 序列化的类型
|
||||
/// </summary>
|
||||
public interface INetworkProtocolRegistrar
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取该程序集中需要 NetworkProtocol 序列化的所有类型
|
||||
/// 返回所有使用 NetworkProtocol 序列化特性标记的类型列表
|
||||
/// </summary>
|
||||
/// <returns>NetworkProtocol 序列化类型列表</returns>
|
||||
List<Type> GetNetworkProtocolTypes();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Fantasy.Assembly
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络协议响应类型解析器接口
|
||||
/// 用于根据 OpCode 解析对应的响应消息类型
|
||||
/// 此接口通常由 NetworkProtocol SourceGenerator 自动生成实现
|
||||
/// </summary>
|
||||
public interface INetworkProtocolResponseTypeResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取已注册的 Response 总数
|
||||
/// </summary>
|
||||
/// <returns>协议系统中可用的 OpCode 数量</returns>
|
||||
int GetRequestCount();
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定 OpCode 对应的响应消息类型
|
||||
/// 用于在处理网络消息时确定期望的响应类型
|
||||
/// </summary>
|
||||
/// <param name="opCode">要解析的 OpCode</param>
|
||||
/// <returns>响应消息的类型,如果该 OpCode 没有关联响应类型则返回 null</returns>
|
||||
Type GetResponseType(uint opCode);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#if FANTASY_NET
|
||||
namespace Fantasy.Assembly;
|
||||
|
||||
/// <summary>
|
||||
/// 分表注册器接口,用于自动注册标记了 SeparateTableAttribute 的实体类型。
|
||||
/// 通过 Source Generator 自动生成实现类,替代运行时反射,提升性能。
|
||||
/// </summary>
|
||||
public interface ISeparateTableRegistrar
|
||||
{
|
||||
/// <summary>
|
||||
/// 分表信息记录,包含父实体类型、子实体类型和数据库集合名称。
|
||||
/// </summary>
|
||||
/// <param name="RootType">父实体的类型,表示子实体属于哪个父实体。</param>
|
||||
/// <param name="EntityType">子实体的类型,即标记了 SeparateTableAttribute 的实体类型。</param>
|
||||
/// <param name="TableName">在数据库中使用的集合名称。</param>
|
||||
public sealed record SeparateTableInfo(Type RootType, Type EntityType, string TableName);
|
||||
|
||||
/// <summary>
|
||||
/// 注册所有分表信息。
|
||||
/// 返回包含所有标记了 SeparateTableAttribute 的实体及其配置信息的列表。
|
||||
/// </summary>
|
||||
/// <returns>分表信息列表。</returns>
|
||||
List<SeparateTableInfo> Register();
|
||||
|
||||
/// <summary>
|
||||
/// 反注册所有分表信息。
|
||||
/// 返回需要移除的分表信息列表。
|
||||
/// </summary>
|
||||
/// <returns>分表信息列表。</returns>
|
||||
List<SeparateTableInfo> UnRegister();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,523 @@
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using Fantasy.Assembly;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
|
||||
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace Fantasy.Entitas
|
||||
{
|
||||
internal sealed class UpdateQueueInfo
|
||||
{
|
||||
public bool IsStop;
|
||||
public readonly Type Type;
|
||||
public readonly long RunTimeId;
|
||||
|
||||
public UpdateQueueInfo(Type type, long runTimeId)
|
||||
{
|
||||
Type = type;
|
||||
IsStop = false;
|
||||
RunTimeId = runTimeId;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class FrameUpdateQueueInfo
|
||||
{
|
||||
public readonly Type Type;
|
||||
public readonly long RunTimeId;
|
||||
|
||||
public FrameUpdateQueueInfo(Type type, long runTimeId)
|
||||
{
|
||||
Type = type;
|
||||
RunTimeId = runTimeId;
|
||||
}
|
||||
}
|
||||
|
||||
internal struct CustomEntitiesSystemKey : IEquatable<CustomEntitiesSystemKey>
|
||||
{
|
||||
public int CustomEventType { get; }
|
||||
public Type EntitiesType { get; }
|
||||
public CustomEntitiesSystemKey(int customEventType, Type entitiesType)
|
||||
{
|
||||
CustomEventType = customEventType;
|
||||
EntitiesType = entitiesType;
|
||||
}
|
||||
public bool Equals(CustomEntitiesSystemKey other)
|
||||
{
|
||||
return CustomEventType == other.CustomEventType && EntitiesType == other.EntitiesType;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is CustomEntitiesSystemKey other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(CustomEventType, EntitiesType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entity管理组件
|
||||
/// </summary>
|
||||
#if FANTASY_UNITY
|
||||
public sealed class EntityComponent : Entity, ISceneUpdate, ISceneLateUpdate, IAssembly
|
||||
#else
|
||||
public sealed class EntityComponent : Entity, ISceneUpdate, IAssembly
|
||||
#endif
|
||||
{
|
||||
private readonly OneToManyList<long, Type> _assemblyList = new();
|
||||
private readonly OneToManyList<long, Type> _assemblyHashCodes = new();
|
||||
|
||||
private readonly Dictionary<Type, IAwakeSystem> _awakeSystems = new();
|
||||
private readonly Dictionary<Type, IUpdateSystem> _updateSystems = new();
|
||||
private readonly Dictionary<Type, IDestroySystem> _destroySystems = new();
|
||||
private readonly Dictionary<Type, IDeserializeSystem> _deserializeSystems = new();
|
||||
|
||||
private readonly OneToManyList<long, CustomEntitiesSystemKey> _assemblyCustomSystemList = new();
|
||||
private readonly Dictionary<CustomEntitiesSystemKey, ICustomEntitiesSystem> _customEntitiesSystems = new Dictionary<CustomEntitiesSystemKey, ICustomEntitiesSystem>();
|
||||
|
||||
private readonly Dictionary<Type, long> _hashCodes = new Dictionary<Type, long>();
|
||||
private readonly Queue<UpdateQueueInfo> _updateQueue = new Queue<UpdateQueueInfo>();
|
||||
|
||||
private readonly Dictionary<long, UpdateQueueInfo> _updateQueueDic = new Dictionary<long, UpdateQueueInfo>();
|
||||
#if FANTASY_UNITY
|
||||
private readonly Dictionary<Type, ILateUpdateSystem> _lateUpdateSystems = new();
|
||||
private readonly Queue<UpdateQueueInfo> _lateUpdateQueue = new Queue<UpdateQueueInfo>();
|
||||
private readonly Dictionary<long, UpdateQueueInfo> _lateUpdateQueueDic = new Dictionary<long, UpdateQueueInfo>();
|
||||
#endif
|
||||
|
||||
internal async FTask<EntityComponent> Initialize()
|
||||
{
|
||||
await AssemblySystem.Register(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
#region Assembly
|
||||
|
||||
public FTask Load(long assemblyIdentity)
|
||||
{
|
||||
var task = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
LoadInner(assemblyIdentity);
|
||||
task.SetResult();
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
public FTask ReLoad(long assemblyIdentity)
|
||||
{
|
||||
var task = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyIdentity);
|
||||
LoadInner(assemblyIdentity);
|
||||
task.SetResult();
|
||||
});
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
public FTask OnUnLoad(long assemblyIdentity)
|
||||
{
|
||||
var task = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyIdentity);
|
||||
task.SetResult();
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
private void LoadInner(long assemblyIdentity)
|
||||
{
|
||||
foreach (var entityType in AssemblySystem.ForEach(assemblyIdentity, typeof(IEntity)))
|
||||
{
|
||||
_hashCodes.Add(entityType, HashCodeHelper.ComputeHash64(entityType.FullName));
|
||||
_assemblyHashCodes.Add(assemblyIdentity, entityType);
|
||||
}
|
||||
|
||||
foreach (var entitiesSystemType in AssemblySystem.ForEach(assemblyIdentity, typeof(IEntitiesSystem)))
|
||||
{
|
||||
Type entitiesType = null;
|
||||
var entity = Activator.CreateInstance(entitiesSystemType);
|
||||
|
||||
switch (entity)
|
||||
{
|
||||
case IAwakeSystem iAwakeSystem:
|
||||
{
|
||||
entitiesType = iAwakeSystem.EntitiesType();
|
||||
_awakeSystems.Add(entitiesType, iAwakeSystem);
|
||||
break;
|
||||
}
|
||||
case IDestroySystem iDestroySystem:
|
||||
{
|
||||
entitiesType = iDestroySystem.EntitiesType();
|
||||
_destroySystems.Add(entitiesType, iDestroySystem);
|
||||
break;
|
||||
}
|
||||
case IDeserializeSystem iDeserializeSystem:
|
||||
{
|
||||
entitiesType = iDeserializeSystem.EntitiesType();
|
||||
_deserializeSystems.Add(entitiesType, iDeserializeSystem);
|
||||
break;
|
||||
}
|
||||
case IUpdateSystem iUpdateSystem:
|
||||
{
|
||||
entitiesType = iUpdateSystem.EntitiesType();
|
||||
_updateSystems.Add(entitiesType, iUpdateSystem);
|
||||
break;
|
||||
}
|
||||
#if FANTASY_UNITY
|
||||
case ILateUpdateSystem iLateUpdateSystem:
|
||||
{
|
||||
entitiesType = iLateUpdateSystem.EntitiesType();
|
||||
_lateUpdateSystems.Add(entitiesType, iLateUpdateSystem);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
Log.Error($"IEntitiesSystem not support type {entitiesSystemType}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_assemblyList.Add(assemblyIdentity, entitiesType);
|
||||
}
|
||||
|
||||
foreach (var customEntitiesSystemType in AssemblySystem.ForEach(assemblyIdentity, typeof(ICustomEntitiesSystem)))
|
||||
{
|
||||
var entity = (ICustomEntitiesSystem)Activator.CreateInstance(customEntitiesSystemType);
|
||||
var customEntitiesSystemKey = new CustomEntitiesSystemKey(entity.CustomEventType, entity.EntitiesType());
|
||||
_customEntitiesSystems.Add(customEntitiesSystemKey, entity);
|
||||
_assemblyCustomSystemList.Add(assemblyIdentity, customEntitiesSystemKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUnLoadInner(long assemblyIdentity)
|
||||
{
|
||||
if (_assemblyHashCodes.TryGetValue(assemblyIdentity, out var entityType))
|
||||
{
|
||||
foreach (var type in entityType)
|
||||
{
|
||||
_hashCodes.Remove(type);
|
||||
}
|
||||
|
||||
_assemblyHashCodes.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
if (_assemblyList.TryGetValue(assemblyIdentity, out var assembly))
|
||||
{
|
||||
foreach (var type in assembly)
|
||||
{
|
||||
_awakeSystems.Remove(type);
|
||||
_updateSystems.Remove(type);
|
||||
_destroySystems.Remove(type);
|
||||
#if FANTASY_UNITY
|
||||
_lateUpdateSystems.Remove(type);
|
||||
#endif
|
||||
_deserializeSystems.Remove(type);
|
||||
}
|
||||
|
||||
_assemblyList.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
if (_assemblyCustomSystemList.TryGetValue(assemblyIdentity, out var customSystemAssembly))
|
||||
{
|
||||
foreach (var customEntitiesSystemKey in customSystemAssembly)
|
||||
{
|
||||
_customEntitiesSystems.Remove(customEntitiesSystemKey);
|
||||
}
|
||||
|
||||
_assemblyCustomSystemList.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event
|
||||
|
||||
/// <summary>
|
||||
/// 触发实体的唤醒方法
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void Awake(Entity entity)
|
||||
{
|
||||
if (!_awakeSystems.TryGetValue(entity.Type, out var awakeSystem))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
awakeSystem.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{entity.Type.FullName} Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发实体的销毁方法
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void Destroy(Entity entity)
|
||||
{
|
||||
if (!_destroySystems.TryGetValue(entity.Type, out var system))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
system.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{entity.Type.FullName} Destroy Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发实体的反序列化方法
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void Deserialize(Entity entity)
|
||||
{
|
||||
if (!_deserializeSystems.TryGetValue(entity.Type, out var system))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
system.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{entity.Type.FullName} Deserialize Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CustomEvent
|
||||
|
||||
public void CustomSystem(Entity entity, int customEventType)
|
||||
{
|
||||
var customEntitiesSystemKey = new CustomEntitiesSystemKey(customEventType, entity.Type);
|
||||
|
||||
if (!_customEntitiesSystems.TryGetValue(customEntitiesSystemKey, out var system))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
system.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{entity.Type.FullName} CustomSystem Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update
|
||||
|
||||
/// <summary>
|
||||
/// 将实体加入Update队列,准备进行Update
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void StartUpdate(Entity entity)
|
||||
{
|
||||
var type = entity.Type;
|
||||
var entityRuntimeId = entity.RuntimeId;
|
||||
|
||||
if (!_updateSystems.ContainsKey(type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId);
|
||||
_updateQueue.Enqueue(updateQueueInfo);
|
||||
_updateQueueDic.Add(entityRuntimeId, updateQueueInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止实体Update
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void StopUpdate(Entity entity)
|
||||
{
|
||||
if (!_updateQueueDic.Remove(entity.RuntimeId, out var updateQueueInfo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
updateQueueInfo.IsStop = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行实体系统的Update
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
var updateQueueCount = _updateQueue.Count;
|
||||
|
||||
while (updateQueueCount-- > 0)
|
||||
{
|
||||
var updateQueueStruct = _updateQueue.Dequeue();
|
||||
|
||||
if (updateQueueStruct.IsStop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_updateSystems.TryGetValue(updateQueueStruct.Type, out var updateSystem))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var entity = Scene.GetEntity(updateQueueStruct.RunTimeId);
|
||||
|
||||
if (entity == null || entity.IsDisposed)
|
||||
{
|
||||
_updateQueueDic.Remove(updateQueueStruct.RunTimeId);
|
||||
continue;
|
||||
}
|
||||
|
||||
_updateQueue.Enqueue(updateQueueStruct);
|
||||
|
||||
try
|
||||
{
|
||||
updateSystem.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{updateQueueStruct.Type.FullName} Update Error {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#if FANTASY_UNITY
|
||||
#region LateUpdate
|
||||
|
||||
/// <summary>
|
||||
/// 将实体加入LateUpdate队列,准备进行LateUpdate
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void StartLateUpdate(Entity entity)
|
||||
{
|
||||
var type = entity.Type;
|
||||
var entityRuntimeId = entity.RuntimeId;
|
||||
|
||||
if (!_lateUpdateSystems.ContainsKey(type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId);
|
||||
_lateUpdateQueue.Enqueue(updateQueueInfo);
|
||||
_lateUpdateQueueDic.Add(entityRuntimeId, updateQueueInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止实体进行LateUpdate
|
||||
/// </summary>
|
||||
/// <param name="entity">实体对象</param>
|
||||
public void StopLateUpdate(Entity entity)
|
||||
{
|
||||
if (!_lateUpdateQueueDic.Remove(entity.RuntimeId, out var updateQueueInfo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
updateQueueInfo.IsStop = true;
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
var lateUpdateQueue = _lateUpdateQueue.Count;
|
||||
|
||||
while (lateUpdateQueue-- > 0)
|
||||
{
|
||||
var lateUpdateQueueStruct = _lateUpdateQueue.Dequeue();
|
||||
|
||||
if (lateUpdateQueueStruct.IsStop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_lateUpdateSystems.TryGetValue(lateUpdateQueueStruct.Type, out var lateUpdateSystem))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var entity = Scene.GetEntity(lateUpdateQueueStruct.RunTimeId);
|
||||
|
||||
if (entity == null || entity.IsDisposed)
|
||||
{
|
||||
_lateUpdateQueueDic.Remove(lateUpdateQueueStruct.RunTimeId);
|
||||
continue;
|
||||
}
|
||||
|
||||
_lateUpdateQueue.Enqueue(lateUpdateQueueStruct);
|
||||
|
||||
try
|
||||
{
|
||||
lateUpdateSystem.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{lateUpdateQueueStruct.Type.FullName} Update Error {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endif
|
||||
public long GetHashCode(Type type)
|
||||
{
|
||||
return _hashCodes[type];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放实体系统管理器资源
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
_updateQueue.Clear();
|
||||
_updateQueueDic.Clear();
|
||||
#if FANTASY_UNITY
|
||||
_lateUpdateQueue.Clear();
|
||||
_lateUpdateQueueDic.Clear();
|
||||
_lateUpdateSystems.Clear();
|
||||
#endif
|
||||
_assemblyList.Clear();
|
||||
_awakeSystems.Clear();
|
||||
_updateSystems.Clear();
|
||||
_destroySystems.Clear();
|
||||
_deserializeSystems.Clear();
|
||||
|
||||
AssemblySystem.UnRegister(this);
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,476 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Fantasy.Assembly;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas.Interface;
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
// ReSharper disable ForCanBeConvertedToForeach
|
||||
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
|
||||
#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 CS8602 // Dereference of a possibly null reference.
|
||||
|
||||
namespace Fantasy.Entitas
|
||||
{
|
||||
/// <summary>
|
||||
/// 更新队列节点,用于存储需要每帧更新的实体信息
|
||||
/// </summary>
|
||||
internal sealed class UpdateQueueNode
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体类型
|
||||
/// </summary>
|
||||
public long TypeHashCode;
|
||||
/// <summary>
|
||||
/// 实体运行时ID
|
||||
/// </summary>
|
||||
public long RunTimeId;
|
||||
}
|
||||
/// <summary>
|
||||
/// 实体组件系统管理器,负责管理所有实体的生命周期和系统调度
|
||||
/// 支持程序集热重载、实体生命周期事件和每帧更新循环
|
||||
/// </summary>
|
||||
#if FANTASY_UNITY
|
||||
public sealed class EntityComponent : Entity, ISceneUpdate, ISceneLateUpdate, IAssemblyLifecycle
|
||||
#else
|
||||
public sealed class EntityComponent : Entity, ISceneUpdate, IAssemblyLifecycle
|
||||
#endif
|
||||
{
|
||||
/// <summary>
|
||||
/// 已加载的程序集清单ID集合
|
||||
/// </summary>
|
||||
private readonly HashSet<long> _assemblyManifests = new();
|
||||
/// <summary>
|
||||
/// 实体唤醒系统字典,Key为实体类型TypeHashCode,Value为对应的唤醒系统
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, Action<Entity>> _awakeSystems = new();
|
||||
/// <summary>
|
||||
/// 实体更新系统字典,Key为实体类型TypeHashCode,Value为对应的更新系统
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, Action<Entity>> _updateSystems = new();
|
||||
/// <summary>
|
||||
/// 实体销毁系统字典,Key为实体类型TypeHashCode,Value为对应的销毁系统
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, Action<Entity>> _destroySystems = new();
|
||||
/// <summary>
|
||||
/// 实体反序列化系统字典,Key为实体类型TypeHashCode,Value为对应的反序列化系统
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, Action<Entity>> _deserializeSystems = new();
|
||||
/// <summary>
|
||||
/// 更新队列,使用链表实现循环遍历和O(1)删除
|
||||
/// </summary>
|
||||
private readonly LinkedList<UpdateQueueNode> _updateQueue = new();
|
||||
/// <summary>
|
||||
/// 更新节点字典,Key为实体RuntimeId,Value为对应的链表节点,用于快速查找和删除
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, LinkedListNode<UpdateQueueNode>> _updateNodes = new();
|
||||
#if FANTASY_UNITY
|
||||
private readonly Dictionary<long, Action<Entity>> _lateUpdateSystems = new();
|
||||
/// <summary>
|
||||
/// Late更新队列,使用链表实现循环遍历和O(1)删除
|
||||
/// </summary>
|
||||
private readonly LinkedList<UpdateQueueNode> _lateUpdateQueue = new();
|
||||
/// <summary>
|
||||
/// Late更新节点字典,Key为实体RuntimeId,Value为对应的链表节点,用于快速查找和删除
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, LinkedListNode<UpdateQueueNode>> _lateUpdateNodes = new();
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 销毁时会清理组件里的所有数据
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_assemblyManifests.Clear();
|
||||
_awakeSystems.Clear();
|
||||
_updateSystems.Clear();
|
||||
_destroySystems.Clear();
|
||||
|
||||
_updateQueue.Clear();
|
||||
_updateNodes.Clear();
|
||||
#if FANTASY_UNITY
|
||||
_lateUpdateSystems.Clear();
|
||||
_lateUpdateQueue.Clear();
|
||||
_lateUpdateNodes.Clear();
|
||||
#endif
|
||||
AssemblyLifecycle.Remove(this);
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
#region AssemblyManifest
|
||||
|
||||
/// <summary>
|
||||
/// 初始化EntityComponent,将其注册到程序集系统中
|
||||
/// </summary>
|
||||
/// <returns>返回初始化后的EntityComponent实例</returns>
|
||||
internal async FTask<EntityComponent> Initialize()
|
||||
{
|
||||
await AssemblyLifecycle.Add(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载程序集,注册该程序集中的所有实体系统
|
||||
/// 支持热重载:如果程序集已加载,会先卸载再重新加载
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象,包含程序集的元数据和注册器</param>
|
||||
/// <returns>异步任务</returns>
|
||||
public FTask OnLoad(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
var task = FTask.Create(false);
|
||||
var assemblyManifestId = assemblyManifest.AssemblyManifestId;
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
// 如果程序集已加载,先卸载旧的
|
||||
if (_assemblyManifests.Contains(assemblyManifestId))
|
||||
{
|
||||
OnUnLoadInner(assemblyManifest);
|
||||
}
|
||||
#if FANTASY_NET
|
||||
assemblyManifest.EntitySystemRegistrar.RegisterSystems(
|
||||
_awakeSystems,
|
||||
_updateSystems,
|
||||
_destroySystems,
|
||||
_deserializeSystems);
|
||||
#endif
|
||||
#if FANTASY_UNITY
|
||||
assemblyManifest.EntitySystemRegistrar.RegisterSystems(
|
||||
_awakeSystems,
|
||||
_updateSystems,
|
||||
_destroySystems,
|
||||
_deserializeSystems,
|
||||
_lateUpdateSystems);
|
||||
#endif
|
||||
_assemblyManifests.Add(assemblyManifestId);
|
||||
task.SetResult();
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载程序集,取消注册该程序集中的所有实体系统
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象,包含程序集的元数据和注册器</param>
|
||||
/// <returns>异步任务</returns>
|
||||
public FTask OnUnload(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
var task = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyManifest);
|
||||
task.SetResult();
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载程序集的内部实现
|
||||
/// 会清理该程序集注册的所有系统,并移除更新队列中对应的实体
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象,包含程序集的元数据和注册器</param>
|
||||
private void OnUnLoadInner(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
#if FANTASY_NET
|
||||
assemblyManifest.EntitySystemRegistrar.UnRegisterSystems(
|
||||
_awakeSystems,
|
||||
_updateSystems,
|
||||
_destroySystems,
|
||||
_deserializeSystems);
|
||||
#endif
|
||||
#if FANTASY_UNITY
|
||||
assemblyManifest.EntitySystemRegistrar.UnRegisterSystems(
|
||||
_awakeSystems,
|
||||
_updateSystems,
|
||||
_destroySystems,
|
||||
_deserializeSystems,
|
||||
_lateUpdateSystems);
|
||||
#endif
|
||||
_assemblyManifests.Remove(assemblyManifest.AssemblyManifestId);
|
||||
// 清理更新队列中已失效的节点(系统被卸载后,对应实体的更新系统不再存在)
|
||||
var node = _updateQueue.First;
|
||||
while (node != null)
|
||||
{
|
||||
var next = node.Next;
|
||||
if (!_updateSystems.ContainsKey(node.Value.TypeHashCode))
|
||||
{
|
||||
_updateQueue.Remove(node);
|
||||
_updateNodes.Remove(node.Value.RunTimeId);
|
||||
}
|
||||
node = next;
|
||||
}
|
||||
#if FANTASY_UNITY
|
||||
var lateNode = _lateUpdateQueue.First;
|
||||
while (lateNode != null)
|
||||
{
|
||||
var next = lateNode.Next;
|
||||
if (!_lateUpdateSystems.ContainsKey(lateNode.Value.TypeHashCode))
|
||||
{
|
||||
_lateUpdateQueue.Remove(lateNode);
|
||||
_lateUpdateNodes.Remove(lateNode.Value.RunTimeId);
|
||||
}
|
||||
lateNode = next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event
|
||||
|
||||
/// <summary>
|
||||
/// 触发实体的唤醒事件,调用对应的AwakeSystem
|
||||
/// </summary>
|
||||
/// <param name="entity">需要唤醒的实体</param>
|
||||
public void Awake(Entity entity)
|
||||
{
|
||||
if (!_awakeSystems.TryGetValue(entity.TypeHashCode, out var awakeSystem))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
awakeSystem(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{entity.Type.FullName} Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发实体的销毁事件,调用对应的DestroySystem
|
||||
/// </summary>
|
||||
/// <param name="entity">需要销毁的实体</param>
|
||||
public void Destroy(Entity entity)
|
||||
{
|
||||
if (!_destroySystems.TryGetValue(entity.TypeHashCode, out var system))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
system(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{entity.Type.FullName} Destroy Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发实体的反序列化事件,调用对应的DeserializeSystem
|
||||
/// </summary>
|
||||
/// <param name="entity">需要反序列化的实体</param>
|
||||
public void Deserialize(Entity entity)
|
||||
{
|
||||
if (!_deserializeSystems.TryGetValue(entity.TypeHashCode, out var system))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
system(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{entity.Type.FullName} Deserialize Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update
|
||||
|
||||
/// <summary>
|
||||
/// 注册实体到每帧更新循环
|
||||
/// 实体将在每帧Update时执行对应的UpdateSystem
|
||||
/// </summary>
|
||||
/// <param name="entity">需要注册更新的实体</param>
|
||||
public void RegisterUpdate(Entity entity)
|
||||
{
|
||||
var typeHashCode = entity.TypeHashCode;
|
||||
// 检查该实体类型是否有对应的更新系统
|
||||
if (!_updateSystems.ContainsKey(typeHashCode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var runtimeId = entity.RuntimeId;
|
||||
// 防止重复注册
|
||||
if (_updateNodes.ContainsKey(runtimeId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建节点并加入链表尾部
|
||||
var nodeData = new UpdateQueueNode { TypeHashCode = typeHashCode, RunTimeId = runtimeId };
|
||||
var node = _updateQueue.AddLast(nodeData);
|
||||
_updateNodes.Add(runtimeId, node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从每帧更新循环中注销实体
|
||||
/// 实体将不再执行UpdateSystem
|
||||
/// </summary>
|
||||
/// <param name="entity">需要注销更新的实体</param>
|
||||
public void UnregisterUpdate(Entity entity)
|
||||
{
|
||||
if (!_updateNodes.Remove(entity.RuntimeId, out var node))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 利用链表节点实现O(1)时间复杂度删除
|
||||
_updateQueue.Remove(node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每帧更新循环,遍历所有已注册的实体并调用对应的UpdateSystem
|
||||
/// 使用链表实现循环队列,已删除的实体会自动清理
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
var scene = Scene;
|
||||
var node = _updateQueue.First;
|
||||
var count = _updateQueue.Count;
|
||||
|
||||
// 遍历当前所有节点,count确保只遍历本帧的节点
|
||||
while (count-- > 0 && node != null)
|
||||
{
|
||||
var next = node.Next; // 提前保存下一个节点,防止当前节点被删除
|
||||
var data = node.Value;
|
||||
|
||||
// 检查更新系统是否存在(可能被热重载卸载)
|
||||
if (!_updateSystems.TryGetValue(data.TypeHashCode, out var updateSystem))
|
||||
{
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
var entity = scene.GetEntity(data.RunTimeId);
|
||||
|
||||
// 如果实体已销毁,自动清理
|
||||
if (entity == null || entity.IsDisposed)
|
||||
{
|
||||
_updateQueue.Remove(node);
|
||||
_updateNodes.Remove(data.RunTimeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
updateSystem.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"Update Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LateUpdate
|
||||
#if FANTASY_UNITY
|
||||
/// <summary>
|
||||
/// 注册实体到每帧更新循环
|
||||
/// 实体将在每帧LateUUpdate时执行对应的LateUUpdateSystem
|
||||
/// </summary>
|
||||
/// <param name="entity">需要注册更新的实体</param>
|
||||
public void RegisterLateUpdate(Entity entity)
|
||||
{
|
||||
var typeHashCode = entity.TypeHashCode;
|
||||
// 检查该实体类型是否有对应的更新系统
|
||||
if (!_lateUpdateSystems.ContainsKey(typeHashCode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var runtimeId = entity.RuntimeId;
|
||||
// 防止重复注册
|
||||
if (_lateUpdateNodes.ContainsKey(runtimeId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建节点并加入链表尾部
|
||||
var nodeData = new UpdateQueueNode { TypeHashCode = typeHashCode, RunTimeId = runtimeId };
|
||||
var node = _lateUpdateQueue.AddLast(nodeData);
|
||||
_lateUpdateNodes.Add(runtimeId, node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从每帧更新循环中注销实体
|
||||
/// 实体将不再执行LateUpdateSystem
|
||||
/// </summary>
|
||||
/// <param name="entity">需要注销更新的实体</param>
|
||||
public void UnregisterLateUpdate(Entity entity)
|
||||
{
|
||||
if (!_lateUpdateNodes.Remove(entity.RuntimeId, out var node))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 利用链表节点实现O(1)时间复杂度删除
|
||||
_lateUpdateQueue.Remove(node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每帧更新循环,遍历所有已注册的实体并调用对应的LateUpdateSystem
|
||||
/// 使用链表实现循环队列,已删除的实体会自动清理
|
||||
/// </summary>
|
||||
public void LateUpdate()
|
||||
{
|
||||
var scene = Scene;
|
||||
var node = _lateUpdateQueue.First;
|
||||
var count = _lateUpdateQueue.Count;
|
||||
|
||||
// 遍历当前所有节点,count确保只遍历本帧的节点
|
||||
while (count-- > 0 && node != null)
|
||||
{
|
||||
var next = node.Next; // 提前保存下一个节点,防止当前节点被删除
|
||||
var data = node.Value;
|
||||
|
||||
// 检查更新系统是否存在(可能被热重载卸载)
|
||||
if (!_lateUpdateSystems.TryGetValue(data.TypeHashCode, out var lateUpdateSystem))
|
||||
{
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
var entity = scene.GetEntity(data.RunTimeId);
|
||||
|
||||
// 如果实体已销毁,自动清理
|
||||
if (entity == null || entity.IsDisposed)
|
||||
{
|
||||
_lateUpdateQueue.Remove(node);
|
||||
_lateUpdateNodes.Remove(data.RunTimeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
lateUpdateSystem.Invoke(entity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"Update Error {e}");
|
||||
}
|
||||
}
|
||||
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,108 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Fantasy.Assembly;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Entitas;
|
||||
|
||||
// ReSharper disable PossibleMultipleEnumeration
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
// ReSharper disable MethodOverloadWithOptionalParameter
|
||||
|
||||
namespace Fantasy.Event
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件组件系统,负责管理和调度所有事件
|
||||
/// </summary>
|
||||
public sealed class EventComponent : Entity, IAssemblyLifecycle
|
||||
internal sealed class EventCache
|
||||
{
|
||||
private readonly HashSet<long> _assemblyManifests = new();
|
||||
private readonly OneToManyList<RuntimeTypeHandle, IEvent> _events = new();
|
||||
private readonly OneToManyList<RuntimeTypeHandle, IEvent> _asyncEvents = new();
|
||||
private readonly OneToManyList<RuntimeTypeHandle, IEvent> _sphereEvents = new();
|
||||
|
||||
/// <summary>
|
||||
/// 销毁时会清理组件里的所有数据
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
public readonly Type EnventType;
|
||||
public readonly object Obj;
|
||||
public EventCache(Type enventType, object obj)
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_assemblyManifests.Clear();
|
||||
_events.Clear();
|
||||
_asyncEvents.Clear();
|
||||
_sphereEvents.Clear();
|
||||
AssemblyLifecycle.Remove(this);
|
||||
base.Dispose();
|
||||
EnventType = enventType;
|
||||
Obj = obj;
|
||||
}
|
||||
}
|
||||
|
||||
#region AssemblyManifest
|
||||
public sealed class EventComponent : Entity, IAssembly
|
||||
{
|
||||
private readonly OneToManyList<Type, IEvent> _events = new();
|
||||
private readonly OneToManyList<Type, IAsyncEvent> _asyncEvents = new();
|
||||
private readonly OneToManyList<long, EventCache> _assemblyEvents = new();
|
||||
private readonly OneToManyList<long, EventCache> _assemblyAsyncEvents = new();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化EventComponent,将其注册到程序集系统中
|
||||
/// </summary>
|
||||
/// <returns>返回初始化后的EventComponent实例</returns>
|
||||
internal async FTask<EventComponent> Initialize()
|
||||
{
|
||||
await AssemblyLifecycle.Add(this);
|
||||
await AssemblySystem.Register(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载程序集,注册该程序集中的所有事件系统
|
||||
/// 支持热重载:如果程序集已加载,会先卸载再重新加载
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象,包含程序集的元数据和注册器</param>
|
||||
/// <returns>异步任务</returns>
|
||||
public async FTask OnLoad(AssemblyManifest assemblyManifest)
|
||||
|
||||
#region Assembly
|
||||
|
||||
public async FTask Load(long assemblyIdentity)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
var assemblyManifestId = assemblyManifest.AssemblyManifestId;
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
// 如果程序集已加载,先卸载旧的
|
||||
if (_assemblyManifests.Contains(assemblyManifestId))
|
||||
LoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
public async FTask ReLoad(long assemblyIdentity)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyIdentity);
|
||||
LoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
public async FTask OnUnLoad(long assemblyIdentity)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
private void LoadInner(long assemblyIdentity)
|
||||
{
|
||||
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IEvent)))
|
||||
{
|
||||
var @event = (IEvent)Activator.CreateInstance(type);
|
||||
|
||||
if (@event == null)
|
||||
{
|
||||
OnUnLoadInner(assemblyManifest);
|
||||
continue;
|
||||
}
|
||||
assemblyManifest.EventSystemRegistrar.RegisterSystems(
|
||||
_events,
|
||||
_asyncEvents,
|
||||
_sphereEvents);
|
||||
_assemblyManifests.Add(assemblyManifestId);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载程序集,取消注册该程序集中的所有实体系统
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象,包含程序集的元数据和注册器</param>
|
||||
/// <returns>异步任务</returns>
|
||||
public async FTask OnUnload(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
|
||||
var eventType = @event.EventType();
|
||||
_events.Add(eventType, @event);
|
||||
_assemblyEvents.Add(assemblyIdentity, new EventCache(eventType, @event));
|
||||
}
|
||||
|
||||
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IAsyncEvent)))
|
||||
{
|
||||
OnUnLoadInner(assemblyManifest);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
var @event = (IAsyncEvent)Activator.CreateInstance(type);
|
||||
|
||||
if (@event == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var eventType = @event.EventType();
|
||||
_asyncEvents.Add(eventType, @event);
|
||||
_assemblyAsyncEvents.Add(assemblyIdentity, new EventCache(eventType, @event));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载程序集的内部实现
|
||||
/// 会清理该程序集注册的所有系统
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">程序集清单对象,包含程序集的元数据和注册器</param>
|
||||
private void OnUnLoadInner(AssemblyManifest assemblyManifest)
|
||||
|
||||
private void OnUnLoadInner(long assemblyIdentity)
|
||||
{
|
||||
assemblyManifest.EventSystemRegistrar.UnRegisterSystems(
|
||||
_events,
|
||||
_asyncEvents,
|
||||
_sphereEvents);
|
||||
_assemblyManifests.Remove(assemblyManifest.AssemblyManifestId);
|
||||
if (_assemblyEvents.TryGetValue(assemblyIdentity, out var events))
|
||||
{
|
||||
foreach (var @event in events)
|
||||
{
|
||||
_events.RemoveValue(@event.EnventType, (IEvent)@event.Obj);
|
||||
}
|
||||
|
||||
_assemblyEvents.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
if (_assemblyAsyncEvents.TryGetValue(assemblyIdentity, out var asyncEvents))
|
||||
{
|
||||
foreach (var @event in asyncEvents)
|
||||
{
|
||||
_asyncEvents.RemoveValue(@event.EnventType, (IAsyncEvent)@event.Obj);
|
||||
}
|
||||
|
||||
_assemblyAsyncEvents.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -110,13 +131,13 @@ namespace Fantasy.Event
|
||||
#region Publish
|
||||
|
||||
/// <summary>
|
||||
/// 发布同步事件(struct类型)
|
||||
/// 发布一个值类型的事件数据。
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventData">事件数据类型(值类型)</typeparam>
|
||||
/// <param name="eventData">事件数据</param>
|
||||
/// <typeparam name="TEventData">事件数据类型(值类型)。</typeparam>
|
||||
/// <param name="eventData">事件数据实例。</param>
|
||||
public void Publish<TEventData>(TEventData eventData) where TEventData : struct
|
||||
{
|
||||
if (!_events.TryGetValue(typeof(TEventData).TypeHandle, out var list))
|
||||
if (!_events.TryGetValue(typeof(TEventData), out var list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -125,7 +146,7 @@ namespace Fantasy.Event
|
||||
{
|
||||
try
|
||||
{
|
||||
((IEvent<TEventData>)@event).Invoke(eventData);
|
||||
@event.Invoke(eventData);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -135,14 +156,14 @@ namespace Fantasy.Event
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布同步事件(Entity类型)
|
||||
/// 发布一个继承自 Entity 的事件数据。
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventData">事件数据类型(Entity类型)</typeparam>
|
||||
/// <param name="eventData">事件数据</param>
|
||||
/// <param name="isDisposed">事件处理完成后是否自动销毁Entity</param>
|
||||
/// <typeparam name="TEventData">事件数据类型(继承自 Entity)。</typeparam>
|
||||
/// <param name="eventData">事件数据实例。</param>
|
||||
/// <param name="isDisposed">是否释放事件数据。</param>
|
||||
public void Publish<TEventData>(TEventData eventData, bool isDisposed = true) where TEventData : Entity
|
||||
{
|
||||
if (!_events.TryGetValue(typeof(TEventData).TypeHandle, out var list))
|
||||
if (!_events.TryGetValue(typeof(TEventData), out var list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -151,8 +172,7 @@ namespace Fantasy.Event
|
||||
{
|
||||
try
|
||||
{
|
||||
// 转换为泛型接口,Entity是引用类型但仍避免虚方法调用开销
|
||||
((IEvent<TEventData>)@event).Invoke(eventData);
|
||||
@event.Invoke(eventData);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -165,72 +185,68 @@ namespace Fantasy.Event
|
||||
eventData.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发布一个值类型的事件数据。
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventData">事件数据类型(值类型)。</typeparam>
|
||||
/// <param name="eventData">事件数据实例。</param>
|
||||
/// <returns>表示异步操作的任务。</returns>
|
||||
public async FTask PublishAsync<TEventData>(TEventData eventData) where TEventData : struct
|
||||
{
|
||||
if (!_asyncEvents.TryGetValue(typeof(TEventData), out var list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var tasks = ListPool<FTask>.Create();
|
||||
|
||||
foreach (var @event in list)
|
||||
{
|
||||
tasks.Add(@event.InvokeAsync(eventData));
|
||||
}
|
||||
|
||||
await FTask.WaitAll(tasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发布一个继承自 Entity 的事件数据。
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventData">事件数据类型(继承自 Entity)。</typeparam>
|
||||
/// <param name="eventData">事件数据实例。</param>
|
||||
/// <param name="isDisposed">是否释放事件数据。</param>
|
||||
/// <returns>表示异步操作的任务。</returns>
|
||||
public async FTask PublishAsync<TEventData>(TEventData eventData, bool isDisposed = true) where TEventData : Entity
|
||||
{
|
||||
if (!_asyncEvents.TryGetValue(eventData.GetType(), out var list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var tasks = ListPool<FTask>.Create();
|
||||
|
||||
foreach (var @event in list)
|
||||
{
|
||||
tasks.Add(@event.InvokeAsync(eventData));
|
||||
}
|
||||
|
||||
await FTask.WaitAll(tasks);
|
||||
|
||||
if (isDisposed)
|
||||
{
|
||||
eventData.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布异步事件(struct类型)
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventData">事件数据类型(值类型)</typeparam>
|
||||
/// <param name="eventData">事件数据</param>
|
||||
public async FTask PublishAsync<TEventData>(TEventData eventData) where TEventData : struct
|
||||
{
|
||||
if (!_asyncEvents.TryGetValue(typeof(TEventData).TypeHandle, out var list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var tasks = ListPool<FTask>.Create();
|
||||
|
||||
foreach (var @event in list)
|
||||
{
|
||||
try
|
||||
{
|
||||
tasks.Add(((IAsyncEvent<TEventData>)@event).InvokeAsync(eventData));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
await FTask.WaitAll(tasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布异步事件(Entity类型)
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventData">事件数据类型(Entity类型)</typeparam>
|
||||
/// <param name="eventData">事件数据</param>
|
||||
/// <param name="isDisposed">事件处理完成后是否自动销毁Entity</param>
|
||||
public async FTask PublishAsync<TEventData>(TEventData eventData, bool isDisposed = true) where TEventData : Entity
|
||||
{
|
||||
if (!_asyncEvents.TryGetValue(typeof(TEventData).TypeHandle, out var list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var tasks = ListPool<FTask>.Create();
|
||||
|
||||
foreach (var @event in list)
|
||||
{
|
||||
try
|
||||
{
|
||||
tasks.Add(((IAsyncEvent<TEventData>)@event).InvokeAsync(eventData));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
await FTask.WaitAll(tasks);
|
||||
|
||||
if (isDisposed)
|
||||
{
|
||||
eventData.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_events.Clear();
|
||||
_asyncEvents.Clear();
|
||||
_assemblyEvents.Clear();
|
||||
_assemblyAsyncEvents.Clear();
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,53 +13,35 @@ namespace Fantasy.Event
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Type EventType();
|
||||
/// <summary>
|
||||
/// 时间内部使用的入口
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
void Invoke(object self);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 事件的泛型接口
|
||||
/// 异步事件的接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件数据类型</typeparam>
|
||||
public interface IEvent<in T> : IEvent
|
||||
public interface IAsyncEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件内部使用的入口
|
||||
/// <see cref="IEvent.EventType"/>
|
||||
/// </summary>
|
||||
/// <param name="self">事件数据</param>
|
||||
void Invoke(T self);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步事件的泛型接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件数据类型</typeparam>
|
||||
public interface IAsyncEvent<in T> : IEvent
|
||||
{
|
||||
/// <returns></returns>
|
||||
Type EventType();
|
||||
/// <summary>
|
||||
/// 异步事件调用入口
|
||||
/// <see cref="IEvent.Invoke"/>
|
||||
/// </summary>
|
||||
/// <param name="self">事件数据</param>
|
||||
FTask InvokeAsync(T self);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 领域事件的泛型接口
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件数据类型</typeparam>
|
||||
public interface ISphereEvent<in T> : IEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 领域事件调用入口
|
||||
/// </summary>
|
||||
/// <param name="self">事件数据</param>
|
||||
FTask Invoke(T self);
|
||||
/// <returns></returns>
|
||||
FTask InvokeAsync(object self);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事件的抽象类,要使用事件必须要继承这个抽象接口。
|
||||
/// 同时实现泛型和非泛型接口,支持零装箱调用
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要监听的事件泛型类型</typeparam>
|
||||
public abstract class EventSystem<T> : IEvent<T>
|
||||
public abstract class EventSystem<T> : IEvent
|
||||
{
|
||||
private readonly Type _selfType = typeof(T);
|
||||
/// <summary>
|
||||
@@ -70,22 +52,20 @@ namespace Fantasy.Event
|
||||
{
|
||||
return _selfType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事件调用的方法,要在这个方法里编写事件发生的逻辑
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
protected abstract void Handler(T self);
|
||||
|
||||
/// <summary>
|
||||
/// 泛型调用入口
|
||||
/// <see cref="IEvent.Invoke"/>
|
||||
/// </summary>
|
||||
/// <param name="self">事件数据</param>
|
||||
public void Invoke(T self)
|
||||
/// <returns></returns>
|
||||
public void Invoke(object self)
|
||||
{
|
||||
try
|
||||
{
|
||||
Handler(self);
|
||||
Handler((T) self);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -95,10 +75,9 @@ namespace Fantasy.Event
|
||||
}
|
||||
/// <summary>
|
||||
/// 异步事件的抽象类,要使用事件必须要继承这个抽象接口。
|
||||
/// 同时实现泛型和非泛型接口,支持零装箱调用
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要监听的事件泛型类型</typeparam>
|
||||
public abstract class AsyncEventSystem<T> : IAsyncEvent<T>
|
||||
public abstract class AsyncEventSystem<T> : IAsyncEvent
|
||||
{
|
||||
private readonly Type _selfType = typeof(T);
|
||||
/// <summary>
|
||||
@@ -114,55 +93,15 @@ namespace Fantasy.Event
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
protected abstract FTask Handler(T self);
|
||||
|
||||
/// <summary>
|
||||
/// 泛型异步调用入口
|
||||
/// </summary>
|
||||
/// <param name="self">事件数据</param>
|
||||
public async FTask InvokeAsync(T self)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Handler(self);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"{_selfType.Name} Error {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 领域事件的抽象类,要使用事件必须要继承这个抽象接口。
|
||||
/// 同时实现泛型和非泛型接口,支持零装箱调用
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要监听的事件泛型类型</typeparam>
|
||||
public abstract class SphereEventSystem<T> : ISphereEvent<T>
|
||||
{
|
||||
private readonly Type _selfType = typeof(T);
|
||||
/// <summary>
|
||||
/// <see cref="IEvent.EventType"/>
|
||||
/// <see cref="IEvent.Invoke"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EventType()
|
||||
{
|
||||
return _selfType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事件调用的方法,要在这个方法里编写事件发生的逻辑
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
protected abstract FTask Handler(T self);
|
||||
|
||||
/// <summary>
|
||||
/// 泛型调用入口
|
||||
/// </summary>
|
||||
/// <param name="self">事件数据</param>
|
||||
public async FTask Invoke(T self)
|
||||
public async FTask InvokeAsync(object self)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Handler(self);
|
||||
await Handler((T) self);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Network.Interface;
|
||||
using Fantasy.Pool;
|
||||
using Fantasy.Serialize;
|
||||
|
||||
@@ -18,8 +17,8 @@ namespace Fantasy.Entitas
|
||||
{
|
||||
private int _poolCount;
|
||||
private const int MaxCapacity = ushort.MaxValue;
|
||||
private readonly OneToManyQueue<RuntimeTypeHandle, AMessage> _poolQueue = new OneToManyQueue<RuntimeTypeHandle, AMessage>();
|
||||
private readonly Dictionary<RuntimeTypeHandle, Func<AMessage>> _typeCheckCache = new Dictionary<RuntimeTypeHandle, Func<AMessage>>();
|
||||
private readonly OneToManyQueue<Type, AMessage> _poolQueue = new OneToManyQueue<Type, AMessage>();
|
||||
private readonly Dictionary<Type, Func<AMessage>> _typeCheckCache = new Dictionary<Type, Func<AMessage>>();
|
||||
/// <summary>
|
||||
/// 销毁组件
|
||||
/// </summary>
|
||||
@@ -37,7 +36,7 @@ namespace Fantasy.Entitas
|
||||
/// <returns></returns>
|
||||
public T Rent<T>() where T : AMessage, new()
|
||||
{
|
||||
if (!_poolQueue.TryDequeue(typeof(T).TypeHandle, out var queue))
|
||||
if (!_poolQueue.TryDequeue(typeof(T), out var queue))
|
||||
{
|
||||
var instance = new T();
|
||||
instance.SetScene(Scene);
|
||||
@@ -59,10 +58,9 @@ namespace Fantasy.Entitas
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public AMessage Rent(Type type)
|
||||
{
|
||||
var runtimeTypeHandle = type.TypeHandle;
|
||||
if (!_poolQueue.TryDequeue(runtimeTypeHandle, out var queue))
|
||||
if (!_poolQueue.TryDequeue(type, out var queue))
|
||||
{
|
||||
if (!_typeCheckCache.TryGetValue(runtimeTypeHandle, out var createInstance))
|
||||
if (!_typeCheckCache.TryGetValue(type, out var createInstance))
|
||||
{
|
||||
if (!typeof(AMessage).IsAssignableFrom(type))
|
||||
{
|
||||
@@ -71,7 +69,7 @@ namespace Fantasy.Entitas
|
||||
else
|
||||
{
|
||||
createInstance = CreateInstance.CreateMessage(type);
|
||||
_typeCheckCache[runtimeTypeHandle] = createInstance;
|
||||
_typeCheckCache[type] = createInstance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +106,7 @@ namespace Fantasy.Entitas
|
||||
|
||||
_poolCount++;
|
||||
obj.SetIsPool(false);
|
||||
_poolQueue.Enqueue(obj.GetType().TypeHandle, obj);
|
||||
_poolQueue.Enqueue(obj.GetType(), obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,7 +133,7 @@ namespace Fantasy.Entitas
|
||||
|
||||
_poolCount++;
|
||||
obj.SetIsPool(false);
|
||||
_poolQueue.Enqueue(typeof(T).TypeHandle, obj);
|
||||
_poolQueue.Enqueue(typeof(T), obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#if FANTASY_NET
|
||||
namespace Fantasy.SeparateTable;
|
||||
|
||||
/// <summary>
|
||||
/// 分表存储特性,用于标记需要进行数据库分表存储的实体类型。
|
||||
/// 当实体标记此特性后,该实体将作为父实体的子组件,并在数据库中使用独立的集合进行存储。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 使用场景:
|
||||
/// - 当父实体的某些数据量较大,需要拆分到独立的数据库表中存储时
|
||||
/// - 需要优化数据库查询性能,避免单表数据过大时
|
||||
/// - Source Generator 会自动生成注册代码,无需手动反射处理
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// [SeparateTable(typeof(Player), "PlayerInventory")]
|
||||
/// public class PlayerInventoryEntity : Entity
|
||||
/// {
|
||||
/// // 实体字段...
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
|
||||
public class SeparateTableAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取父实体的类型,指示此实体属于哪个父实体的子集合。
|
||||
/// 通过此属性建立父子实体的逻辑关联关系。
|
||||
/// </summary>
|
||||
public readonly Type RootType;
|
||||
|
||||
/// <summary>
|
||||
/// 获取在数据库中使用的集合名称(表名)。
|
||||
/// 此实体的数据将单独存储到此命名的集合中。
|
||||
/// </summary>
|
||||
public readonly string CollectionName;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 <see cref="SeparateTableAttribute"/> 类的新实例,指定父实体类型和数据库集合名称。
|
||||
/// </summary>
|
||||
/// <param name="rootType">父实体的类型,表示此分表实体从属于哪个父实体。</param>
|
||||
/// <param name="collectionName">在数据库中存储此实体的集合名称(表名)。</param>
|
||||
public SeparateTableAttribute(Type rootType, string collectionName)
|
||||
{
|
||||
RootType = rootType;
|
||||
CollectionName = collectionName;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,221 +0,0 @@
|
||||
#if FANTASY_NET
|
||||
// ReSharper disable SuspiciousTypeConversion.Global
|
||||
|
||||
using Fantasy.Assembly;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
namespace Fantasy.SeparateTable
|
||||
{
|
||||
/// <summary>
|
||||
/// 分表组件,用于管理实体的数据库分表存储功能。
|
||||
/// 负责注册、加载和保存标记了 <see cref="SeparateTableAttribute"/> 的实体数据。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 此组件实现了程序集生命周期接口,会在程序集加载/卸载时自动注册/反注册分表信息。
|
||||
/// 通过 Source Generator 生成的注册器自动管理分表实体的元数据,避免运行时反射。
|
||||
/// </remarks>
|
||||
public sealed class SeparateTableComponent : Entity, IAssemblyLifecycle
|
||||
{
|
||||
/// <summary>
|
||||
/// 存储已加载的程序集清单ID集合,用于追踪哪些程序集的分表信息已注册。
|
||||
/// </summary>
|
||||
private readonly HashSet<long> _assemblyManifests = new();
|
||||
|
||||
/// <summary>
|
||||
/// 分表信息映射表,键为父实体类型,值为该父实体对应的所有分表信息集合。
|
||||
/// 用于快速查询某个实体类型有哪些子实体需要分表存储。
|
||||
/// </summary>
|
||||
private readonly OneToManyHashSet<long, ISeparateTableRegistrar.SeparateTableInfo> _separateTables = new ();
|
||||
|
||||
#region AssemblyManifest
|
||||
|
||||
/// <summary>
|
||||
/// 初始化分表组件,将其注册到程序集生命周期管理器中。
|
||||
/// </summary>
|
||||
/// <returns>返回初始化后的分表组件实例。</returns>
|
||||
internal async FTask<SeparateTableComponent> Initialize()
|
||||
{
|
||||
await AssemblyLifecycle.Add(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当程序集加载时的回调方法,负责注册该程序集中的所有分表信息。
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">加载的程序集清单,包含该程序集的所有元数据。</param>
|
||||
/// <returns>异步任务。</returns>
|
||||
/// <remarks>
|
||||
/// 此方法在线程同步上下文中执行,确保线程安全。
|
||||
/// 如果程序集已被加载过(如热重载场景),会先卸载旧的注册信息再重新注册。
|
||||
/// </remarks>
|
||||
public async FTask OnLoad(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
var assemblyManifestId = assemblyManifest.AssemblyManifestId;
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
// 如果程序集已加载,先卸载旧的
|
||||
if (_assemblyManifests.Contains(assemblyManifestId))
|
||||
{
|
||||
OnUnLoadInner(assemblyManifest);
|
||||
}
|
||||
|
||||
// 从 Source Generator 生成的注册器中获取分表信息
|
||||
var separateTableInfos = assemblyManifest.SeparateTableRegistrar.Register();
|
||||
|
||||
// 将分表信息按父实体类型进行分组注册
|
||||
foreach (var separateTableInfo in separateTableInfos)
|
||||
{
|
||||
_separateTables.Add(TypeHashCache.GetHashCode(separateTableInfo.RootType), separateTableInfo);
|
||||
}
|
||||
|
||||
_assemblyManifests.Add(assemblyManifestId);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当程序集卸载时的回调方法,负责反注册该程序集中的所有分表信息。
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">卸载的程序集清单。</param>
|
||||
/// <returns>异步任务。</returns>
|
||||
/// <remarks>
|
||||
/// 此方法在线程同步上下文中执行,确保线程安全。
|
||||
/// </remarks>
|
||||
public FTask OnUnload(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
var task = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyManifest);
|
||||
task.SetResult();
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载程序集的内部实现,从映射表中移除该程序集的所有分表信息。
|
||||
/// </summary>
|
||||
/// <param name="assemblyManifest">要卸载的程序集清单。</param>
|
||||
private void OnUnLoadInner(AssemblyManifest assemblyManifest)
|
||||
{
|
||||
// 获取该程序集需要反注册的分表信息
|
||||
var separateTableInfos = assemblyManifest.SeparateTableRegistrar.UnRegister();
|
||||
|
||||
// 从映射表中逐个移除
|
||||
foreach (var separateTableInfo in separateTableInfos)
|
||||
{
|
||||
_separateTables.RemoveValue(TypeHashCache.GetHashCode(separateTableInfo.RootType), separateTableInfo);
|
||||
}
|
||||
|
||||
_assemblyManifests.Remove(assemblyManifest.AssemblyManifestId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Collections
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库加载指定实体的所有分表数据,并自动建立父子关系。
|
||||
/// </summary>
|
||||
/// <param name="entity">需要加载分表数据的实体实例。</param>
|
||||
/// <typeparam name="T">实体的泛型类型,必须继承自 <see cref="Entity"/>。</typeparam>
|
||||
/// <returns>异步任务。</returns>
|
||||
/// <remarks>
|
||||
/// 此方法会根据实体类型查找其关联的所有分表配置,逐个从数据库中加载对应的分表实体,
|
||||
/// 并通过 AddComponent 方法将这些分表实体作为组件添加到父实体上,建立父子关系。
|
||||
/// 如果实体类型没有配置分表信息,则直接返回不做任何操作。
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// var player = await db.Query<Player>(playerId);
|
||||
/// await separateTableComponent.Load(player); // 加载玩家的所有分表数据
|
||||
/// </code>
|
||||
/// </example>
|
||||
public async FTask LoadWithSeparateTables<T>(T entity) where T : Entity
|
||||
{
|
||||
// 检查该实体类型是否配置了分表
|
||||
if (!_separateTables.TryGetValue(entity.TypeHashCode, out var separateTables))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var worldDateBase = Scene.World.DataBase;
|
||||
|
||||
// 遍历所有分表配置,逐个加载
|
||||
foreach (var separateTable in separateTables)
|
||||
{
|
||||
// 使用实体ID作为查询条件,从指定的集合中加载分表实体
|
||||
var separateTableEntity = await worldDateBase.QueryNotLock<Entity>(
|
||||
entity.Id, true, separateTable.TableName);
|
||||
|
||||
if (separateTableEntity == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 将加载的分表实体作为组件添加到父实体上
|
||||
entity.AddComponent(separateTableEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将实体及其所有分表组件保存到数据库中。
|
||||
/// </summary>
|
||||
/// <param name="entity">需要保存的实体实例。</param>
|
||||
/// <typeparam name="T">实体的泛型类型,必须继承自 <see cref="Entity"/> 并具有无参构造函数。</typeparam>
|
||||
/// <returns>异步任务。</returns>
|
||||
/// <remarks>
|
||||
/// 此方法会检查实体是否配置了分表信息:
|
||||
/// - 如果没有配置分表,则直接保存实体本身到数据库。
|
||||
/// - 如果配置了分表,会收集实体上所有需要分表存储的组件,统一批量保存到数据库。
|
||||
/// 使用对象池优化列表分配,避免频繁 GC。
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// player.Inventory.Items.Add(newItem);
|
||||
/// await separateTableComponent.Save(player); // 保存玩家及分表数据
|
||||
/// </code>
|
||||
/// </example>
|
||||
public async FTask PersistAggregate<T>(T entity) where T : Entity, new()
|
||||
{
|
||||
// 检查该实体类型是否配置了分表
|
||||
if (!_separateTables.TryGetValue(entity.TypeHashCode, out var separateTables))
|
||||
{
|
||||
// 没有分表配置,直接保存实体
|
||||
await entity.Scene.World.DataBase.Save(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用对象池创建列表,避免 GC
|
||||
using var saveSeparateTables = ListPool<Entity>.Create(entity);
|
||||
|
||||
// 收集所有需要分表保存的组件
|
||||
foreach (var separateTableInfo in separateTables)
|
||||
{
|
||||
var separateTableEntity = entity.GetComponent(separateTableInfo.EntityType);
|
||||
if (separateTableEntity == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
saveSeparateTables.Add(separateTableEntity);
|
||||
}
|
||||
|
||||
// 批量保存实体ID及其所有分表组件
|
||||
await entity.Scene.World.DataBase.Save(entity.Id, saveSeparateTables);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,167 @@
|
||||
// ReSharper disable SuspiciousTypeConversion.Global
|
||||
|
||||
using Fantasy.Assembly;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
#if FANTASY_NET
|
||||
namespace Fantasy.SingleCollection
|
||||
{
|
||||
/// <summary>
|
||||
/// 用于处理Entity下的实体进行数据库分表存储的组件
|
||||
/// </summary>
|
||||
public sealed class SingleCollectionComponent : Entity, IAssembly
|
||||
{
|
||||
private CoroutineLock _coroutineLock;
|
||||
private readonly OneToManyHashSet<Type, string> _collection = new OneToManyHashSet<Type, string>();
|
||||
|
||||
private readonly OneToManyList<long, SingleCollectionInfo> _assemblyCollections =
|
||||
new OneToManyList<long, SingleCollectionInfo>();
|
||||
|
||||
private sealed class SingleCollectionInfo(Type rootType, string collectionName)
|
||||
{
|
||||
public readonly Type RootType = rootType;
|
||||
public readonly string CollectionName = collectionName;
|
||||
}
|
||||
|
||||
internal async FTask<SingleCollectionComponent> Initialize()
|
||||
{
|
||||
var coroutineLockType = HashCodeHelper.ComputeHash64(GetType().FullName);
|
||||
_coroutineLock = Scene.CoroutineLockComponent.Create(coroutineLockType);
|
||||
await AssemblySystem.Register(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
#region Assembly
|
||||
|
||||
public async FTask Load(long assemblyIdentity)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
LoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
public async FTask ReLoad(long assemblyIdentity)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyIdentity);
|
||||
LoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
public async FTask OnUnLoad(long assemblyIdentity)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
private void LoadInner(long assemblyIdentity)
|
||||
{
|
||||
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(ISupportedSingleCollection)))
|
||||
{
|
||||
var customAttributes = type.GetCustomAttributes(typeof(SingleCollectionAttribute), false);
|
||||
if (customAttributes.Length == 0)
|
||||
{
|
||||
Log.Error(
|
||||
$"type {type.FullName} Implemented the interface of ISingleCollection, requiring the implementation of SingleCollectionAttribute");
|
||||
continue;
|
||||
}
|
||||
|
||||
var singleCollectionAttribute = (SingleCollectionAttribute)customAttributes[0];
|
||||
var rootType = singleCollectionAttribute.RootType;
|
||||
var collectionName = singleCollectionAttribute.CollectionName;
|
||||
_collection.Add(rootType, collectionName);
|
||||
_assemblyCollections.Add(assemblyIdentity, new SingleCollectionInfo(rootType, collectionName));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUnLoadInner(long assemblyIdentity)
|
||||
{
|
||||
if (!_assemblyCollections.TryGetValue(assemblyIdentity, out var types))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var singleCollectionInfo in types)
|
||||
{
|
||||
_collection.RemoveValue(singleCollectionInfo.RootType, singleCollectionInfo.CollectionName);
|
||||
}
|
||||
|
||||
_assemblyCollections.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Collections
|
||||
|
||||
/// <summary>
|
||||
/// 通过数据库获取某一个实体类型下所有的分表数据到当前实体下,并且会自动建立父子关系。
|
||||
/// </summary>
|
||||
/// <param name="entity">实体实例</param>
|
||||
/// <typeparam name="T">实体泛型类型</typeparam>
|
||||
public async FTask GetCollections<T>(T entity) where T : Entity, ISingleCollectionRoot
|
||||
{
|
||||
if (!_collection.TryGetValue(typeof(T), out var collections))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var worldDateBase = Scene.World.DataBase;
|
||||
|
||||
using (await _coroutineLock.Wait(entity.Id))
|
||||
{
|
||||
foreach (var collectionName in collections)
|
||||
{
|
||||
var singleCollection = await worldDateBase.QueryNotLock<Entity>(entity.Id, true, collectionName);
|
||||
entity.AddComponent(singleCollection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 存储当前实体下支持分表的组件到数据中,包括存储实体本身。
|
||||
/// </summary>
|
||||
/// <param name="entity">实体实例</param>
|
||||
/// <typeparam name="T">实体泛型类型</typeparam>
|
||||
public async FTask SaveCollections<T>(T entity) where T : Entity, ISingleCollectionRoot
|
||||
{
|
||||
using var collections = ListPool<Entity>.Create();
|
||||
|
||||
foreach (var treeEntity in entity.ForEachSingleCollection)
|
||||
{
|
||||
if (treeEntity is not ISupportedSingleCollection)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
collections.Add(treeEntity);
|
||||
}
|
||||
|
||||
collections.Add(entity);
|
||||
await entity.Scene.World.DataBase.Save(entity.Id, collections);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Serialization;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.IdFactory;
|
||||
using Fantasy.Pool;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
@@ -32,7 +30,15 @@ namespace Fantasy.Entitas
|
||||
public abstract partial class Entity : IEntity
|
||||
{
|
||||
#region Members
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,表示实体是否支持对象池。
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[ProtoIgnore]
|
||||
[IgnoreDataMember]
|
||||
private bool _isPool;
|
||||
/// <summary>
|
||||
/// 实体的Id
|
||||
/// </summary>
|
||||
@@ -80,14 +86,6 @@ namespace Fantasy.Entitas
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public Type Type { get; protected set; }
|
||||
/// <summary>
|
||||
/// 实体的真实Type的HashCode
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public long TypeHashCode { get; private set; }
|
||||
#if FANTASY_NET
|
||||
[BsonElement("t")] [BsonIgnoreIfNull] private EntityList<Entity> _treeDb;
|
||||
[BsonElement("m")] [BsonIgnoreIfNull] private EntityList<Entity> _multiDb;
|
||||
@@ -100,7 +98,6 @@ namespace Fantasy.Entitas
|
||||
/// </summary>
|
||||
/// <typeparam name="T">父实体的泛型类型</typeparam>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T GetParent<T>() where T : Entity, new()
|
||||
{
|
||||
return Parent as T;
|
||||
@@ -141,11 +138,10 @@ namespace Fantasy.Entitas
|
||||
{
|
||||
if (!typeof(Entity).IsAssignableFrom(type))
|
||||
{
|
||||
throw new NotSupportedException($"Type:{type.FullName} must inherit from Entity");
|
||||
throw new NotSupportedException($"{type.FullName} Type:{type.FullName} must inherit from Entity");
|
||||
}
|
||||
|
||||
Entity entity = null;
|
||||
var runtimeTypeHandle = type.TypeHandle;
|
||||
|
||||
if (isPool)
|
||||
{
|
||||
@@ -153,10 +149,10 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!scene.TypeInstance.TryGetValue(runtimeTypeHandle, out var createInstance))
|
||||
if (!scene.TypeInstance.TryGetValue(type, out var createInstance))
|
||||
{
|
||||
createInstance = CreateInstance.CreateIPool(type);
|
||||
scene.TypeInstance[runtimeTypeHandle] = createInstance;
|
||||
scene.TypeInstance[type] = createInstance;
|
||||
}
|
||||
|
||||
entity = (Entity)createInstance();
|
||||
@@ -164,18 +160,17 @@ namespace Fantasy.Entitas
|
||||
|
||||
entity.Scene = scene;
|
||||
entity.Type = type;
|
||||
entity.TypeHashCode = TypeHashCache.GetHashCode(type);
|
||||
entity.SetIsPool(isPool);
|
||||
entity.Id = id;
|
||||
entity.RuntimeId = scene.RuntimeIdFactory.Create(isPool);
|
||||
entity.RuntimeId = scene.RuntimeIdFactory.Create;
|
||||
scene.AddEntity(entity);
|
||||
|
||||
if (isRunEvent)
|
||||
{
|
||||
scene.EntityComponent.Awake(entity);
|
||||
scene.EntityComponent.RegisterUpdate(entity);
|
||||
scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
scene.EntityComponent.RegisterLateUpdate(entity);
|
||||
scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -209,18 +204,17 @@ namespace Fantasy.Entitas
|
||||
var entity = isPool ? scene.EntityPool.Rent<T>() : new T();
|
||||
entity.Scene = scene;
|
||||
entity.Type = typeof(T);
|
||||
entity.TypeHashCode = EntityTypeHashCache<T>.HashCode;
|
||||
entity.SetIsPool(isPool);
|
||||
entity.Id = id;
|
||||
entity.RuntimeId = scene.RuntimeIdFactory.Create(isPool);
|
||||
entity.RuntimeId = scene.RuntimeIdFactory.Create;
|
||||
scene.AddEntity(entity);
|
||||
|
||||
if (isRunEvent)
|
||||
{
|
||||
scene.EntityComponent.Awake(entity);
|
||||
scene.EntityComponent.RegisterUpdate(entity);
|
||||
scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
scene.EntityComponent.RegisterLateUpdate(entity);
|
||||
scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -239,13 +233,13 @@ namespace Fantasy.Entitas
|
||||
/// <returns>返回添加到实体上组件的实例</returns>
|
||||
public T AddComponent<T>(bool isPool = true) where T : Entity, new()
|
||||
{
|
||||
var id = EntitySupportedChecker<T>.IsMulti ? Scene.EntityIdFactory.Create : Id;
|
||||
var id = SupportedMultiEntityChecker<T>.IsSupported ? Scene.EntityIdFactory.Create : Id;
|
||||
var entity = Create<T>(Scene, id, isPool, false);
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.RegisterUpdate(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
Scene.EntityComponent.RegisterLateUpdate(entity);
|
||||
Scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
return entity;
|
||||
}
|
||||
@@ -262,9 +256,9 @@ namespace Fantasy.Entitas
|
||||
var entity = Create<T>(Scene, id, isPool, false);
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.RegisterUpdate(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
Scene.EntityComponent.RegisterLateUpdate(entity);
|
||||
Scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
return entity;
|
||||
}
|
||||
@@ -304,7 +298,13 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
else
|
||||
{
|
||||
var typeHashCode = component.TypeHashCode;
|
||||
#if FANTASY_NET
|
||||
if (component is ISupportedSingleCollection && component.Id != Id)
|
||||
{
|
||||
Log.Error($"component type :{type.FullName} for implementing ISupportedSingleCollection, it is required that the Id must be the same as the parent");
|
||||
}
|
||||
#endif
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(type);;
|
||||
|
||||
if (_tree == null)
|
||||
{
|
||||
@@ -337,6 +337,14 @@ namespace Fantasy.Entitas
|
||||
/// <typeparam name="T">要添加组件的泛型类型</typeparam>
|
||||
public void AddComponent<T>(T component) where T : Entity
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
if (type == typeof(Entity))
|
||||
{
|
||||
Log.Error("Cannot add a generic Entity type as a component. Specify a more specific type.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this == component)
|
||||
{
|
||||
Log.Error("Cannot add oneself to one's own components");
|
||||
@@ -345,18 +353,18 @@ namespace Fantasy.Entitas
|
||||
|
||||
if (component.IsDisposed)
|
||||
{
|
||||
Log.Error($"component is Disposed {typeof(T).FullName}");
|
||||
Log.Error($"component is Disposed {type.FullName}");
|
||||
return;
|
||||
}
|
||||
|
||||
component.Parent?.RemoveComponent(component, false);
|
||||
|
||||
if (EntitySupportedChecker<T>.IsMulti)
|
||||
if (SupportedMultiEntityChecker<T>.IsSupported)
|
||||
{
|
||||
_multi ??= Scene.EntitySortedDictionaryPool.Rent();
|
||||
_multi.Add(component.Id, component);
|
||||
#if FANTASY_NET
|
||||
if (EntitySupportedChecker<T>.IsDataBase)
|
||||
if (SupportedDataBaseChecker<T>.IsSupported)
|
||||
{
|
||||
_multiDb ??= Scene.EntityListPool.Rent();
|
||||
_multiDb.Add(component);
|
||||
@@ -365,7 +373,13 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
else
|
||||
{
|
||||
var typeHashCode = component.TypeHashCode;
|
||||
#if FANTASY_NET
|
||||
if (SupportedSingleCollectionChecker<T>.IsSupported && component.Id != Id)
|
||||
{
|
||||
Log.Error($"component type :{type.FullName} for implementing ISupportedSingleCollection, it is required that the Id must be the same as the parent");
|
||||
}
|
||||
#endif
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(type);
|
||||
|
||||
if (_tree == null)
|
||||
{
|
||||
@@ -373,13 +387,13 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
else if (_tree.ContainsKey(typeHashCode))
|
||||
{
|
||||
Log.Error($"type:{typeof(T).FullName} If you want to add multiple components of the same type, please implement IMultiEntity");
|
||||
Log.Error($"type:{type.FullName} If you want to add multiple components of the same type, please implement IMultiEntity");
|
||||
return;
|
||||
}
|
||||
|
||||
_tree.Add(typeHashCode, component);
|
||||
#if FANTASY_NET
|
||||
if (EntitySupportedChecker<T>.IsDataBase)
|
||||
if (SupportedDataBaseChecker<T>.IsSupported)
|
||||
{
|
||||
_treeDb ??= Scene.EntityListPool.Rent();
|
||||
_treeDb.Add(component);
|
||||
@@ -392,7 +406,7 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个组件到当前实体上
|
||||
/// 添加一个组件到当前实体上
|
||||
/// </summary>
|
||||
/// <param name="type">组件的类型</param>
|
||||
/// <param name="isPool">是否在对象池创建</param>
|
||||
@@ -403,9 +417,9 @@ namespace Fantasy.Entitas
|
||||
var entity = Entity.Create(Scene, type, id, isPool, false);
|
||||
AddComponent(entity);
|
||||
Scene.EntityComponent.Awake(entity);
|
||||
Scene.EntityComponent.RegisterUpdate(entity);
|
||||
Scene.EntityComponent.StartUpdate(entity);
|
||||
#if FANTASY_UNITY
|
||||
Scene.EntityComponent.RegisterLateUpdate(entity);
|
||||
Scene.EntityComponent.StartLateUpdate(entity);
|
||||
#endif
|
||||
return entity;
|
||||
}
|
||||
@@ -419,15 +433,9 @@ namespace Fantasy.Entitas
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool HasComponent<T>() where T : Entity, new()
|
||||
{
|
||||
if (_tree == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _tree.ContainsKey(EntityTypeHashCache<T>.HashCode);
|
||||
return HasComponent(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -435,15 +443,14 @@ namespace Fantasy.Entitas
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool HasComponent(Type type)
|
||||
{
|
||||
if (_tree == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _tree.ContainsKey(TypeHashCache.GetHashCode(type));
|
||||
|
||||
return _tree.ContainsKey(Scene.EntityComponent.GetHashCode(type));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -452,7 +459,6 @@ namespace Fantasy.Entitas
|
||||
/// <param name="id"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool HasComponent<T>(long id) where T : Entity, ISupportedMultiEntity, new()
|
||||
{
|
||||
if (_multi == null)
|
||||
@@ -468,11 +474,10 @@ namespace Fantasy.Entitas
|
||||
#region GetComponent
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上查找一个子实体
|
||||
/// 当前实体上查找一个字实体
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要查找实体泛型类型</typeparam>
|
||||
/// <returns>查找的实体实例</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T GetComponent<T>() where T : Entity, new()
|
||||
{
|
||||
if (_tree == null)
|
||||
@@ -480,15 +485,15 @@ namespace Fantasy.Entitas
|
||||
return null;
|
||||
}
|
||||
|
||||
return _tree.TryGetValue(EntityTypeHashCache<T>.HashCode, out var component) ? (T)component : null;
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(typeof(T));
|
||||
return _tree.TryGetValue(typeHashCode, out var component) ? (T)component : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上查找一个子实体
|
||||
/// 当前实体上查找一个字实体
|
||||
/// </summary>
|
||||
/// <param name="type">要查找实体类型</param>
|
||||
/// <returns>查找的实体实例</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Entity GetComponent(Type type)
|
||||
{
|
||||
if (_tree == null)
|
||||
@@ -496,28 +501,28 @@ namespace Fantasy.Entitas
|
||||
return null;
|
||||
}
|
||||
|
||||
return _tree.GetValueOrDefault(TypeHashCache.GetHashCode(type));
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(type);
|
||||
return _tree.TryGetValue(typeHashCode, out var component) ? component : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上查找一个子实体
|
||||
/// 当前实体上查找一个字实体
|
||||
/// </summary>
|
||||
/// <param name="id">要查找实体的Id</param>
|
||||
/// <typeparam name="T">要查找实体泛型类型</typeparam>
|
||||
/// <returns>查找的实体实例</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T GetComponent<T>(long id) where T : Entity, ISupportedMultiEntity, new()
|
||||
{
|
||||
if (_multi == null)
|
||||
{
|
||||
return null;
|
||||
return default;
|
||||
}
|
||||
|
||||
return _multi.TryGetValue(id, out var entity) ? (T)entity : null;
|
||||
return _multi.TryGetValue(id, out var entity) ? (T)entity : default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前实体上查找一个子实体,如果没有就创建一个新的并添加到当前实体上
|
||||
/// 当前实体上查找一个字实体,如果没有就创建一个新的并添加到当前实体上
|
||||
/// </summary>
|
||||
/// <param name="isPool">是否从对象池创建</param>
|
||||
/// <typeparam name="T">要查找或添加实体泛型类型</typeparam>
|
||||
@@ -539,7 +544,7 @@ namespace Fantasy.Entitas
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public void RemoveComponent<T>(bool isDispose = true) where T : Entity, new()
|
||||
{
|
||||
if (EntitySupportedChecker<T>.IsMulti)
|
||||
if (SupportedMultiEntityChecker<T>.IsSupported)
|
||||
{
|
||||
throw new NotSupportedException($"{typeof(T).FullName} message:Cannot delete components that implement the ISupportedMultiEntity interface");
|
||||
}
|
||||
@@ -549,13 +554,14 @@ namespace Fantasy.Entitas
|
||||
return;
|
||||
}
|
||||
|
||||
var typeHashCode = EntityTypeHashCache<T>.HashCode;
|
||||
var type = typeof(T);
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(type);
|
||||
if (!_tree.TryGetValue(typeHashCode, out var component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if FANTASY_NET
|
||||
if (_treeDb != null && EntitySupportedChecker<T>.IsDataBase)
|
||||
if (_treeDb != null && SupportedDataBaseChecker<T>.IsSupported)
|
||||
{
|
||||
_treeDb.Remove(component);
|
||||
|
||||
@@ -598,7 +604,7 @@ namespace Fantasy.Entitas
|
||||
return;
|
||||
}
|
||||
#if FANTASY_NET
|
||||
if (_multiDb != null && EntitySupportedChecker<T>.IsDataBase)
|
||||
if (SupportedDataBaseChecker<T>.IsSupported)
|
||||
{
|
||||
_multiDb.Remove(component);
|
||||
if (_multiDb.Count == 0)
|
||||
@@ -662,7 +668,7 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
else if (_tree != null)
|
||||
{
|
||||
var typeHashCode = component.TypeHashCode;
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(component.Type);
|
||||
if (!_tree.ContainsKey(typeHashCode))
|
||||
{
|
||||
return;
|
||||
@@ -706,8 +712,14 @@ namespace Fantasy.Entitas
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (EntitySupportedChecker<T>.IsMulti)
|
||||
|
||||
if (typeof(T) == typeof(Entity))
|
||||
{
|
||||
Log.Error("Cannot remove a generic Entity type as a component. Specify a more specific type.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SupportedMultiEntityChecker<T>.IsSupported)
|
||||
{
|
||||
if (_multi != null)
|
||||
{
|
||||
@@ -716,7 +728,7 @@ namespace Fantasy.Entitas
|
||||
return;
|
||||
}
|
||||
#if FANTASY_NET
|
||||
if (EntitySupportedChecker<T>.IsDataBase)
|
||||
if (SupportedDataBaseChecker<T>.IsSupported)
|
||||
{
|
||||
_multiDb.Remove(component);
|
||||
if (_multiDb.Count == 0)
|
||||
@@ -736,13 +748,13 @@ namespace Fantasy.Entitas
|
||||
}
|
||||
else if (_tree != null)
|
||||
{
|
||||
var typeHashCode = EntityTypeHashCache<T>.HashCode;
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(typeof(T));
|
||||
if (!_tree.ContainsKey(typeHashCode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if FANTASY_NET
|
||||
if (_treeDb != null && EntitySupportedChecker<T>.IsDataBase)
|
||||
if (_treeDb != null && SupportedDataBaseChecker<T>.IsSupported)
|
||||
{
|
||||
_treeDb.Remove(component);
|
||||
|
||||
@@ -789,7 +801,7 @@ namespace Fantasy.Entitas
|
||||
{
|
||||
Scene = scene;
|
||||
Type ??= GetType();
|
||||
RuntimeId = Scene.RuntimeIdFactory.Create(false);
|
||||
RuntimeId = Scene.RuntimeIdFactory.Create;
|
||||
if (resetId)
|
||||
{
|
||||
Id = RuntimeId;
|
||||
@@ -802,7 +814,8 @@ namespace Fantasy.Entitas
|
||||
{
|
||||
entity.Parent = this;
|
||||
entity.Type = entity.GetType();
|
||||
_tree.Add(TypeHashCache.GetHashCode(entity.Type), entity);
|
||||
var typeHashCode = Scene.EntityComponent.GetHashCode(entity.Type);
|
||||
_tree.Add(typeHashCode, entity);
|
||||
entity.Deserialize(scene, resetId);
|
||||
}
|
||||
}
|
||||
@@ -835,7 +848,66 @@ namespace Fantasy.Entitas
|
||||
#endregion
|
||||
|
||||
#region ForEach
|
||||
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// 查询当前实体下支持数据库分表存储实体
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public IEnumerable<Entity> ForEachSingleCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var (_, treeEntity) in _tree)
|
||||
{
|
||||
if (treeEntity is not ISupportedSingleCollection)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return treeEntity;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询当前实体下支持传送实体
|
||||
/// </summary>
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
public IEnumerable<Entity> ForEachTransfer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_tree != null)
|
||||
{
|
||||
foreach (var (_, treeEntity) in _tree)
|
||||
{
|
||||
if (treeEntity is ISupportedTransfer)
|
||||
{
|
||||
yield return treeEntity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_multiDb != null)
|
||||
{
|
||||
foreach (var treeEntity in _multiDb)
|
||||
{
|
||||
if (treeEntity is not ISupportedTransfer)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return treeEntity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 查询当前实体下的实现了ISupportedMultiEntity接口的实体
|
||||
/// </summary>
|
||||
@@ -924,6 +996,11 @@ namespace Fantasy.Entitas
|
||||
#if FANTASY_NET
|
||||
if (_treeDb != null)
|
||||
{
|
||||
foreach (var entity in _treeDb)
|
||||
{
|
||||
entity.Dispose();
|
||||
}
|
||||
|
||||
_treeDb.Clear();
|
||||
scene.EntityListPool.Return(_treeDb);
|
||||
_treeDb = null;
|
||||
@@ -931,6 +1008,11 @@ namespace Fantasy.Entitas
|
||||
|
||||
if (_multiDb != null)
|
||||
{
|
||||
foreach (var entity in _multiDb)
|
||||
{
|
||||
entity.Dispose();
|
||||
}
|
||||
|
||||
_multiDb.Clear();
|
||||
scene.EntityListPool.Return(_multiDb);
|
||||
_multiDb = null;
|
||||
@@ -948,7 +1030,12 @@ namespace Fantasy.Entitas
|
||||
Scene = null;
|
||||
Parent = null;
|
||||
scene.RemoveEntity(runTimeId);
|
||||
scene.EntityPool.Return(Type, this);
|
||||
|
||||
if (IsPool())
|
||||
{
|
||||
scene.EntityPool.Return(Type, this);
|
||||
}
|
||||
|
||||
Type = null;
|
||||
}
|
||||
|
||||
@@ -960,27 +1047,20 @@ namespace Fantasy.Entitas
|
||||
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsPool()
|
||||
{
|
||||
return IdFactoryHelper.RuntimeIdTool.GetIsPool(RuntimeId);
|
||||
return _isPool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
|
||||
/// </summary>
|
||||
/// <param name="isPool"></param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetIsPool(bool isPool) { }
|
||||
public void SetIsPool(bool isPool)
|
||||
{
|
||||
_isPool = isPool;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entity的泛型抽象类,如果使用泛型Entity必须继承这个接口才可以使用
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract partial class Entity<T> : Entity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,6 @@ namespace Fantasy.Entitas
|
||||
_runTimeId = t.RuntimeId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取实体引用
|
||||
/// </summary>
|
||||
public T Value => _entity?.RuntimeId != _runTimeId ? null : _entity;
|
||||
|
||||
/// <summary>
|
||||
/// 将一个实体转换为EntityReference
|
||||
/// </summary>
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 支持再一个组件里添加多个同类型组件
|
||||
/// </summary>
|
||||
public interface ISupportedMultiEntity : IDisposable
|
||||
{
|
||||
}
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// Entity支持数据库
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public interface ISupportedDataBase
|
||||
{
|
||||
}
|
||||
|
||||
// Entity支持分表存储、保存到数据库的时候不会跟随父组件保存在一个表里、会单独保存在一个表里
|
||||
// 需要配合SeparateTableAttribute一起使用、如在Entity类头部定义SeparateTableAttribute(typeOf(Unit), "UnitBag")
|
||||
// SeparateTableAttribute用来定义这个Entity是属于哪个Entity的子集以及表名
|
||||
/// <summary>
|
||||
/// 定义实体支持分表存储的接口。当实体需要单独存储在一个数据库表中,并且在保存到数据库时不会与父实体一起保存在同一个表中时,应实现此接口。
|
||||
/// </summary>
|
||||
public interface ISupportedSeparateTable
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entity支持传送
|
||||
/// </summary>
|
||||
public interface ISupportedTransfer
|
||||
{
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// Entity保存到数据库的时候会根据子组件设置分表存储特性分表存储在不同的数据库表中
|
||||
// /// </summary>
|
||||
// public interface ISeparateTableRoot
|
||||
// {
|
||||
// }
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体接口支持性的编译时检查器。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要检查的实体类型,必须继承自 <see cref="Entity"/></typeparam>
|
||||
/// <remarks>
|
||||
/// 性能优势:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>静态字段在每个具体类型实例化时仅初始化一次</description></item>
|
||||
/// <item><description>JIT编译器会将静态布尔值内联为常量,实现分支消除优化</description></item>
|
||||
/// <item><description>避免重复的运行时类型检查开销</description></item>
|
||||
/// <item><description>多个相关检查集中在同一个静态类,提高CPU缓存局部性</description></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public static class EntitySupportedChecker<T> where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取实体类型是否实现了 <see cref="ISupportedMultiEntity"/> 接口。
|
||||
/// 实现该接口的实体支持在父实体中添加多个同类型的组件实例。
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// 如果实体类型实现了 <see cref="ISupportedMultiEntity"/> 接口,则为 <c>true</c>;否则为 <c>false</c>。
|
||||
/// </value>
|
||||
public static bool IsMulti { get; }
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// 获取实体类型是否实现了 <see cref="ISupportedDataBase"/> 接口。
|
||||
/// 实现该接口的实体支持数据库持久化存储。
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// 如果实体类型实现了 <see cref="ISupportedDataBase"/> 接口,则为 <c>true</c>;否则为 <c>false</c>。
|
||||
/// </value>
|
||||
public static bool IsDataBase { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取实体类型是否实现了 <see cref="ISupportedTransfer"/> 接口。
|
||||
/// 实现该接口的实体支持跨进程传输(如服务器间传送)。
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// 如果实体类型实现了 <see cref="ISupportedTransfer"/> 接口,则为 <c>true</c>;否则为 <c>false</c>。
|
||||
/// </value>
|
||||
public static bool IsTransfer { get; }
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 静态构造函数,在首次访问该泛型类型时执行一次,缓存所有接口检查结果。
|
||||
/// </summary>
|
||||
static EntitySupportedChecker()
|
||||
{
|
||||
var type = typeof(T);
|
||||
IsMulti = typeof(ISupportedMultiEntity).IsAssignableFrom(type);
|
||||
#if FANTASY_NET
|
||||
IsDataBase = typeof(ISupportedDataBase).IsAssignableFrom(type);
|
||||
IsTransfer = typeof(ISupportedTransfer).IsAssignableFrom(type);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity保存到数据库的时候会根据子组件设置分离存储特性分表存储在不同的集合表中
|
||||
/// </summary>
|
||||
public interface ISingleCollectionRoot { }
|
||||
public static class SingleCollectionRootChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SingleCollectionRootChecker()
|
||||
{
|
||||
IsSupported = typeof(ISingleCollectionRoot).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity支持数据库
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public interface ISupportedDataBase { }
|
||||
|
||||
public static class SupportedDataBaseChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SupportedDataBaseChecker()
|
||||
{
|
||||
IsSupported = typeof(ISupportedDataBase).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 支持再一个组件里添加多个同类型组件
|
||||
/// </summary>
|
||||
public interface ISupportedMultiEntity : IDisposable { }
|
||||
|
||||
public static class SupportedMultiEntityChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SupportedMultiEntityChecker()
|
||||
{
|
||||
IsSupported = typeof(ISupportedMultiEntity).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
// Entity是单一集合、保存到数据库的时候不会跟随父组件保存在一个集合里、会单独保存在一个集合里
|
||||
// 需要配合SingleCollectionAttribute一起使用、如在Entity类头部定义SingleCollectionAttribute(typeOf(Unit))
|
||||
// SingleCollectionAttribute用来定义这个Entity是属于哪个Entity的子集
|
||||
/// <summary>
|
||||
/// 定义实体支持单一集合存储的接口。当实体需要单独存储在一个集合中,并且在保存到数据库时不会与父组件一起保存在同一个集合中时,应实现此接口。
|
||||
/// </summary>
|
||||
public interface ISupportedSingleCollection { }
|
||||
public static class SupportedSingleCollectionChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SupportedSingleCollectionChecker()
|
||||
{
|
||||
IsSupported = typeof(ISupportedSingleCollection).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 表示用于指定实体的单一集合存储属性。此属性用于配合 <see cref="ISupportedSingleCollection"/> 接口使用,
|
||||
/// 用于定义实体属于哪个父实体的子集合,以及在数据库中使用的集合名称。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
|
||||
public class SingleCollectionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取父实体的类型,指示此实体是属于哪个父实体的子集合。
|
||||
/// </summary>
|
||||
public readonly Type RootType;
|
||||
/// <summary>
|
||||
/// 获取在数据库中使用的集合名称。
|
||||
/// </summary>
|
||||
public readonly string CollectionName;
|
||||
/// <summary>
|
||||
/// 初始化 <see cref="SingleCollectionAttribute"/> 类的新实例,指定父实体类型和集合名称。
|
||||
/// </summary>
|
||||
/// <param name="rootType">父实体的类型。</param>
|
||||
/// <param name="collectionName">在数据库中使用的集合名称。</param>
|
||||
public SingleCollectionAttribute(Type rootType, string collectionName)
|
||||
{
|
||||
RootType = rootType;
|
||||
CollectionName = collectionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#if FANTASY_NET
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity支持传送
|
||||
/// </summary>
|
||||
public interface ISupportedTransfer { }
|
||||
public static class SupportedTransferChecker<T> where T : Entity
|
||||
{
|
||||
public static bool IsSupported { get; }
|
||||
|
||||
static SupportedTransferChecker()
|
||||
{
|
||||
IsSupported = typeof(ISupportedTransfer).IsAssignableFrom(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,100 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Fantasy.Helper;
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体类型哈希码缓存器。
|
||||
/// 提供两种缓存机制:
|
||||
/// 1. 泛型静态字段缓存(用于泛型方法,零开销)
|
||||
/// 2. 全局字典缓存(用于非泛型方法,运行时查找)
|
||||
/// </summary>
|
||||
public static class TypeHashCache
|
||||
{
|
||||
/// <summary>
|
||||
/// 全局类型哈希码缓存字典,用于非泛型方法的运行时查找。
|
||||
/// 使用 ConcurrentDictionary 保证线程安全。
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<RuntimeTypeHandle, long> RuntimeCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定实体类型的哈希码(运行时查找)。
|
||||
/// 首次访问时计算并缓存,后续访问直接返回缓存值。
|
||||
/// </summary>
|
||||
/// <param name="type">实体类型</param>
|
||||
/// <returns>实体类型的哈希码</returns>
|
||||
/// <remarks>
|
||||
/// 使用场景:非泛型方法中使用,如 GetComponent(Type type)
|
||||
/// 性能:首次访问需要计算并插入字典,后续访问为 O(1) 字典查找
|
||||
/// </remarks>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long GetHashCode(Type type)
|
||||
{
|
||||
return RuntimeCache.GetOrAdd(type.TypeHandle,
|
||||
static (_, fullName) => HashCodeHelper.ComputeHash64(fullName),
|
||||
type.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预热缓存,批量计算并缓存一组类型的哈希码。
|
||||
/// </summary>
|
||||
/// <param name="types">要预热的类型集合</param>
|
||||
/// <remarks>
|
||||
/// 建议在程序初始化时调用,避免运行时首次查找的计算开销。
|
||||
/// </remarks>
|
||||
public static void Warmup(IEnumerable<Type> types)
|
||||
{
|
||||
foreach (var type in types)
|
||||
{
|
||||
if (typeof(Entity).IsAssignableFrom(type))
|
||||
{
|
||||
GetHashCode(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有缓存(仅用于热重载场景)。
|
||||
/// </summary>
|
||||
internal static void Clear()
|
||||
{
|
||||
RuntimeCache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实体类型哈希码泛型缓存器。
|
||||
/// 通过泛型静态字段缓存每个实体类型的哈希码,实现零开销的类型哈希码访问。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要缓存哈希码的实体类型,必须继承自 <see cref="Entity"/></typeparam>
|
||||
/// <remarks>
|
||||
/// 性能优势:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>每个类型的哈希码只计算一次,后续访问直接返回缓存值</description></item>
|
||||
/// <item><description>JIT编译器会将静态字段访问内联为常量</description></item>
|
||||
/// <item><description>无需字典查找,性能远超运行时缓存</description></item>
|
||||
/// <item><description>适合在泛型方法中使用,如 GetComponent<T>()</description></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
internal static class EntityTypeHashCache<T> where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取实体类型 <typeparamref name="T"/> 的哈希码。
|
||||
/// 该值在首次访问时计算并缓存,后续访问直接返回缓存值。
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// 实体类型的哈希码,用于在 Entity 的 _tree 字典中快速查找组件。
|
||||
/// </value>
|
||||
public static long HashCode { get; }
|
||||
|
||||
static EntityTypeHashCache()
|
||||
{
|
||||
// 直接调用非泛型版本,复用计算逻辑并共享缓存
|
||||
HashCode = TypeHashCache.GetHashCode(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,7 @@ using Fantasy.Async;
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的Awake事件的接口
|
||||
/// </summary>
|
||||
public interface IAwakeSystem : IEntitySystem { }
|
||||
internal interface IAwakeSystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// 实体的Awake事件的抽象接口
|
||||
/// </summary>
|
||||
@@ -17,7 +14,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntityType() => typeof(T);
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 如果需要自定义组件事件系统,请继承此接口。
|
||||
/// 这个接口内部使用。不对外开放。
|
||||
/// </summary>
|
||||
internal interface ICustomEntitySystem
|
||||
internal interface ICustomEntitiesSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
@@ -18,7 +18,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Type EntityType();
|
||||
Type EntitiesType();
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发事件方法
|
||||
/// </summary>
|
||||
@@ -31,7 +31,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 如果需要自定义组件事件系统,请继承此抽象类。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class CustomSystem<T> : ICustomEntitySystem where T : Entity
|
||||
public abstract class CustomSystem<T> : ICustomEntitiesSystem where T : Entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 这个1表示是一个自定义事件类型,执行这个事件是时候需要用到这个1.
|
||||
@@ -46,7 +46,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract Type EntityType();
|
||||
public abstract Type EntitiesType();
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发Awake的方法。
|
||||
/// </summary>
|
||||
@@ -3,10 +3,7 @@ using Fantasy.Async;
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的反序列化事件的接口
|
||||
/// </summary>
|
||||
public interface IDeserializeSystem : IEntitySystem { }
|
||||
internal interface IDeserializeSystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// 实体的反序列化事件的抽象接口
|
||||
/// </summary>
|
||||
@@ -17,7 +14,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntityType() => typeof(T);
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
|
||||
@@ -3,10 +3,7 @@ using Fantasy.Async;
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体销毁事件的接口
|
||||
/// </summary>
|
||||
public interface IDestroySystem : IEntitySystem { }
|
||||
internal interface IDestroySystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// 实体销毁事件的抽象接口
|
||||
/// </summary>
|
||||
@@ -17,7 +14,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntityType() => typeof(T);
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
|
||||
@@ -6,13 +6,13 @@ namespace Fantasy.Entitas.Interface
|
||||
/// <summary>
|
||||
/// ECS事件系统的核心接口,任何事件都是要继承这个接口
|
||||
/// </summary>
|
||||
public interface IEntitySystem
|
||||
public interface IEntitiesSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Type EntityType();
|
||||
Type EntitiesType();
|
||||
/// <summary>
|
||||
/// 框架内部调用的触发事件方法
|
||||
/// </summary>
|
||||
@@ -3,7 +3,7 @@ using System;
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
public interface ILateUpdateSystem : IEntitySystem { }
|
||||
internal interface ILateUpdateSystem : IEntitiesSystem { }
|
||||
|
||||
/// <summary>
|
||||
/// 实体的LateUpdate事件的抽象接口
|
||||
@@ -15,7 +15,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntityType() => typeof(T);
|
||||
public Type EntitiesType() => typeof(T);
|
||||
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
|
||||
@@ -2,10 +2,7 @@ using System;
|
||||
|
||||
namespace Fantasy.Entitas.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Update事件的接口
|
||||
/// </summary>
|
||||
public interface IUpdateSystem : IEntitySystem { }
|
||||
internal interface IUpdateSystem : IEntitiesSystem { }
|
||||
/// <summary>
|
||||
/// Update事件的抽象接口
|
||||
/// </summary>
|
||||
@@ -16,7 +13,7 @@ namespace Fantasy.Entitas.Interface
|
||||
/// 实体的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type EntityType() => typeof(T);
|
||||
public Type EntitiesType() => typeof(T);
|
||||
/// <summary>
|
||||
/// 事件的抽象方法,需要自己实现这个方法
|
||||
/// </summary>
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Fantasy.Helper
|
||||
/// <summary>
|
||||
/// 根据时间获取时间戳
|
||||
/// </summary>
|
||||
public static long Transition(this DateTime dateTime)
|
||||
public static long Transition(DateTime dateTime)
|
||||
{
|
||||
return (dateTime.ToUniversalTime().Ticks - Epoch) / 10000;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace Fantasy.Helper
|
||||
/// <summary>
|
||||
/// 根据时间获取 时间戳
|
||||
/// </summary>
|
||||
public static long TransitionToSeconds(this DateTime dateTime)
|
||||
public static long TransitionToSeconds(DateTime dateTime)
|
||||
{
|
||||
return (dateTime.ToUniversalTime().Ticks - Epoch) / 10000000;
|
||||
}
|
||||
|
||||
@@ -114,18 +114,6 @@ namespace Fantasy.IdFactory
|
||||
|
||||
public sealed class EntityIdFactoryTool : IIdFactoryTool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool GetIsPool(ref long entityId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool GetIsPool(long runtimeId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(ref long entityId)
|
||||
{
|
||||
@@ -133,12 +121,6 @@ namespace Fantasy.IdFactory
|
||||
return (uint)(result & EntityIdStruct.MaskTime);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(long entityId)
|
||||
{
|
||||
return GetTime(ref entityId);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(ref long entityId)
|
||||
{
|
||||
@@ -146,20 +128,9 @@ namespace Fantasy.IdFactory
|
||||
return (uint)(result & EntityIdStruct.MaskSceneId);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(long entityId)
|
||||
{
|
||||
return GetSceneId(ref entityId);
|
||||
}
|
||||
|
||||
public byte GetWorldId(ref long entityId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public byte GetWorldId(long entityId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,30 +12,27 @@ namespace Fantasy.IdFactory
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct RuntimeIdStruct
|
||||
{
|
||||
// RuntimeId: IsPool(1) + time(23) + SceneId(16) + sequence(24) = 64 bits
|
||||
// +------------------+-------------------+-----------------------------+--------------------------------------+
|
||||
// | IsPool(1) 对象池 | time(23) 最大60天 | SceneId(16) 最多65535个Scene | sequence(24) 每秒每个进程能生产16777215个
|
||||
// +------------------+-------------------+-----------------------------+--------------------------------------+
|
||||
// RuntimeId:23 + 8 + 8 + 25 = 64
|
||||
// +-------------------+-----------------------------+--------------------------------------+
|
||||
// | time(23) 最大60天 | SceneId(16) 最多65535个Scene | sequence(25) 每秒每个进程能生产33554431个
|
||||
// +-------------------+-----------------------------+--------------------------------------+
|
||||
public uint Time { get; private set; }
|
||||
public uint SceneId { get; private set; }
|
||||
public uint Sequence { get; private set; }
|
||||
public bool IsPool { get; private set; }
|
||||
|
||||
public const uint MaskSequence = 0xFFFFFF; // 24位
|
||||
public const uint MaskSceneId = 0xFFFF; // 16位
|
||||
public const uint MaskTime = 0x7FFFFF; // 23位 (最高位留给 IsPool)
|
||||
|
||||
public const uint MaskSequence = 0x1FFFFFF;
|
||||
public const uint MaskSceneId = 0xFFFF;
|
||||
public const uint MaskTime = 0x7FFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// RuntimeIdStruct(如果超过下面参数的设定该ID会失效)。
|
||||
/// </summary>
|
||||
/// <param name="isPool"></param>
|
||||
/// <param name="time">time不能超过8388607</param>
|
||||
/// <param name="sceneId">sceneId不能超过65535</param>
|
||||
/// <param name="sequence">sequence不能超过16777215</param>
|
||||
public RuntimeIdStruct(bool isPool, uint time, uint sceneId, uint sequence)
|
||||
/// <param name="sequence">sequence不能超过33554431</param>
|
||||
public RuntimeIdStruct(uint time, uint sceneId, uint sequence)
|
||||
{
|
||||
// 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。
|
||||
IsPool = isPool;
|
||||
Time = time;
|
||||
SceneId = sceneId;
|
||||
Sequence = sequence;
|
||||
@@ -43,10 +40,9 @@ namespace Fantasy.IdFactory
|
||||
|
||||
public static implicit operator long(RuntimeIdStruct runtimeIdStruct)
|
||||
{
|
||||
ulong result = runtimeIdStruct.Sequence; // 低24位: sequence
|
||||
result |= (ulong)runtimeIdStruct.SceneId << 24; // 第24-39位: sceneId
|
||||
result |= (ulong)runtimeIdStruct.Time << 40; // 第40-62位: time
|
||||
result |= (runtimeIdStruct.IsPool ? 1UL : 0UL) << 63; // 最高位63: isPool
|
||||
ulong result = runtimeIdStruct.Sequence;
|
||||
result |= (ulong)runtimeIdStruct.SceneId << 25;
|
||||
result |= (ulong)runtimeIdStruct.Time << 41;
|
||||
return (long)result;
|
||||
}
|
||||
|
||||
@@ -55,11 +51,12 @@ namespace Fantasy.IdFactory
|
||||
var result = (ulong)runtimeId;
|
||||
var runtimeIdStruct = new RuntimeIdStruct
|
||||
{
|
||||
Sequence = (uint)(result & MaskSequence), // 低24位: sequence
|
||||
SceneId = (uint)((result >> 24) & MaskSceneId), // 第24-39位: sceneId
|
||||
Time = (uint)((result >> 40) & MaskTime), // 第40-62位: time
|
||||
IsPool = ((result >> 63) & 1) == 1 // 最高位63: isPool
|
||||
Sequence = (uint)(result & MaskSequence)
|
||||
};
|
||||
result >>= 25;
|
||||
runtimeIdStruct.SceneId = (byte)(result & MaskSceneId);
|
||||
result >>= 16;
|
||||
runtimeIdStruct.Time = (uint)(result & MaskTime);
|
||||
return runtimeIdStruct;
|
||||
}
|
||||
}
|
||||
@@ -94,100 +91,45 @@ namespace Fantasy.IdFactory
|
||||
}
|
||||
}
|
||||
|
||||
public long Create(bool isPool)
|
||||
public long Create
|
||||
{
|
||||
var time = (uint)((TimeHelper.Now - _epochNow) / 1000);
|
||||
|
||||
if (time > _lastTime)
|
||||
get
|
||||
{
|
||||
_lastTime = time;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
else if (++_lastSequence > RuntimeIdStruct.MaskSequence - 1)
|
||||
{
|
||||
_lastTime++;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
var time = (uint)((TimeHelper.Now - _epochNow) / 1000);
|
||||
|
||||
if (time > _lastTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
else if (++_lastSequence > RuntimeIdStruct.MaskSequence - 1)
|
||||
{
|
||||
_lastTime++;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
|
||||
return new RuntimeIdStruct(isPool, time, _sceneId, _lastSequence);
|
||||
return new RuntimeIdStruct(time, _sceneId, _lastSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RuntimeIdFactoryTool : IIdFactoryTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 IsPool 标志
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool GetIsPool(long runtimeId)
|
||||
{
|
||||
return GetIsPool(ref runtimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 IsPool 标志
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool GetIsPool(ref long runtimeId)
|
||||
{
|
||||
return (((ulong)runtimeId >> 63) & 1) == 1; // 最高位
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的时间部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 40; // 右移40位到第40-62位
|
||||
var result = (ulong)runtimeId >> 41;
|
||||
return (uint)(result & RuntimeIdStruct.MaskTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的时间部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(long runtimeId)
|
||||
{
|
||||
return GetTime(ref runtimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 SceneId 部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 24; // 右移24位到第24-39位
|
||||
return (uint)(result & RuntimeIdStruct.MaskSceneId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 SceneId 部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(long runtimeId)
|
||||
{
|
||||
return GetSceneId(ref runtimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 Sequence 部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSequence(ref long runtimeId)
|
||||
{
|
||||
return (uint)((ulong)runtimeId & RuntimeIdStruct.MaskSequence); // 低24位
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte GetWorldId(ref long entityId)
|
||||
public uint GetSceneId(ref long runtimeId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var result = (ulong)runtimeId >> 25;
|
||||
return (uint)(result & RuntimeIdStruct.MaskSceneId);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte GetWorldId(long entityId)
|
||||
public byte GetWorldId(ref long entityId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -118,17 +118,17 @@ namespace Fantasy.IdFactory
|
||||
}
|
||||
}
|
||||
|
||||
internal static long RuntimeId(bool isPool, uint time, uint sceneId, byte wordId, uint sequence)
|
||||
internal static long RuntimeId(uint time, uint sceneId, byte wordId, uint sequence)
|
||||
{
|
||||
switch (_idFactoryType)
|
||||
{
|
||||
case IdFactoryType.Default:
|
||||
{
|
||||
return new RuntimeIdStruct(isPool, time, sceneId, sequence);
|
||||
return new RuntimeIdStruct(time, sceneId, sequence);
|
||||
}
|
||||
case IdFactoryType.World:
|
||||
{
|
||||
return new WorldRuntimeIdStruct(isPool, time, sceneId, wordId, sequence);
|
||||
return new WorldRuntimeIdStruct(time, sceneId, wordId, sequence);
|
||||
}
|
||||
default:
|
||||
{
|
||||
|
||||
@@ -19,6 +19,6 @@ namespace Fantasy.IdFactory
|
||||
/// <summary>
|
||||
/// 创建一个新的Id
|
||||
/// </summary>
|
||||
public long Create(bool isPool);
|
||||
public long Create { get; }
|
||||
}
|
||||
}
|
||||
@@ -5,18 +5,6 @@ namespace Fantasy.IdFactory
|
||||
/// </summary>
|
||||
public interface IIdFactoryTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 IsPool 标志
|
||||
/// </summary>
|
||||
/// <param name="runtimeId"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetIsPool(ref long runtimeId);
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 IsPool 标志
|
||||
/// </summary>
|
||||
/// <param name="runtimeId"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetIsPool(long runtimeId);
|
||||
/// <summary>
|
||||
/// 获得创建时间
|
||||
/// </summary>
|
||||
@@ -24,34 +12,16 @@ namespace Fantasy.IdFactory
|
||||
/// <returns></returns>
|
||||
public uint GetTime(ref long entityId);
|
||||
/// <summary>
|
||||
/// 获得创建时间
|
||||
/// </summary>
|
||||
/// <param name="entityId"></param>
|
||||
/// <returns></returns>
|
||||
public uint GetTime(long entityId);
|
||||
/// <summary>
|
||||
/// 获得SceneId
|
||||
/// </summary>
|
||||
/// <param name="entityId"></param>
|
||||
/// <returns></returns>
|
||||
public uint GetSceneId(ref long entityId);
|
||||
/// <summary>
|
||||
/// 获得SceneId
|
||||
/// </summary>
|
||||
/// <param name="entityId"></param>
|
||||
/// <returns></returns>
|
||||
public uint GetSceneId(long entityId);
|
||||
/// <summary>
|
||||
/// 获得WorldId
|
||||
/// </summary>
|
||||
/// <param name="entityId"></param>
|
||||
/// <returns></returns>
|
||||
public byte GetWorldId(ref long entityId);
|
||||
/// <summary>
|
||||
/// 获得WorldId
|
||||
/// </summary>
|
||||
/// <param name="entityId"></param>
|
||||
/// <returns></returns>
|
||||
public byte GetWorldId(long entityId);
|
||||
}
|
||||
}
|
||||
@@ -127,18 +127,6 @@ namespace Fantasy.IdFactory
|
||||
|
||||
public sealed class WorldEntityIdFactoryTool : IIdFactoryTool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool GetIsPool(ref long runtimeId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool GetIsPool(long runtimeId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(ref long entityId)
|
||||
{
|
||||
@@ -146,12 +134,6 @@ namespace Fantasy.IdFactory
|
||||
return (uint)(result & WorldEntityIdStruct.MaskTime);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(long entityId)
|
||||
{
|
||||
return GetTime(ref entityId);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(ref long entityId)
|
||||
{
|
||||
@@ -161,23 +143,11 @@ namespace Fantasy.IdFactory
|
||||
return (uint)(result & WorldEntityIdStruct.MaskSceneId) + worldId;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(long entityId)
|
||||
{
|
||||
return GetSceneId(ref entityId);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte GetWorldId(ref long entityId)
|
||||
{
|
||||
var result = (ulong)entityId >> 18;
|
||||
return (byte)(result & WorldEntityIdStruct.MaskWordId);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte GetWorldId(long entityId)
|
||||
{
|
||||
return GetWorldId(ref entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,33 +13,30 @@ namespace Fantasy.IdFactory
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct WorldRuntimeIdStruct
|
||||
{
|
||||
// RuntimeId: IsPool(1) + time(23) + SceneId(8) + WordId(8) + sequence(24) = 64 bits
|
||||
// +------------------+-------------------+--------------------------+-----------------------+--------------------------------------+
|
||||
// | IsPool(1) 对象池 | time(23) 最大60天 | SceneId(8) 最多255个Scene | WordId(8) 最多255个世界 | sequence(24) 每秒每个进程能生产16777215个
|
||||
// +------------------+-------------------+--------------------------+-----------------------+--------------------------------------+
|
||||
// RuntimeId:23 + 8 + 8 + 25 = 64
|
||||
// +-------------------+--------------------------+-----------------------+--------------------------------------+
|
||||
// | time(23) 最大60天 | SceneId(8) 最多255个Scene | WordId(8) 最多255个世界 | sequence(25) 每秒每个进程能生产33554431个
|
||||
// +-------------------+--------------------------+-----------------------+--------------------------------------+
|
||||
public uint Time { get; private set; }
|
||||
public uint SceneId { get; private set; }
|
||||
public byte WordId { get; private set; }
|
||||
public uint Sequence { get; private set; }
|
||||
public bool IsPool { get; private set; }
|
||||
|
||||
public const uint MaskSequence = 0xFFFFFF; // 24位(从25位减少到24位,为 IsPool 腾出空间)
|
||||
public const uint MaskSceneId = 0xFF; // 8位
|
||||
public const uint MaskWordId = 0xFF; // 8位
|
||||
public const uint MaskTime = 0x7FFFFF; // 23位(最高位留给 IsPool)
|
||||
public const uint MaskSequence = 0x1FFFFFF;
|
||||
public const uint MaskSceneId = 0xFF;
|
||||
public const uint MaskWordId = 0xFF;
|
||||
public const uint MaskTime = 0x7FFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// WorldRuntimeIdStruct(如果超过下面参数的设定该ID会失效)。
|
||||
/// </summary>
|
||||
/// <param name="isPool">是否来自对象池</param>
|
||||
/// <param name="time">time不能超过8388607</param>
|
||||
/// <param name="sceneId">sceneId不能超过255</param>
|
||||
/// <param name="wordId">wordId不能超过255</param>
|
||||
/// <param name="sequence">sequence不能超过16777215(24位)</param>
|
||||
public WorldRuntimeIdStruct(bool isPool, uint time, uint sceneId, byte wordId, uint sequence)
|
||||
/// <param name="sequence">sequence不能超过33554431</param>
|
||||
public WorldRuntimeIdStruct(uint time, uint sceneId, byte wordId, uint sequence)
|
||||
{
|
||||
// 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。
|
||||
IsPool = isPool;
|
||||
Time = time;
|
||||
SceneId = sceneId;
|
||||
WordId = wordId;
|
||||
@@ -48,26 +45,26 @@ namespace Fantasy.IdFactory
|
||||
|
||||
public static implicit operator long(WorldRuntimeIdStruct runtimeIdStruct)
|
||||
{
|
||||
ulong result = runtimeIdStruct.Sequence; // 低24位: sequence
|
||||
result |= (ulong)runtimeIdStruct.WordId << 24; // 第24-31位: wordId
|
||||
result |= (ulong)(runtimeIdStruct.SceneId % (runtimeIdStruct.WordId * 1000)) << 32; // 第32-39位: sceneId
|
||||
result |= (ulong)runtimeIdStruct.Time << 40; // 第40-62位: time
|
||||
result |= (runtimeIdStruct.IsPool ? 1UL : 0UL) << 63; // 最高位63: isPool
|
||||
ulong result = runtimeIdStruct.Sequence;
|
||||
result |= (ulong)runtimeIdStruct.WordId << 25;
|
||||
result |= (ulong)(runtimeIdStruct.SceneId % (runtimeIdStruct.WordId * 1000)) << 33;
|
||||
result |= (ulong)runtimeIdStruct.Time << 41;
|
||||
return (long)result;
|
||||
}
|
||||
|
||||
public static implicit operator WorldRuntimeIdStruct(long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId;
|
||||
var wordId = (byte)((result >> 24) & MaskWordId); // 第24-31位: wordId
|
||||
var runtimeIdStruct = new WorldRuntimeIdStruct
|
||||
{
|
||||
Sequence = (uint)(result & MaskSequence), // 低24位: sequence
|
||||
WordId = wordId,
|
||||
SceneId = (uint)((result >> 32) & MaskSceneId) + (uint)wordId * 1000, // 第32-39位: sceneId
|
||||
Time = (uint)((result >> 40) & MaskTime), // 第40-62位: time
|
||||
IsPool = ((result >> 63) & 1) == 1 // 最高位63: isPool
|
||||
Sequence = (uint)(result & MaskSequence)
|
||||
};
|
||||
result >>= 25;
|
||||
runtimeIdStruct.WordId = (byte)(result & MaskWordId);
|
||||
result >>= 8;
|
||||
runtimeIdStruct.SceneId = (uint)(result & MaskSceneId) + (uint)runtimeIdStruct.WordId * 1000;
|
||||
result >>= 8;
|
||||
runtimeIdStruct.Time = (uint)(result & MaskTime);
|
||||
return runtimeIdStruct;
|
||||
}
|
||||
}
|
||||
@@ -108,120 +105,51 @@ namespace Fantasy.IdFactory
|
||||
}
|
||||
}
|
||||
|
||||
public long Create(bool isPool)
|
||||
public long Create
|
||||
{
|
||||
var time = (uint)((TimeHelper.Now - _epochNow) / 1000);
|
||||
|
||||
if (time > _lastTime)
|
||||
get
|
||||
{
|
||||
_lastTime = time;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
else if (++_lastSequence > WorldRuntimeIdStruct.MaskSequence - 1)
|
||||
{
|
||||
_lastTime++;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
var time = (uint)((TimeHelper.Now - _epochNow) / 1000);
|
||||
|
||||
if (time > _lastTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
else if (++_lastSequence > WorldRuntimeIdStruct.MaskSequence - 1)
|
||||
{
|
||||
_lastTime++;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
|
||||
return new WorldRuntimeIdStruct(isPool, time, _sceneId, _worldId, _lastSequence);
|
||||
return new WorldRuntimeIdStruct(time, _sceneId, _worldId, _lastSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WorldRuntimeIdFactoryTool : IIdFactoryTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 IsPool 标志
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool GetIsPool(long runtimeId)
|
||||
{
|
||||
return GetIsPool(ref runtimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 IsPool 标志
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool GetIsPool(ref long runtimeId)
|
||||
{
|
||||
return (((ulong)runtimeId >> 63) & 1) == 1; // 最高位
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的时间部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 40; // 右移40位到第40-62位
|
||||
var result = (ulong)runtimeId >> 41;
|
||||
return (uint)(result & WorldRuntimeIdStruct.MaskTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的时间部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(long runtimeId)
|
||||
{
|
||||
return GetTime(ref runtimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 SceneId 部分
|
||||
/// </summary>
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 24; // 右移24位
|
||||
var worldId = (uint)(result & WorldRuntimeIdStruct.MaskWordId) * 1000; // 第24-31位: worldId
|
||||
var result = (ulong)runtimeId >> 25;
|
||||
var worldId = (uint)(result & WorldRuntimeIdStruct.MaskWordId) * 1000;
|
||||
result >>= 8;
|
||||
return (uint)(result & WorldRuntimeIdStruct.MaskSceneId) + worldId; // 第32-39位: sceneId
|
||||
return (uint)(result & WorldRuntimeIdStruct.MaskSceneId) + worldId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 SceneId 部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(long runtimeId)
|
||||
{
|
||||
return GetSceneId(ref runtimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 WorldId 部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte GetWorldId(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 24; // 右移24位到第24-31位
|
||||
var result = (ulong)runtimeId >> 25;
|
||||
return (byte)(result & WorldRuntimeIdStruct.MaskWordId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 WorldId 部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte GetWorldId(long runtimeId)
|
||||
{
|
||||
return GetWorldId(ref runtimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 Sequence 部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSequence(ref long runtimeId)
|
||||
{
|
||||
return (uint)((ulong)runtimeId & WorldRuntimeIdStruct.MaskSequence); // 低24位
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 RuntimeId 中的 Sequence 部分
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSequence(long runtimeId)
|
||||
{
|
||||
return GetSequence(ref runtimeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ using System;
|
||||
using System.Diagnostics;
|
||||
#if FANTASY_NET
|
||||
using Fantasy.Platform.Net;
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
#endif
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
@@ -16,27 +14,35 @@ namespace Fantasy
|
||||
public static class Log
|
||||
{
|
||||
private static ILog _logCore;
|
||||
|
||||
private static bool _isRegister;
|
||||
#if FANTASY_NET
|
||||
/// <summary>
|
||||
/// 初始化Log系统
|
||||
/// </summary>
|
||||
public static void Initialize(ILog log = null)
|
||||
public static void Initialize()
|
||||
{
|
||||
if (log == null)
|
||||
if (!_isRegister)
|
||||
{
|
||||
#if FANTASY_NET
|
||||
_logCore = new ConsoleLog();
|
||||
Register(new ConsoleLog());
|
||||
return;
|
||||
}
|
||||
|
||||
_logCore.Initialize(ProgramDefine.RuntimeMode);
|
||||
}
|
||||
#endif
|
||||
#if FANTASY_UNITY
|
||||
_logCore = new UnityLog();
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 注册一个日志系统
|
||||
/// </summary>
|
||||
/// <param name="log"></param>
|
||||
public static void Register(ILog log)
|
||||
{
|
||||
if (_isRegister)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logCore = log;
|
||||
#if FANTASY_NET
|
||||
_logCore.Initialize(ProgramDefine.RuntimeMode);
|
||||
#endif
|
||||
_isRegister = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -57,12 +57,12 @@ namespace Fantasy.Network.Route
|
||||
public NetworkMessagingComponent NetworkMessagingComponent;
|
||||
public MessageDispatcherComponent MessageDispatcherComponent;
|
||||
|
||||
internal void Send<T>(T message) where T : IAddressableRouteMessage
|
||||
internal void Send(IAddressableRouteMessage message)
|
||||
{
|
||||
Call<T>(message).Coroutine();
|
||||
Call(message).Coroutine();
|
||||
}
|
||||
|
||||
internal async FTask Send(Type requestType,APackInfo packInfo)
|
||||
internal async FTask Send(Type requestType, APackInfo packInfo)
|
||||
{
|
||||
await Call(requestType, packInfo);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ namespace Fantasy.Network.Route
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return MessageDispatcherComponent.CreateResponse(packInfo.ProtocolCode, InnerErrorCode.ErrNotFoundRoute);
|
||||
return MessageDispatcherComponent.CreateResponse(requestType, InnerErrorCode.ErrNotFoundRoute);
|
||||
}
|
||||
|
||||
packInfo.IsDisposed = true;
|
||||
@@ -92,9 +92,10 @@ namespace Fantasy.Network.Route
|
||||
|
||||
if (AddressableRouteId == 0)
|
||||
{
|
||||
return MessageDispatcherComponent.CreateResponse(packInfo.ProtocolCode, InnerErrorCode.ErrNotFoundRoute);
|
||||
return MessageDispatcherComponent.CreateResponse(requestType,
|
||||
InnerErrorCode.ErrNotFoundRoute);
|
||||
}
|
||||
|
||||
|
||||
iRouteResponse = await NetworkMessagingComponent.CallInnerRoute(AddressableRouteId, requestType, packInfo);
|
||||
|
||||
if (runtimeId != RuntimeId)
|
||||
@@ -147,11 +148,11 @@ namespace Fantasy.Network.Route
|
||||
/// 调用可寻址路由消息并等待响应。
|
||||
/// </summary>
|
||||
/// <param name="request">可寻址路由请求。</param>
|
||||
private async FTask<IResponse> Call<T>(T request) where T : IAddressableRouteMessage
|
||||
private async FTask<IResponse> Call(IAddressableRouteMessage request)
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return MessageDispatcherComponent.CreateResponse(request.OpCode(), InnerErrorCode.ErrNotFoundRoute);
|
||||
return MessageDispatcherComponent.CreateResponse(request.GetType(), InnerErrorCode.ErrNotFoundRoute);
|
||||
}
|
||||
|
||||
var failCount = 0;
|
||||
@@ -168,7 +169,8 @@ namespace Fantasy.Network.Route
|
||||
|
||||
if (AddressableRouteId == 0)
|
||||
{
|
||||
return MessageDispatcherComponent.CreateResponse(request.OpCode(), InnerErrorCode.ErrNotFoundRoute);
|
||||
return MessageDispatcherComponent.CreateResponse(request.GetType(),
|
||||
InnerErrorCode.ErrNotFoundRoute);
|
||||
}
|
||||
|
||||
var iRouteResponse = await NetworkMessagingComponent.CallInnerRoute(AddressableRouteId, request);
|
||||
@@ -184,7 +186,8 @@ namespace Fantasy.Network.Route
|
||||
{
|
||||
if (++failCount > 20)
|
||||
{
|
||||
Log.Error($"AddressableRouteComponent.Call failCount > 20 route send message fail, routeId: {RouteId} AddressableRouteComponent:{Id}");
|
||||
Log.Error(
|
||||
$"AddressableRouteComponent.Call failCount > 20 route send message fail, routeId: {RouteId} AddressableRouteComponent:{Id}");
|
||||
return iRouteResponse;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Fantasy.Network.Route
|
||||
public AddressableScene(SceneConfig sceneConfig)
|
||||
{
|
||||
Id = IdFactoryHelper.EntityId(0, sceneConfig.Id, (byte)sceneConfig.WorldConfigId, 0);
|
||||
RunTimeId = IdFactoryHelper.RuntimeId(false,0, sceneConfig.Id, (byte)sceneConfig.WorldConfigId, 0);
|
||||
RunTimeId = IdFactoryHelper.RuntimeId(0, sceneConfig.Id, (byte)sceneConfig.WorldConfigId, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace Fantasy.Network.Interface
|
||||
}
|
||||
finally
|
||||
{
|
||||
session.Send(new RouteResponse(), typeof(RouteResponse), rpcId);
|
||||
session.Send(new RouteResponse(), rpcId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,416 +1,426 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Fantasy.Assembly;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.DataStructure.Dictionary;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.InnerMessage;
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
// ReSharper disable ForCanBeConvertedToForeach
|
||||
// ReSharper disable InvertIf
|
||||
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
using Fantasy.Network;
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#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 CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
namespace Fantasy.Network.Interface
|
||||
{
|
||||
public sealed class MessageDispatcherComponent : Entity, IAssemblyLifecycle
|
||||
/// <summary>
|
||||
/// 用于存储消息处理器的信息,包括类型和对象实例。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">消息处理器的类型</typeparam>
|
||||
internal sealed class HandlerInfo<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置消息处理器对象。
|
||||
/// </summary>
|
||||
public T Obj;
|
||||
/// <summary>
|
||||
/// 获取或设置消息处理器的类型。
|
||||
/// </summary>
|
||||
public Type Type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络消息分发组件。
|
||||
/// </summary>
|
||||
public sealed class MessageDispatcherComponent : Entity, IAssembly
|
||||
{
|
||||
public long AssemblyIdentity { get; set; }
|
||||
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<long, Type> _assemblyResponseTypes = new OneToManyList<long, Type>();
|
||||
private readonly OneToManyList<long, uint> _assemblyNetworkProtocols = new OneToManyList<long, uint>();
|
||||
private readonly OneToManyList<long, HandlerInfo<IMessageHandler>> _assemblyMessageHandlers = new OneToManyList<long, HandlerInfo<IMessageHandler>>();
|
||||
#if FANTASY_UNITY
|
||||
private readonly Dictionary<Type, IMessageDelegateHandler> _messageDelegateHandlers = new Dictionary<Type, IMessageDelegateHandler>();
|
||||
#endif
|
||||
#if FANTASY_NET
|
||||
private readonly Dictionary<long, int> _customRouteMap = new Dictionary<long, int>();
|
||||
private readonly OneToManyList<long, long> _assemblyCustomRouteMap = new OneToManyList<long, long>();
|
||||
private readonly Dictionary<Type, IRouteMessageHandler> _routeMessageHandlers = new Dictionary<Type, IRouteMessageHandler>();
|
||||
private readonly OneToManyList<long, HandlerInfo<IRouteMessageHandler>> _assemblyRouteMessageHandlers = new OneToManyList<long, HandlerInfo<IRouteMessageHandler>>();
|
||||
#endif
|
||||
private CoroutineLock _receiveRouteMessageLock;
|
||||
|
||||
private readonly HashSet<long> _assemblyManifests = new();
|
||||
|
||||
private Func<uint, Type>? _lastHitGetOpCodeType;
|
||||
private Func<Session, uint, uint, object, bool>? _lastHitMessageHandler;
|
||||
|
||||
private readonly List<INetworkProtocolOpCodeResolver> _opCodeResolvers = new List<INetworkProtocolOpCodeResolver>();
|
||||
private readonly List<INetworkProtocolResponseTypeResolver> _responseTypeResolvers = new List<INetworkProtocolResponseTypeResolver>();
|
||||
private readonly List<IMessageHandlerResolver> _messageHandlerResolver = new List<IMessageHandlerResolver>();
|
||||
#if FANTASY_NET
|
||||
private Func<uint, int?>? _lastHitGetCustomRouteType;
|
||||
private Func<Session, Entity, uint, uint, object, FTask<bool>>? _lastHitRouteMessageHandler;
|
||||
private readonly List<IMessageHandlerResolver> _routeMessageHandlerResolver = new List<IMessageHandlerResolver>();
|
||||
private readonly List<INetworkProtocolOpCodeResolver> _customRouteResolvers = new List<INetworkProtocolOpCodeResolver>();
|
||||
#endif
|
||||
|
||||
#region Comparer
|
||||
|
||||
private class MessageHandlerResolverComparer : IComparer<IMessageHandlerResolver>
|
||||
{
|
||||
public int Compare(IMessageHandlerResolver? x, IMessageHandlerResolver? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return y.GetMessageHandlerCount().CompareTo(x.GetMessageHandlerCount());
|
||||
}
|
||||
}
|
||||
#if FANTASY_NET
|
||||
private class RouteMessageHandlerResolverComparer : IComparer<IMessageHandlerResolver>
|
||||
{
|
||||
public int Compare(IMessageHandlerResolver? x, IMessageHandlerResolver? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return y.GetRouteMessageHandlerCount().CompareTo(x.GetRouteMessageHandlerCount());
|
||||
}
|
||||
}
|
||||
private class RouteTypeResolverComparer : IComparer<INetworkProtocolOpCodeResolver>
|
||||
{
|
||||
public int Compare(INetworkProtocolOpCodeResolver? x, INetworkProtocolOpCodeResolver? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return y.GetCustomRouteTypeCount().CompareTo(x.GetCustomRouteTypeCount());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private class OpCodeResolverComparer : IComparer<INetworkProtocolOpCodeResolver>
|
||||
{
|
||||
public int Compare(INetworkProtocolOpCodeResolver? x, INetworkProtocolOpCodeResolver? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return y.GetOpCodeCount().CompareTo(x.GetOpCodeCount());
|
||||
}
|
||||
}
|
||||
|
||||
private class ResponseTypeResolverComparer : IComparer<INetworkProtocolResponseTypeResolver>
|
||||
{
|
||||
public int Compare(INetworkProtocolResponseTypeResolver? x, INetworkProtocolResponseTypeResolver? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return y.GetRequestCount().CompareTo(x.GetRequestCount());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_assemblyManifests.Clear();
|
||||
_opCodeResolvers.Clear();
|
||||
_responseTypeResolvers.Clear();
|
||||
_receiveRouteMessageLock.Dispose();
|
||||
_messageHandlerResolver.Clear();
|
||||
#if FANTASY_NET
|
||||
_customRouteResolvers.Clear();
|
||||
_routeMessageHandlerResolver.Clear();
|
||||
_lastHitGetCustomRouteType = null;
|
||||
_lastHitRouteMessageHandler = null;
|
||||
#endif
|
||||
_lastHitGetOpCodeType = null;
|
||||
_lastHitMessageHandler = null;
|
||||
_receiveRouteMessageLock = null;
|
||||
AssemblyLifecycle.Remove(this);
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
#region AssemblyManifest
|
||||
#region Initialize
|
||||
|
||||
internal async FTask<MessageDispatcherComponent> Initialize()
|
||||
{
|
||||
_receiveRouteMessageLock = Scene.CoroutineLockComponent.Create(GetType().TypeHandle.Value.ToInt64());
|
||||
await AssemblyLifecycle.Add(this);
|
||||
await AssemblySystem.Register(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public async FTask OnLoad(AssemblyManifest assemblyManifest)
|
||||
public async FTask Load(long assemblyIdentity)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
var assemblyManifestId = assemblyManifest.AssemblyManifestId;
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
if (_assemblyManifests.Contains(assemblyManifestId))
|
||||
{
|
||||
OnUnLoadInner(assemblyManifest);
|
||||
}
|
||||
// 注册Handler
|
||||
var messageHandlerResolver = assemblyManifest.MessageHandlerResolver;
|
||||
var messageHandlerCount = messageHandlerResolver.GetMessageHandlerCount();
|
||||
if (messageHandlerCount > 0)
|
||||
{
|
||||
_messageHandlerResolver.Add(messageHandlerResolver);
|
||||
_messageHandlerResolver.Sort(new MessageHandlerResolverComparer());
|
||||
}
|
||||
// 注册OpCode
|
||||
var opCodeResolver = assemblyManifest.NetworkProtocolOpCodeResolver;
|
||||
var opCodeCount = opCodeResolver.GetOpCodeCount();
|
||||
if (opCodeCount > 0)
|
||||
{
|
||||
_opCodeResolvers.Add(opCodeResolver);
|
||||
_opCodeResolvers.Sort(new OpCodeResolverComparer());
|
||||
}
|
||||
#if FANTASY_NET
|
||||
var routeMessageHandlerCount = messageHandlerResolver.GetRouteMessageHandlerCount();
|
||||
if (routeMessageHandlerCount > 0)
|
||||
{
|
||||
_routeMessageHandlerResolver.Add(messageHandlerResolver);
|
||||
_routeMessageHandlerResolver.Sort(new RouteMessageHandlerResolverComparer());
|
||||
}
|
||||
// 注册CustomRouteType
|
||||
var customRouteTypeCount = opCodeResolver.GetCustomRouteTypeCount();
|
||||
if (customRouteTypeCount > 0)
|
||||
{
|
||||
_customRouteResolvers.Add(opCodeResolver);
|
||||
_customRouteResolvers.Sort(new RouteTypeResolverComparer());
|
||||
}
|
||||
#endif
|
||||
// 注册ResponseType
|
||||
var responseTypeResolver = assemblyManifest.NetworkProtocolResponseTypeResolver;
|
||||
var requestCount = responseTypeResolver.GetRequestCount();
|
||||
if (requestCount > 0)
|
||||
{
|
||||
_responseTypeResolvers.Add(responseTypeResolver);
|
||||
_responseTypeResolvers.Sort(new ResponseTypeResolverComparer());
|
||||
}
|
||||
_assemblyManifests.Add(assemblyManifestId);
|
||||
LoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
public async FTask OnUnload(AssemblyManifest assemblyManifest)
|
||||
private void LoadInner(long assemblyIdentity)
|
||||
{
|
||||
// 遍历所有实现了IMessage接口的类型,获取OpCode并添加到_networkProtocols字典中
|
||||
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IMessage)))
|
||||
{
|
||||
var obj = (IMessage) Activator.CreateInstance(type);
|
||||
var opCode = obj.OpCode();
|
||||
|
||||
_networkProtocols.Add(opCode, type);
|
||||
|
||||
var responseType = type.GetProperty("ResponseType");
|
||||
|
||||
// 如果类型具有ResponseType属性,将其添加到_responseTypes字典中
|
||||
if (responseType != null)
|
||||
{
|
||||
_responseTypes.Add(type, responseType.PropertyType);
|
||||
_assemblyResponseTypes.Add(assemblyIdentity, type);
|
||||
}
|
||||
|
||||
_assemblyNetworkProtocols.Add(assemblyIdentity, opCode);
|
||||
}
|
||||
|
||||
// 遍历所有实现了IMessageHandler接口的类型,创建实例并添加到_messageHandlers字典中
|
||||
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, 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(assemblyIdentity, new HandlerInfo<IMessageHandler>()
|
||||
{
|
||||
Obj = obj, Type = key
|
||||
});
|
||||
}
|
||||
|
||||
// 如果编译符号FANTASY_NET存在,遍历所有实现了IRouteMessageHandler接口的类型,创建实例并添加到_routeMessageHandlers字典中
|
||||
#if FANTASY_NET
|
||||
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, 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(assemblyIdentity, new HandlerInfo<IRouteMessageHandler>()
|
||||
{
|
||||
Obj = obj, Type = key
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(ICustomRoute)))
|
||||
{
|
||||
var obj = (ICustomRoute) Activator.CreateInstance(type);
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
throw new Exception($"message handle {type.Name} is null");
|
||||
}
|
||||
|
||||
var opCode = obj.OpCode();
|
||||
_customRouteMap[opCode] = obj.RouteType;
|
||||
_assemblyCustomRouteMap.Add(assemblyIdentity, opCode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public async FTask ReLoad(long assemblyIdentity)
|
||||
{
|
||||
var tcs = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyManifest);
|
||||
OnUnLoadInner(assemblyIdentity);
|
||||
LoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
private void OnUnLoadInner(AssemblyManifest assemblyManifest)
|
||||
public async FTask OnUnLoad(long assemblyIdentity)
|
||||
{
|
||||
_messageHandlerResolver.Remove(assemblyManifest.MessageHandlerResolver);
|
||||
_opCodeResolvers.Remove(assemblyManifest.NetworkProtocolOpCodeResolver);
|
||||
_responseTypeResolvers.Remove(assemblyManifest.NetworkProtocolResponseTypeResolver);
|
||||
_messageHandlerResolver.Sort(new MessageHandlerResolverComparer());
|
||||
_opCodeResolvers.Sort(new OpCodeResolverComparer());
|
||||
_responseTypeResolvers.Sort(new ResponseTypeResolverComparer());
|
||||
#if FANTASY_NET
|
||||
_routeMessageHandlerResolver.Remove(assemblyManifest.MessageHandlerResolver);
|
||||
_customRouteResolvers.Remove(assemblyManifest.NetworkProtocolOpCodeResolver);
|
||||
_routeMessageHandlerResolver.Sort(new RouteMessageHandlerResolverComparer());
|
||||
_customRouteResolvers.Sort(new RouteTypeResolverComparer());
|
||||
#endif
|
||||
_assemblyManifests.Remove(assemblyManifest.AssemblyManifestId);
|
||||
var tcs = FTask.Create(false);
|
||||
Scene?.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
OnUnLoadInner(assemblyIdentity);
|
||||
tcs.SetResult();
|
||||
});
|
||||
await tcs;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal void MessageHandler(Session session, Type type, object message, uint rpcId, uint protocolCode)
|
||||
private void OnUnLoadInner(long assemblyIdentity)
|
||||
{
|
||||
if (_lastHitMessageHandler != null &&
|
||||
_lastHitMessageHandler(session, rpcId, protocolCode, message))
|
||||
// 移除程序集对应的ResponseType类型和OpCode信息
|
||||
if (_assemblyResponseTypes.TryGetValue(assemblyIdentity, out var removeResponseTypes))
|
||||
{
|
||||
foreach (var removeResponseType in removeResponseTypes)
|
||||
{
|
||||
_responseTypes.Remove(removeResponseType);
|
||||
}
|
||||
|
||||
_assemblyResponseTypes.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
if (_assemblyNetworkProtocols.TryGetValue(assemblyIdentity, out var removeNetworkProtocols))
|
||||
{
|
||||
foreach (var removeNetworkProtocol in removeNetworkProtocols)
|
||||
{
|
||||
_networkProtocols.RemoveByKey(removeNetworkProtocol);
|
||||
}
|
||||
|
||||
_assemblyNetworkProtocols.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
// 移除程序集对应的消息处理器信息
|
||||
if (_assemblyMessageHandlers.TryGetValue(assemblyIdentity, out var removeMessageHandlers))
|
||||
{
|
||||
foreach (var removeMessageHandler in removeMessageHandlers)
|
||||
{
|
||||
_messageHandlers.Remove(removeMessageHandler.Type);
|
||||
}
|
||||
|
||||
_assemblyMessageHandlers.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
// 如果编译符号FANTASY_NET存在,移除程序集对应的路由消息处理器信息
|
||||
#if FANTASY_NET
|
||||
if (_assemblyRouteMessageHandlers.TryGetValue(assemblyIdentity, out var removeRouteMessageHandlers))
|
||||
{
|
||||
foreach (var removeRouteMessageHandler in removeRouteMessageHandlers)
|
||||
{
|
||||
_routeMessageHandlers.Remove(removeRouteMessageHandler.Type);
|
||||
}
|
||||
|
||||
_assemblyRouteMessageHandlers.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
|
||||
if (_assemblyCustomRouteMap.TryGetValue(assemblyIdentity, out var removeCustomRouteMap))
|
||||
{
|
||||
foreach (var removeCustom in removeCustomRouteMap)
|
||||
{
|
||||
_customRouteMap.Remove(removeCustom);
|
||||
}
|
||||
|
||||
_assemblyCustomRouteMap.RemoveByKey(assemblyIdentity);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FANTASY_UNITY
|
||||
/// <summary>
|
||||
/// 手动注册一个消息处理器。
|
||||
/// </summary>
|
||||
/// <param name="delegate"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void RegisterHandler<T>(MessageDelegate<T> @delegate) where T : IMessage
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
if (!_messageDelegateHandlers.TryGetValue(type, out var messageDelegate))
|
||||
{
|
||||
messageDelegate = new MessageDelegateHandler<T>();
|
||||
_messageDelegateHandlers.Add(type,messageDelegate);
|
||||
}
|
||||
|
||||
messageDelegate.Register(@delegate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动卸载一个消息处理器,必须是通过RegisterHandler方法注册的消息处理器。
|
||||
/// </summary>
|
||||
/// <param name="delegate"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void UnRegisterHandler<T>(MessageDelegate<T> @delegate) where T : IMessage
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
if (!_messageDelegateHandlers.TryGetValue(type, out var messageDelegate))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (messageDelegate.UnRegister(@delegate) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < _messageHandlerResolver.Count; i++)
|
||||
_messageDelegateHandlers.Remove(type);
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 处理普通消息,将消息分发给相应的消息处理器。
|
||||
/// </summary>
|
||||
/// <param name="session">会话对象</param>
|
||||
/// <param name="type">消息类型</param>
|
||||
/// <param name="message">消息对象</param>
|
||||
/// <param name="rpcId">RPC标识</param>
|
||||
/// <param name="protocolCode">协议码</param>
|
||||
public void MessageHandler(Session session, Type type, object message, uint rpcId, uint protocolCode)
|
||||
{
|
||||
#if FANTASY_UNITY
|
||||
if(_messageDelegateHandlers.TryGetValue(type,out var messageDelegateHandler))
|
||||
{
|
||||
var resolver = _messageHandlerResolver[i];
|
||||
if (resolver.MessageHandler(session, rpcId, protocolCode, message))
|
||||
{
|
||||
_lastHitMessageHandler = resolver.MessageHandler;
|
||||
return;
|
||||
}
|
||||
messageDelegateHandler.Handle(session, message);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!_messageHandlers.TryGetValue(type, out var messageHandler))
|
||||
{
|
||||
Log.Warning($"Scene:{session.Scene.Id} Found Unhandled Message: {message.GetType()}");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Warning($"Scene:{session.Scene.Id} Found Unhandled Message: {type}");
|
||||
// 调用消息处理器的Handle方法并启动协程执行处理逻辑
|
||||
messageHandler.Handle(session, rpcId, protocolCode, message).Coroutine();
|
||||
}
|
||||
|
||||
// 如果编译符号FANTASY_NET存在,定义处理路由消息的方法
|
||||
#if FANTASY_NET
|
||||
private async FTask<bool> InnerRouteMessageHandler(Session session, Entity entity, uint rpcId, uint protocolCode, object message)
|
||||
/// <summary>
|
||||
/// 处理路由消息,将消息分发给相应的路由消息处理器。
|
||||
/// </summary>
|
||||
/// <param name="session">会话对象</param>
|
||||
/// <param name="type">消息类型</param>
|
||||
/// <param name="entity">实体对象</param>
|
||||
/// <param name="message">消息对象</param>
|
||||
/// <param name="rpcId">RPC标识</param>
|
||||
public async FTask RouteMessageHandler(Session session, Type type, Entity entity, object message, uint rpcId)
|
||||
{
|
||||
if (_lastHitRouteMessageHandler != null &&
|
||||
await _lastHitRouteMessageHandler(session, entity, rpcId, protocolCode, message))
|
||||
if (!_routeMessageHandlers.TryGetValue(type, out var routeMessageHandler))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Log.Warning($"Scene:{session.Scene.Id} Found Unhandled RouteMessage: {message.GetType()}");
|
||||
|
||||
for (var i = 0; i < _routeMessageHandlerResolver.Count; i++)
|
||||
{
|
||||
var resolver = _routeMessageHandlerResolver[i];
|
||||
if (await resolver.RouteMessageHandler(session, entity, rpcId, protocolCode, message))
|
||||
if (message is IRouteRequest request)
|
||||
{
|
||||
_lastHitRouteMessageHandler = resolver.RouteMessageHandler;
|
||||
return true;
|
||||
FailRouteResponse(session, request.GetType(), InnerErrorCode.ErrEntityNotFound, rpcId);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var runtimeId = entity.RuntimeId;
|
||||
var sessionRuntimeId = session.RuntimeId;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal async FTask RouteMessageHandler(Session session, Type type, Entity entity, object message, uint rpcId, uint protocolCode)
|
||||
{
|
||||
if (entity is Scene)
|
||||
{
|
||||
// 如果是Scene的话、就不要加锁了、如果加锁很一不小心就可能会造成死锁
|
||||
if (!await InnerRouteMessageHandler(session, entity, rpcId, protocolCode, message))
|
||||
{
|
||||
Log.Warning($"Scene:{session.Scene.Id} Found Unhandled RouteMessage: {type}");
|
||||
}
|
||||
await routeMessageHandler.Handle(session, entity, rpcId, message);
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用协程锁来确保消息的顺序
|
||||
var runtimeId = entity.RuntimeId;
|
||||
var sessionRuntimeId = session.RuntimeId;
|
||||
// 使用协程锁来确保多线程安全
|
||||
using (await _receiveRouteMessageLock.Wait(runtimeId))
|
||||
{
|
||||
if (sessionRuntimeId != session.RuntimeId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (runtimeId != entity.RuntimeId)
|
||||
{
|
||||
if (message is IRouteRequest request)
|
||||
{
|
||||
FailRouteResponse(session, request.OpCode(), InnerErrorCode.ErrEntityNotFound, rpcId);
|
||||
FailRouteResponse(session, request.GetType(), InnerErrorCode.ErrEntityNotFound, rpcId);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await InnerRouteMessageHandler(session, entity, rpcId, protocolCode, message))
|
||||
{
|
||||
Log.Warning($"Scene:{session.Scene.Id} Found Unhandled RouteMessage: {message.GetType()}");
|
||||
}
|
||||
await routeMessageHandler.Handle(session, entity, rpcId, message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#region Response
|
||||
|
||||
internal void FailRouteResponse(Session session, uint requestOpCode, uint error, uint rpcId)
|
||||
internal bool GetCustomRouteType(long protocolCode, out int routeType)
|
||||
{
|
||||
session.Send(CreateRouteResponse(requestOpCode, error, out var responseType), responseType, rpcId);
|
||||
return _customRouteMap.TryGetValue(protocolCode, out routeType);
|
||||
}
|
||||
|
||||
internal IResponse CreateResponse(uint requestOpCode, uint error)
|
||||
#endif
|
||||
internal void FailRouteResponse(Session session, Type requestType, uint error, uint rpcId)
|
||||
{
|
||||
var response = CreateRouteResponse(requestType, error);
|
||||
session.Send(response, rpcId);
|
||||
}
|
||||
|
||||
internal IResponse CreateResponse(Type requestType, uint error)
|
||||
{
|
||||
IResponse response;
|
||||
|
||||
for (var i = 0; i < _responseTypeResolvers.Count; i++)
|
||||
if (_responseTypes.TryGetValue(requestType, out var responseType))
|
||||
{
|
||||
var resolver = _responseTypeResolvers[i];
|
||||
var responseType = resolver.GetResponseType(requestOpCode);
|
||||
if (responseType == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
response = (IResponse) Activator.CreateInstance(responseType);
|
||||
response.ErrorCode = error;
|
||||
return response;
|
||||
}
|
||||
|
||||
response = new Response();
|
||||
else
|
||||
{
|
||||
response = new Response();
|
||||
}
|
||||
|
||||
response.ErrorCode = error;
|
||||
return response;
|
||||
}
|
||||
|
||||
private IRouteResponse CreateRouteResponse(uint requestOpCode, uint error, out Type responseType)
|
||||
|
||||
internal IRouteResponse CreateRouteResponse(Type requestType, uint error)
|
||||
{
|
||||
IRouteResponse response;
|
||||
|
||||
for (var i = 0; i < _responseTypeResolvers.Count; i++)
|
||||
if (_responseTypes.TryGetValue(requestType, out var responseType))
|
||||
{
|
||||
var resolver = _responseTypeResolvers[i];
|
||||
responseType = resolver.GetResponseType(requestOpCode);
|
||||
if (responseType == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
response = (IRouteResponse)Activator.CreateInstance(responseType);
|
||||
response.ErrorCode = error;
|
||||
return response;
|
||||
response = (IRouteResponse) Activator.CreateInstance(responseType);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = new RouteResponse();
|
||||
}
|
||||
|
||||
responseType = typeof(RouteResponse);
|
||||
response = new RouteResponse();
|
||||
response.ErrorCode = error;
|
||||
return response;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region OpCode
|
||||
|
||||
internal Type? GetOpCodeType(uint opCode)
|
||||
|
||||
/// <summary>
|
||||
/// 根据消息类型获取对应的OpCode。
|
||||
/// </summary>
|
||||
/// <param name="type">消息类型</param>
|
||||
/// <returns>消息对应的OpCode</returns>
|
||||
public uint GetOpCode(Type type)
|
||||
{
|
||||
if (_lastHitGetOpCodeType != null )
|
||||
{
|
||||
var opCodeType = _lastHitGetOpCodeType(opCode);
|
||||
if (opCodeType != null)
|
||||
{
|
||||
return opCodeType;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < _opCodeResolvers.Count; i++)
|
||||
{
|
||||
var resolver = _opCodeResolvers[i];
|
||||
var opCodeType = resolver.GetOpCodeType(opCode);
|
||||
if (opCodeType != null)
|
||||
{
|
||||
_lastHitGetOpCodeType = resolver.GetOpCodeType;
|
||||
return opCodeType;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return _networkProtocols.GetKeyByValue(type);
|
||||
}
|
||||
#if FANTASY_NET
|
||||
internal int? GetCustomRouteType(uint protocolCode)
|
||||
|
||||
/// <summary>
|
||||
/// 根据OpCode获取对应的消息类型。
|
||||
/// </summary>
|
||||
/// <param name="code">OpCode</param>
|
||||
/// <returns>OpCode对应的消息类型</returns>
|
||||
public Type GetOpCodeType(uint code)
|
||||
{
|
||||
if (_lastHitGetCustomRouteType != null)
|
||||
{
|
||||
var opCodeType = _lastHitGetCustomRouteType(protocolCode);
|
||||
if (opCodeType.HasValue)
|
||||
{
|
||||
return opCodeType.Value;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < _customRouteResolvers.Count; i++)
|
||||
{
|
||||
var resolver = _customRouteResolvers[i];
|
||||
var opCodeType = resolver.GetCustomRouteType(protocolCode);
|
||||
if (opCodeType.HasValue)
|
||||
{
|
||||
_lastHitGetCustomRouteType = resolver.GetCustomRouteType;
|
||||
return opCodeType.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return _networkProtocols.GetValueByKey(code);
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,8 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Pool;
|
||||
using Fantasy.Serialize;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
using ProtoBuf;
|
||||
#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 CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace Fantasy.Network.Interface
|
||||
{
|
||||
public abstract class AMessage : ASerialize, IPool
|
||||
{
|
||||
#if FANTASY_NET || FANTASY_UNITY || FANTASY_CONSOLE
|
||||
[BsonIgnore]
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
private Scene _scene;
|
||||
protected Scene GetScene()
|
||||
{
|
||||
return _scene;
|
||||
}
|
||||
|
||||
public void SetScene(Scene scene)
|
||||
{
|
||||
_scene = scene;
|
||||
}
|
||||
#endif
|
||||
#if FANTASY_NET
|
||||
[BsonIgnore]
|
||||
#endif
|
||||
[JsonIgnore]
|
||||
[IgnoreDataMember]
|
||||
[ProtoIgnore]
|
||||
private bool _isPool;
|
||||
|
||||
public bool IsPool()
|
||||
{
|
||||
return _isPool;
|
||||
}
|
||||
|
||||
public void SetIsPool(bool isPool)
|
||||
{
|
||||
_isPool = isPool;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 表示通用消息接口。
|
||||
/// </summary>
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace Fantasy.InnerMessage
|
||||
return Fantasy.Network.OpCode.BenchmarkMessage;
|
||||
}
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public partial class BenchmarkRequest : AMessage, IRequest
|
||||
{
|
||||
|
||||
@@ -96,9 +96,9 @@ namespace Fantasy.PacketParser
|
||||
return true;
|
||||
}
|
||||
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType)
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message)
|
||||
{
|
||||
return memoryStream == null ? Pack(ref rpcId, ref routeId, message, messageType) : Pack(ref rpcId, ref routeId, memoryStream);
|
||||
return memoryStream == null ? Pack(ref rpcId, ref routeId, message) : Pack(ref rpcId, ref routeId, memoryStream);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -114,12 +114,12 @@ namespace Fantasy.PacketParser
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message, Type messageType)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message)
|
||||
{
|
||||
var memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack);
|
||||
var opCode = message.OpCode();
|
||||
OpCodeIdStruct opCodeIdStruct = opCode;
|
||||
OpCodeIdStruct opCodeIdStruct = message.OpCode();
|
||||
memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin);
|
||||
|
||||
if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer))
|
||||
@@ -131,7 +131,8 @@ namespace Fantasy.PacketParser
|
||||
{
|
||||
Log.Error($"type:{messageType} Does not support processing protocol");
|
||||
}
|
||||
|
||||
|
||||
var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType);
|
||||
var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength;
|
||||
|
||||
if (packetBodyCount == 0)
|
||||
@@ -208,9 +209,9 @@ namespace Fantasy.PacketParser
|
||||
return true;
|
||||
}
|
||||
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType)
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message)
|
||||
{
|
||||
return memoryStream == null ? Pack(ref rpcId, message, messageType) : Pack(ref rpcId, memoryStream);
|
||||
return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -227,12 +228,12 @@ namespace Fantasy.PacketParser
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, IMessage message, Type messageType)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, IMessage message)
|
||||
{
|
||||
var memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack);
|
||||
var opCode = message.OpCode();
|
||||
OpCodeIdStruct opCodeIdStruct = opCode;
|
||||
OpCodeIdStruct opCodeIdStruct = message.OpCode();
|
||||
memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin);
|
||||
|
||||
if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer))
|
||||
@@ -245,8 +246,7 @@ namespace Fantasy.PacketParser
|
||||
Log.Error($"type:{messageType} Does not support processing protocol");
|
||||
}
|
||||
|
||||
|
||||
// var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType);
|
||||
var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType);
|
||||
var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength;
|
||||
|
||||
if (packetBodyCount == 0)
|
||||
@@ -324,9 +324,9 @@ namespace Fantasy.PacketParser
|
||||
return true;
|
||||
}
|
||||
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType)
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message)
|
||||
{
|
||||
return memoryStream == null ? Pack(ref rpcId, message, messageType) : Pack(ref rpcId, memoryStream);
|
||||
return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -343,12 +343,12 @@ namespace Fantasy.PacketParser
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, IMessage message, Type messageType)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, IMessage message)
|
||||
{
|
||||
var memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.UnPack);
|
||||
var opCode = message.OpCode();
|
||||
OpCodeIdStruct opCodeIdStruct = opCode;
|
||||
OpCodeIdStruct opCodeIdStruct = message.OpCode();
|
||||
memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin);
|
||||
|
||||
if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer))
|
||||
@@ -361,6 +361,7 @@ namespace Fantasy.PacketParser
|
||||
Log.Error($"type:{messageType} Does not support processing protocol");
|
||||
}
|
||||
|
||||
var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType);
|
||||
var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength;
|
||||
|
||||
if (packetBodyCount == 0)
|
||||
|
||||
@@ -19,18 +19,17 @@ namespace Fantasy.PacketParser
|
||||
/// <param name="scene">scene</param>
|
||||
/// <param name="rpcId">如果是RPC消息需要传递一个rpcId</param>
|
||||
/// <param name="message">打包的网络消息</param>
|
||||
/// <param name="messageType">打包的网络消息类型</param>
|
||||
/// <param name="memoryStreamLength">序列化后流的长度</param>
|
||||
/// <returns>打包完成会返回一个MemoryStreamBuffer</returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static MemoryStreamBuffer Pack(Scene scene, uint rpcId, IMessage message, Type messageType, out int memoryStreamLength)
|
||||
public static MemoryStreamBuffer Pack(Scene scene, uint rpcId, IMessage message, out int memoryStreamLength)
|
||||
{
|
||||
memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
var memoryStream = new MemoryStreamBuffer();
|
||||
memoryStream.MemoryStreamBufferSource = MemoryStreamBufferSource.Pack;
|
||||
var opCode = message.OpCode();
|
||||
OpCodeIdStruct opCodeIdStruct = opCode;
|
||||
OpCodeIdStruct opCodeIdStruct = message.OpCode();
|
||||
memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin);
|
||||
|
||||
if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer))
|
||||
@@ -42,7 +41,8 @@ namespace Fantasy.PacketParser
|
||||
{
|
||||
Log.Error($"type:{messageType} Does not support processing protocol");
|
||||
}
|
||||
;
|
||||
|
||||
var opCode = scene.MessageDispatcherComponent.GetOpCode(messageType);
|
||||
var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength;
|
||||
|
||||
if (packetBodyCount == 0)
|
||||
|
||||
@@ -143,9 +143,9 @@ namespace Fantasy.PacketParser
|
||||
return false;
|
||||
}
|
||||
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType)
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message)
|
||||
{
|
||||
return memoryStream == null ? Pack(ref rpcId, ref routeId, message, messageType) : Pack(ref rpcId, ref routeId, memoryStream);
|
||||
return memoryStream == null ? Pack(ref rpcId, ref routeId, message) : Pack(ref rpcId, ref routeId, memoryStream);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -161,12 +161,12 @@ namespace Fantasy.PacketParser
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message, Type messageType)
|
||||
private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message)
|
||||
{
|
||||
var memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack);
|
||||
var opCode = message.OpCode();
|
||||
OpCodeIdStruct opCodeIdStruct = opCode;
|
||||
OpCodeIdStruct opCodeIdStruct = message.OpCode();
|
||||
memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin);
|
||||
|
||||
if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer))
|
||||
@@ -179,7 +179,7 @@ namespace Fantasy.PacketParser
|
||||
Log.Error($"type:{messageType} Does not support processing protocol");
|
||||
}
|
||||
|
||||
|
||||
var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType);
|
||||
var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength;
|
||||
|
||||
if (packetBodyCount == 0)
|
||||
@@ -306,9 +306,9 @@ namespace Fantasy.PacketParser
|
||||
return false;
|
||||
}
|
||||
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType)
|
||||
public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message)
|
||||
{
|
||||
return memoryStream == null ? Pack(ref rpcId, message, messageType) : Pack(ref rpcId, memoryStream);
|
||||
return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -326,12 +326,12 @@ namespace Fantasy.PacketParser
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, IMessage message, Type messageType)
|
||||
private unsafe MemoryStreamBuffer Pack(ref uint rpcId, IMessage message)
|
||||
{
|
||||
var memoryStreamLength = 0;
|
||||
var messageType = message.GetType();
|
||||
var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack);
|
||||
var opCode = message.OpCode();
|
||||
OpCodeIdStruct opCodeIdStruct = opCode;
|
||||
OpCodeIdStruct opCodeIdStruct = message.OpCode();
|
||||
memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin);
|
||||
|
||||
if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer))
|
||||
@@ -344,7 +344,7 @@ namespace Fantasy.PacketParser
|
||||
Log.Error($"type:{messageType} Does not support processing protocol");
|
||||
}
|
||||
|
||||
|
||||
var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType);
|
||||
var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength;
|
||||
|
||||
if (packetBodyCount == 0)
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Fantasy.PacketParser.Interface
|
||||
internal ANetwork Network;
|
||||
internal MessageDispatcherComponent MessageDispatcherComponent;
|
||||
protected bool IsDisposed { get; private set; }
|
||||
public abstract MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType);
|
||||
public abstract MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message);
|
||||
public virtual void Dispose()
|
||||
{
|
||||
IsDisposed = true;
|
||||
|
||||
@@ -86,43 +86,37 @@ namespace Fantasy.Network
|
||||
|
||||
public static class OpCode
|
||||
{
|
||||
// 格式: Index | (OpCodeProtocolType << 23) | (Protocol << 27)
|
||||
// 所有值已预先计算,使 SourceGenerator 可以在编译时获取这些常量
|
||||
|
||||
public const uint BenchmarkMessage = 142606335; // Create(ProtoBuf=0, OuterMessage=1, 8388607)
|
||||
public const uint BenchmarkRequest = 276824063; // Create(ProtoBuf=0, OuterRequest=2, 8388607)
|
||||
public const uint BenchmarkResponse = 411041791; // Create(ProtoBuf=0, OuterResponse=3, 8388607)
|
||||
public const uint PingRequest = 4026531841; // Create(ProtoBuf=0, OuterPingRequest=30, 1)
|
||||
public const uint PingResponse = 4160749569; // Create(ProtoBuf=0, OuterPingResponse=31, 1)
|
||||
public const uint DefaultResponse = 805306369; // Create(ProtoBuf=0, InnerResponse=6, 1)
|
||||
public const uint DefaultRouteResponse = 1207959559; // Create(ProtoBuf=0, InnerRouteResponse=9, 7)
|
||||
public const uint AddressableAddRequest = 1073741825; // Create(ProtoBuf=0, InnerRouteRequest=8, 1)
|
||||
public const uint AddressableAddResponse = 1207959553; // Create(ProtoBuf=0, InnerRouteResponse=9, 1)
|
||||
public const uint AddressableGetRequest = 1073741826; // Create(ProtoBuf=0, InnerRouteRequest=8, 2)
|
||||
public const uint AddressableGetResponse = 1207959554; // Create(ProtoBuf=0, InnerRouteResponse=9, 2)
|
||||
public const uint AddressableRemoveRequest = 1073741827; // Create(ProtoBuf=0, InnerRouteRequest=8, 3)
|
||||
public const uint AddressableRemoveResponse = 1207959555; // Create(ProtoBuf=0, InnerRouteResponse=9, 3)
|
||||
public const uint AddressableLockRequest = 1073741828; // Create(ProtoBuf=0, InnerRouteRequest=8, 4)
|
||||
public const uint AddressableLockResponse = 1207959556; // Create(ProtoBuf=0, InnerRouteResponse=9, 4)
|
||||
public const uint AddressableUnLockRequest = 1073741829; // Create(ProtoBuf=0, InnerRouteRequest=8, 5)
|
||||
public const uint AddressableUnLockResponse = 1207959557; // Create(ProtoBuf=0, InnerRouteResponse=9, 5)
|
||||
public const uint LinkRoamingRequest = 1073741830; // Create(ProtoBuf=0, InnerRouteRequest=8, 6)
|
||||
public const uint LinkRoamingResponse = 1207959558; // Create(ProtoBuf=0, InnerRouteResponse=9, 6)
|
||||
public const uint UnLinkRoamingRequest = 1073741832; // Create(ProtoBuf=0, InnerRouteRequest=8, 8)
|
||||
public const uint UnLinkRoamingResponse = 1207959560; // Create(ProtoBuf=0, InnerRouteResponse=9, 8)
|
||||
public const uint LockTerminusIdRequest = 1073741833; // Create(ProtoBuf=0, InnerRouteRequest=8, 9)
|
||||
public const uint LockTerminusIdResponse = 1207959561; // Create(ProtoBuf=0, InnerRouteResponse=9, 9)
|
||||
public const uint UnLockTerminusIdRequest = 1073741834; // Create(ProtoBuf=0, InnerRouteRequest=8, 10)
|
||||
public const uint UnLockTerminusIdResponse = 1207959562; // Create(ProtoBuf=0, InnerRouteResponse=9, 10)
|
||||
public const uint GetTerminusIdRequest = 1073741835; // Create(ProtoBuf=0, InnerRouteRequest=8, 11)
|
||||
public const uint GetTerminusIdResponse = 1207959563; // Create(ProtoBuf=0, InnerRouteResponse=9, 11)
|
||||
|
||||
public const uint TransferTerminusRequest = 1082130433; // Create(Bson=1, InnerRouteRequest=8, 1)
|
||||
public const uint TransferTerminusResponse = 1216348161; // Create(Bson=1, InnerRouteResponse=9, 1)
|
||||
|
||||
/// <summary>
|
||||
/// 创建 OpCode(运行时使用)
|
||||
/// </summary>
|
||||
public static readonly uint BenchmarkMessage = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterMessage, 8388607);
|
||||
public static readonly uint BenchmarkRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterRequest, 8388607);
|
||||
public static readonly uint BenchmarkResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterResponse, 8388607);
|
||||
public static readonly uint PingRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterPingRequest, 1);
|
||||
public static readonly uint PingResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterPingResponse, 1);
|
||||
public static readonly uint DefaultResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerResponse, 1);
|
||||
public static readonly uint DefaultRouteResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 7);
|
||||
public static readonly uint AddressableAddRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 1);
|
||||
public static readonly uint AddressableAddResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 1);
|
||||
public static readonly uint AddressableGetRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 2);
|
||||
public static readonly uint AddressableGetResponse = Create(OpCodeProtocolType.ProtoBuf,OpCodeType.InnerRouteResponse,2);
|
||||
public static readonly uint AddressableRemoveRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 3);
|
||||
public static readonly uint AddressableRemoveResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 3);
|
||||
public static readonly uint AddressableLockRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 4);
|
||||
public static readonly uint AddressableLockResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 4);
|
||||
public static readonly uint AddressableUnLockRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 5);
|
||||
public static readonly uint AddressableUnLockResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 5);
|
||||
public static readonly uint LinkRoamingRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 6);
|
||||
public static readonly uint LinkRoamingResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 6);
|
||||
public static readonly uint UnLinkRoamingRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 8);
|
||||
public static readonly uint UnLinkRoamingResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 8);
|
||||
public static readonly uint LockTerminusIdRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 9);
|
||||
public static readonly uint LockTerminusIdResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 9);
|
||||
public static readonly uint UnLockTerminusIdRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 10);
|
||||
public static readonly uint UnLockTerminusIdResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 10);
|
||||
public static readonly uint GetTerminusIdRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 11);
|
||||
public static readonly uint GetTerminusIdResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 11);
|
||||
|
||||
public static readonly uint TransferTerminusRequest = Create(OpCodeProtocolType.Bson, OpCodeType.InnerRouteRequest, 1);
|
||||
public static readonly uint TransferTerminusResponse = Create(OpCodeProtocolType.Bson, OpCodeType.InnerRouteResponse, 1);
|
||||
|
||||
public static uint Create(uint opCodeProtocolType, uint protocol, uint index)
|
||||
{
|
||||
return new OpCodeIdStruct(opCodeProtocolType, protocol, index);
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Fantasy.PacketParser
|
||||
{
|
||||
public sealed class InnerPackInfo : APackInfo
|
||||
{
|
||||
private readonly Dictionary<RuntimeTypeHandle, Func<object>> _createInstances = new Dictionary<RuntimeTypeHandle, Func<object>>();
|
||||
private readonly Dictionary<Type, Func<object>> _createInstances = new Dictionary<Type, Func<object>>();
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
@@ -53,13 +53,13 @@ namespace Fantasy.PacketParser
|
||||
|
||||
if (MemoryStream.Length == 0)
|
||||
{
|
||||
if (_createInstances.TryGetValue(messageType.TypeHandle, out var createInstance))
|
||||
if (_createInstances.TryGetValue(messageType, out var createInstance))
|
||||
{
|
||||
return createInstance();
|
||||
}
|
||||
|
||||
createInstance = CreateInstance.CreateObject(messageType);
|
||||
_createInstances.Add(messageType.TypeHandle, createInstance);
|
||||
_createInstances.Add(messageType, createInstance);
|
||||
return createInstance();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Fantasy.PacketParser
|
||||
private int _disposeCount;
|
||||
public Type MessageType { get; private set; }
|
||||
private static readonly ConcurrentQueue<ProcessPackInfo> Caches = new ConcurrentQueue<ProcessPackInfo>();
|
||||
private readonly ConcurrentDictionary<RuntimeTypeHandle, Func<object>> _createInstances = new ConcurrentDictionary<RuntimeTypeHandle, Func<object>>();
|
||||
private readonly ConcurrentDictionary<Type, Func<object>> _createInstances = new ConcurrentDictionary<Type, Func<object>>();
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
@@ -54,8 +54,7 @@ namespace Fantasy.PacketParser
|
||||
packInfo.IsDisposed = false;
|
||||
var memoryStream = new MemoryStreamBuffer();
|
||||
memoryStream.MemoryStreamBufferSource = MemoryStreamBufferSource.Pack;
|
||||
var opCode = message.OpCode();
|
||||
OpCodeIdStruct opCodeIdStruct = opCode;
|
||||
OpCodeIdStruct opCodeIdStruct = message.OpCode();
|
||||
memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin);
|
||||
|
||||
if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer))
|
||||
@@ -67,7 +66,8 @@ namespace Fantasy.PacketParser
|
||||
{
|
||||
Log.Error($"type:{type} Does not support processing protocol");
|
||||
}
|
||||
|
||||
|
||||
var opCode = scene.MessageDispatcherComponent.GetOpCode(packInfo.MessageType);
|
||||
var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength;
|
||||
|
||||
if (packetBodyCount == 0)
|
||||
@@ -128,24 +128,25 @@ namespace Fantasy.PacketParser
|
||||
Log.Debug("Deserialize MemoryStream is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
var messageTypeTypeHandle = messageType.TypeHandle;
|
||||
|
||||
object obj = null;
|
||||
MemoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin);
|
||||
|
||||
if (MemoryStream.Length == 0)
|
||||
{
|
||||
if (_createInstances.TryGetValue(messageTypeTypeHandle, out var createInstance))
|
||||
if (_createInstances.TryGetValue(messageType, out var createInstance))
|
||||
{
|
||||
return createInstance();
|
||||
}
|
||||
|
||||
createInstance = CreateInstance.CreateObject(messageType);
|
||||
_createInstances.TryAdd(messageTypeTypeHandle, createInstance);
|
||||
_createInstances.TryAdd(messageType, createInstance);
|
||||
return createInstance();
|
||||
}
|
||||
|
||||
if (SerializerManager.TryGetSerializer(OpCodeIdStruct.OpCodeProtocolType, out var serializer))
|
||||
{
|
||||
var obj = serializer.Deserialize(messageType, MemoryStream);
|
||||
obj = serializer.Deserialize(messageType, MemoryStream);
|
||||
MemoryStream.Seek(0, SeekOrigin.Begin);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ using Fantasy.Network;
|
||||
using Fantasy.Network.Interface;
|
||||
using Fantasy.PacketParser;
|
||||
using Fantasy.PacketParser.Interface;
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
@@ -86,12 +85,12 @@ namespace Fantasy.Scheduler
|
||||
|
||||
if (!Scene.TryGetEntity(packInfo.RouteId, out var entity))
|
||||
{
|
||||
Scene.MessageDispatcherComponent.FailRouteResponse(session, packInfo.ProtocolCode, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId);
|
||||
Scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId);
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = packInfo.Deserialize(messageType);
|
||||
await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId, packInfo.ProtocolCode);
|
||||
await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -111,12 +110,12 @@ namespace Fantasy.Scheduler
|
||||
|
||||
if (!Scene.TryGetEntity(packInfo.RouteId, out var entity))
|
||||
{
|
||||
Scene.MessageDispatcherComponent.FailRouteResponse(session, packInfo.ProtocolCode, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId);
|
||||
Scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId);
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = packInfo.Deserialize(messageType);
|
||||
await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId, packInfo.ProtocolCode);
|
||||
await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -159,7 +158,7 @@ namespace Fantasy.Scheduler
|
||||
case OpCodeType.OuterAddressableRequest:
|
||||
case OpCodeType.OuterAddressableMessage:
|
||||
{
|
||||
Scene.MessageDispatcherComponent.FailRouteResponse(session, packInfo.ProtocolCode, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId);
|
||||
Scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -191,7 +190,7 @@ namespace Fantasy.Scheduler
|
||||
}
|
||||
|
||||
var obj = packInfo.Deserialize(messageType);
|
||||
await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId, packInfo.ProtocolCode);
|
||||
await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Fantasy.Scheduler
|
||||
public readonly SortedDictionary<uint, MessageSender> RequestCallback = new();
|
||||
public readonly Dictionary<uint, MessageSender> TimeoutRouteMessageSenders = new();
|
||||
|
||||
public void SendInnerRoute<T>(long routeId, T message) where T : IRouteMessage
|
||||
public void SendInnerRoute(long routeId, IRouteMessage message)
|
||||
{
|
||||
if (routeId == 0)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ namespace Fantasy.Scheduler
|
||||
Scene.GetSession(routeId).Send(0, routeId, messageType, packInfo);
|
||||
}
|
||||
|
||||
public void SendInnerRoute<T>(ICollection<long> routeIdCollection, T message) where T : IRouteMessage
|
||||
public void SendInnerRoute(ICollection<long> routeIdCollection, IRouteMessage message)
|
||||
{
|
||||
if (routeIdCollection.Count <= 0)
|
||||
{
|
||||
@@ -109,7 +109,7 @@ namespace Fantasy.Scheduler
|
||||
}
|
||||
}
|
||||
|
||||
public async FTask SendAddressable<T>(long addressableId, T message) where T : IRouteMessage
|
||||
public async FTask SendAddressable(long addressableId, IRouteMessage message)
|
||||
{
|
||||
await CallAddressable(addressableId, message);
|
||||
}
|
||||
@@ -121,7 +121,7 @@ namespace Fantasy.Scheduler
|
||||
Log.Error($"CallInnerRoute routeId == 0");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var rpcId = ++_rpcId;
|
||||
var session = Scene.GetSession(routeId);
|
||||
var requestCallback = FTask<IResponse>.Create(false);
|
||||
@@ -130,7 +130,7 @@ namespace Fantasy.Scheduler
|
||||
return await requestCallback;
|
||||
}
|
||||
|
||||
public async FTask<IResponse> CallInnerRouteBySession<T>(Session session, long routeId, T request) where T : IRouteMessage
|
||||
public async FTask<IResponse> CallInnerRouteBySession(Session session, long routeId, IRouteMessage request)
|
||||
{
|
||||
var rpcId = ++_rpcId;
|
||||
var requestCallback = FTask<IResponse>.Create(false);
|
||||
@@ -139,7 +139,7 @@ namespace Fantasy.Scheduler
|
||||
return await requestCallback;
|
||||
}
|
||||
|
||||
public async FTask<IResponse> CallInnerRoute<T>(long routeId, T request) where T : IRouteMessage
|
||||
public async FTask<IResponse> CallInnerRoute(long routeId, IRouteMessage request)
|
||||
{
|
||||
if (routeId == 0)
|
||||
{
|
||||
@@ -151,11 +151,11 @@ namespace Fantasy.Scheduler
|
||||
var session = Scene.GetSession(routeId);
|
||||
var requestCallback = FTask<IResponse>.Create(false);
|
||||
RequestCallback.Add(rpcId, MessageSender.Create(rpcId, request, requestCallback));
|
||||
session.Send<T>(request, rpcId, routeId);
|
||||
session.Send(request, rpcId, routeId);
|
||||
return await requestCallback;
|
||||
}
|
||||
|
||||
public async FTask<IResponse> CallAddressable<T>(long addressableId, T request) where T : IRouteMessage
|
||||
public async FTask<IResponse> CallAddressable(long addressableId, IRouteMessage request)
|
||||
{
|
||||
var failCount = 0;
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace Fantasy.Scheduler
|
||||
|
||||
if (addressableRouteId == 0)
|
||||
{
|
||||
return MessageDispatcherComponent.CreateResponse(request.OpCode(), InnerErrorCode.ErrNotFoundRoute);
|
||||
return MessageDispatcherComponent.CreateResponse(request.GetType(), InnerErrorCode.ErrNotFoundRoute);
|
||||
}
|
||||
|
||||
var iRouteResponse = await CallInnerRoute(addressableRouteId, request);
|
||||
@@ -246,8 +246,8 @@ namespace Fantasy.Scheduler
|
||||
}
|
||||
case IRequest iRequest:
|
||||
{
|
||||
var response = MessageDispatcherComponent.CreateResponse(iRequest.GetType(), InnerErrorCode.ErrRpcFail);
|
||||
var responseRpcId = messageSender.RpcId;
|
||||
var response = MessageDispatcherComponent.CreateResponse(iRequest.OpCode(), InnerErrorCode.ErrRpcFail);
|
||||
ResponseHandler(responseRpcId, response);
|
||||
Log.Warning($"timeout rpcId:{rpcId} responseRpcId:{responseRpcId} {iRequest.ToJson()}");
|
||||
break;
|
||||
@@ -256,7 +256,7 @@ namespace Fantasy.Scheduler
|
||||
{
|
||||
Log.Error(messageSender.Request != null
|
||||
? $"Unsupported protocol type {messageSender.Request.GetType()} rpcId:{rpcId} messageSender.Request != null"
|
||||
: $"Unsupported protocol type:{messageSender.MessageType} rpcId:{rpcId}");
|
||||
: $"Unsupported protocol type:{messageSender.MessageType.FullName} rpcId:{rpcId}");
|
||||
RequestCallback.Remove(rpcId);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ using Fantasy.PacketParser;
|
||||
using Fantasy.Helper;
|
||||
using Fantasy.InnerMessage;
|
||||
using Fantasy.Roaming;
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
#endif
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
@@ -126,7 +125,7 @@ namespace Fantasy.Scheduler
|
||||
{
|
||||
throw new Exception("OuterMessageScheduler error session does not have an AddressableRouteComponent component");
|
||||
}
|
||||
|
||||
|
||||
await addressableRouteComponent.Send(messageType, packInfo);
|
||||
}
|
||||
finally
|
||||
@@ -165,8 +164,7 @@ namespace Fantasy.Scheduler
|
||||
// session可能已经断开了,所以这里需要判断
|
||||
if (session.RuntimeId == runtimeId)
|
||||
{
|
||||
var responseType = MessageDispatcherComponent.GetOpCodeType(response.OpCode());
|
||||
session.Send(response, responseType, rpcId);
|
||||
session.Send(response, rpcId);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -186,9 +184,7 @@ namespace Fantasy.Scheduler
|
||||
|
||||
try
|
||||
{
|
||||
var routeType = MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode);
|
||||
|
||||
if (!routeType.HasValue)
|
||||
if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType))
|
||||
{
|
||||
throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");
|
||||
}
|
||||
@@ -207,7 +203,7 @@ namespace Fantasy.Scheduler
|
||||
throw new Exception($"OuterMessageScheduler CustomRouteType session does not have an routeComponent component messageType:{messageType.FullName} ProtocolCode:{packInfo.ProtocolCode}");
|
||||
}
|
||||
|
||||
if (!routeComponent.TryGetRouteId(routeType.Value, out var routeId))
|
||||
if (!routeComponent.TryGetRouteId(routeType, out var routeId))
|
||||
{
|
||||
throw new Exception($"OuterMessageScheduler RouteComponent cannot find RouteId with RouteType {routeType}");
|
||||
}
|
||||
@@ -231,9 +227,7 @@ namespace Fantasy.Scheduler
|
||||
|
||||
try
|
||||
{
|
||||
var routeType = MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode);
|
||||
|
||||
if (!routeType.HasValue)
|
||||
if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType))
|
||||
{
|
||||
throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");
|
||||
}
|
||||
@@ -252,7 +246,7 @@ namespace Fantasy.Scheduler
|
||||
throw new Exception("OuterMessageScheduler CustomRouteType session does not have an routeComponent component");
|
||||
}
|
||||
|
||||
if (!routeComponent.TryGetRouteId(routeType.Value, out var routeId))
|
||||
if (!routeComponent.TryGetRouteId(routeType, out var routeId))
|
||||
{
|
||||
throw new Exception($"OuterMessageScheduler RouteComponent cannot find RouteId with RouteType {routeType}");
|
||||
}
|
||||
@@ -263,8 +257,7 @@ namespace Fantasy.Scheduler
|
||||
// session可能已经断开了,所以这里需要判断
|
||||
if (session.RuntimeId == runtimeId)
|
||||
{
|
||||
var responseType = MessageDispatcherComponent.GetOpCodeType(response.OpCode());
|
||||
session.Send(response, responseType, rpcId);
|
||||
session.Send(response, rpcId);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -284,9 +277,7 @@ namespace Fantasy.Scheduler
|
||||
|
||||
try
|
||||
{
|
||||
var routeType = MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode);
|
||||
|
||||
if (!routeType.HasValue)
|
||||
if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType))
|
||||
{
|
||||
throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");
|
||||
}
|
||||
@@ -305,7 +296,7 @@ namespace Fantasy.Scheduler
|
||||
throw new Exception($"OuterMessageScheduler Roaming session does not have an sessionRoamingComponent component messageType:{messageType.FullName} ProtocolCode:{packInfo.ProtocolCode}");
|
||||
}
|
||||
|
||||
await sessionRoamingComponent.Send(routeType.Value, messageType, packInfo);
|
||||
await sessionRoamingComponent.Send(routeType, messageType, packInfo);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -324,9 +315,7 @@ namespace Fantasy.Scheduler
|
||||
|
||||
try
|
||||
{
|
||||
var routeType = MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode);
|
||||
|
||||
if (!routeType.HasValue)
|
||||
if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType))
|
||||
{
|
||||
throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");
|
||||
}
|
||||
@@ -347,12 +336,11 @@ namespace Fantasy.Scheduler
|
||||
|
||||
var rpcId = packInfo.RpcId;
|
||||
var runtimeId = session.RuntimeId;
|
||||
var response = await sessionRoamingComponent.Call(routeType.Value, messageType, packInfo);
|
||||
var response = await sessionRoamingComponent.Call(routeType, messageType, packInfo);
|
||||
// session可能已经断开了,所以这里需要判断
|
||||
if (session.RuntimeId == runtimeId)
|
||||
{
|
||||
var responseType = MessageDispatcherComponent.GetOpCodeType(response.OpCode());
|
||||
session.Send(response, responseType, rpcId);
|
||||
session.Send(response, rpcId);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -67,18 +67,19 @@ namespace Fantasy.Network.HTTP
|
||||
// 注册控制器服务
|
||||
var addControllers = builder.Services.AddControllers()
|
||||
.AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNamingPolicy = null; });
|
||||
foreach (var assemblyManifest in AssemblyManifest.GetAssemblyManifest)
|
||||
foreach (var assembly in AssemblySystem.ForEachAssembly)
|
||||
{
|
||||
addControllers.AddApplicationPart(assemblyManifest.Assembly);
|
||||
addControllers.AddApplicationPart(assembly);
|
||||
}
|
||||
var app = builder.Build();
|
||||
var listenUrl = $"http://{bindIp}:{port}/";
|
||||
var listenUrl = $"http://{bindIp}:{port}/";;
|
||||
app.Urls.Add(listenUrl);
|
||||
// 启用开发者工具
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
// 路由注册
|
||||
app.MapControllers();
|
||||
// 开启监听
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Fantasy.Network.Interface
|
||||
protected bool IsInit;
|
||||
public Session Session { get; protected set; }
|
||||
public abstract Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000);
|
||||
public abstract void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType);
|
||||
public abstract void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message);
|
||||
public override void Dispose()
|
||||
{
|
||||
IsInit = false;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Fantasy.Network.Interface
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType);
|
||||
public abstract void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -9,6 +9,6 @@ namespace Fantasy.Network.Interface
|
||||
{
|
||||
public Session Session { get;}
|
||||
public bool IsDisposed { get;}
|
||||
public void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType);
|
||||
public void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message);
|
||||
}
|
||||
}
|
||||
@@ -520,14 +520,14 @@ namespace Fantasy.Network.KCP
|
||||
private const byte KcpHeaderRequestConnection = (byte)KcpHeader.RequestConnection;
|
||||
private const byte KcpHeaderConfirmConnection = (byte)KcpHeader.ConfirmConnection;
|
||||
|
||||
public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType)
|
||||
public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message)
|
||||
{
|
||||
if (_cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message, messageType);
|
||||
|
||||
var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message);
|
||||
|
||||
if (!_isConnected)
|
||||
{
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Fantasy.Network.KCP
|
||||
}
|
||||
}
|
||||
|
||||
public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType)
|
||||
public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message)
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
@@ -120,7 +120,7 @@ namespace Fantasy.Network.KCP
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message, messageType);
|
||||
var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message);
|
||||
Kcp.Send(buffer.GetBuffer().AsSpan(0, (int)buffer.Position));
|
||||
|
||||
if (buffer.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack)
|
||||
|
||||
@@ -316,9 +316,9 @@ namespace Fantasy.Network.TCP
|
||||
|
||||
#region Send
|
||||
|
||||
public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message, Type messageType)
|
||||
public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message)
|
||||
{
|
||||
_sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message, messageType));
|
||||
_sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message));
|
||||
|
||||
if (!_isSending)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user