diff --git a/Config/Excel/Server/MachineConfig.xlsx b/Config/Excel/Server/MachineConfig.xlsx deleted file mode 100644 index 195d88d..0000000 Binary files a/Config/Excel/Server/MachineConfig.xlsx and /dev/null differ diff --git a/Config/Excel/Server/ProcessConfig.xlsx b/Config/Excel/Server/ProcessConfig.xlsx deleted file mode 100644 index ae71a9b..0000000 Binary files a/Config/Excel/Server/ProcessConfig.xlsx and /dev/null differ diff --git a/Config/Excel/Server/SceneConfig.xlsx b/Config/Excel/Server/SceneConfig.xlsx deleted file mode 100644 index e2fbd61..0000000 Binary files a/Config/Excel/Server/SceneConfig.xlsx and /dev/null differ diff --git a/Config/Excel/Server/WorldConfig.xlsx b/Config/Excel/Server/WorldConfig.xlsx deleted file mode 100644 index 110e58a..0000000 Binary files a/Config/Excel/Server/WorldConfig.xlsx and /dev/null differ diff --git a/Config/Excel/Server/~$MachineConfig.xlsx b/Config/Excel/Server/~$MachineConfig.xlsx deleted file mode 100644 index fd5ec18..0000000 Binary files a/Config/Excel/Server/~$MachineConfig.xlsx and /dev/null differ diff --git a/Config/Excel/Server/~$ProcessConfig.xlsx b/Config/Excel/Server/~$ProcessConfig.xlsx deleted file mode 100644 index fd5ec18..0000000 Binary files a/Config/Excel/Server/~$ProcessConfig.xlsx and /dev/null differ diff --git a/Config/Excel/Server/~$SceneConfig.xlsx b/Config/Excel/Server/~$SceneConfig.xlsx deleted file mode 100644 index fd5ec18..0000000 Binary files a/Config/Excel/Server/~$SceneConfig.xlsx and /dev/null differ diff --git a/Config/Excel/Server/~$WorldConfig.xlsx b/Config/Excel/Server/~$WorldConfig.xlsx deleted file mode 100644 index fd5ec18..0000000 Binary files a/Config/Excel/Server/~$WorldConfig.xlsx and /dev/null differ diff --git a/Config/Json/configs.json b/Config/Json/configs.json new file mode 100644 index 0000000..eb4f787 --- /dev/null +++ b/Config/Json/configs.json @@ -0,0 +1,433 @@ +{ + "WeightConfig": [ + { + "Id": 100001, + "Model": "Weights/Weight2_5g", + "Type": 0, + "Weight": 3 + } + ], + "RingConfig": [ + { + "Id": 120001, + "Model": "rod_rings/rumoi/rumoi_oxiline_spin" + }, + { + "Id": 120002, + "Model": "rod_rings/smt/smt_pure_ceramic_bolo" + } + ], + "LureConfig": [ + { + "Id": 80001, + "Model": "lures/express_fishing/crankbaits_1/775/crankbaits_775", + "Hook": [ + 700102 + ], + "EfficacyBase": 50, + "Length": 0, + "Weight": 250 + }, + { + "Id": 80002, + "Model": "lures/express_fishing/poppers_1/poppers_590/poppers_590", + "Hook": [ + 700102 + ], + "EfficacyBase": 50, + "Length": 0, + "Weight": 120 + }, + { + "Id": 80003, + "Model": "lures/express_fishing/softplastic/ef_supergrab_6/softplastic_g_1622", + "Hook": [ + 0 + ], + "EfficacyBase": 50, + "Length": 0, + "Weight": 120 + }, + { + "Id": 80004, + "Model": "lures/express_fishing/softplastic/ef_superminnow_6/softplastic_m_1634", + "Hook": [ + 0 + ], + "EfficacyBase": 50, + "Length": 0, + "Weight": 120 + } + ], + "ItemConfig": [ + { + "Id": 10001, + "Model": "rods/syberia/tele_10037/tele_10037_t13", + "Type": 1, + "Max": 0, + "AutoUse": 0 + }, + { + "Id": 10002, + "Model": "rods/syberia/bolo_10021/bolo_10021_LB400", + "Type": 0, + "Max": 1100002, + "AutoUse": 0 + }, + { + "Id": 10003, + "Model": "rods/syberia/spin_10034/spin_10034_S60H", + "Type": 0, + "Max": 1100001, + "AutoUse": 0 + } + ], + "ReelConfig": [ + { + "Id": 40001, + "Model": "reels/syberia/spin_5002/spin_5002", + "Type": 0, + "GearRatio": [ + "7" + ], + "Size": 250, + "Strength": 40 + }, + { + "Id": 40002, + "Model": "reels/syberia/spin_5036/spin_5036", + "Type": 0, + "GearRatio": [ + "5" + ], + "Size": 120, + "Strength": 40 + } + ], + "LineConfig": [ + { + "Id": 60001, + "Model": "Lines/UFE Mono/UFE monoClear", + "Type": 0, + "Length": 7, + "Strength": 40, + "Size": 1 + }, + { + "Id": 60002, + "Model": "rods/syberia/bolo_10021/bolo_10021_LB400", + "Type": 0, + "Length": 5, + "Strength": 40, + "Size": 1 + } + ], + "HookConfig": [ + { + "Id": 90001, + "Model": "hooks/alliance/c_hook_20789_20794/c_hook_20789", + "Type": 1, + "Zadzior": 1, + "Length": 0, + "Weight": 1 + }, + { + "Id": 90002, + "Model": "hooks/berserk_hooks/triple_20569_20577/triple_20569", + "Type": 1, + "Zadzior": 1, + "Length": 0, + "Weight": 1 + } + ], + "RodConfig": [ + { + "Id": 30001, + "Model": "rods/syberia/tele_10037/tele_10037_t13", + "Type": 1, + "Ring": 0, + "Length": 7, + "Weight": 250, + "Strength": 40, + "MaxRange": 67, + "ConstructionType": 0 + }, + { + "Id": 30002, + "Model": "rods/syberia/bolo_10021/bolo_10021_LB400", + "Type": 0, + "Ring": 1100002, + "Length": 5, + "Weight": 120, + "Strength": 40, + "MaxRange": 30, + "ConstructionType": 0 + }, + { + "Id": 30003, + "Model": "rods/syberia/spin_10034/spin_10034_S60H", + "Type": 0, + "Ring": 1100001, + "Length": 5, + "Weight": 120, + "Strength": 40, + "MaxRange": 30, + "ConstructionType": 0 + } + ], + "FishConfig": [ + { + "Id": 210001, + "Model": [ + "Burbot_B" + ], + "Type": 0, + "SpeciesName": 10, + "MinWeight": 1, + "MaxWeight": 34, + "Accept": 2100001 + }, + { + "Id": 210002, + "Model": [ + "CarpCommon_B" + ], + "Type": 0, + "SpeciesName": 11, + "MinWeight": 1, + "MaxWeight": 34, + "Accept": 2100001 + }, + { + "Id": 210003, + "Model": [ + "CarpGrass_B" + ], + "Type": 0, + "SpeciesName": 14, + "MinWeight": 1, + "MaxWeight": 34, + "Accept": 2100001 + }, + { + "Id": 210004, + "Model": [ + "CarpCrucian_B" + ], + "Type": 0, + "SpeciesName": 16, + "MinWeight": 1, + "MaxWeight": 34, + "Accept": 2100001 + } + ], + "BasicConfig": [ + { + "Id": 1001, + "Name": "Weights/Weight2_5g", + "Val": [ + "0" + ] + } + ], + "InitConfig": [ + { + "Id": 1, + "ItemId": 30001, + "Amount": 1 + }, + { + "Id": 2, + "ItemId": 30002, + "Amount": 1 + }, + { + "Id": 3, + "ItemId": 30003, + "Amount": 1 + }, + { + "Id": 4, + "ItemId": 40001, + "Amount": 1 + }, + { + "Id": 5, + "ItemId": 50001, + "Amount": 1 + }, + { + "Id": 6, + "ItemId": 50002, + "Amount": 1 + }, + { + "Id": 7, + "ItemId": 50003, + "Amount": 1 + }, + { + "Id": 8, + "ItemId": 60001, + "Amount": 1 + }, + { + "Id": 9, + "ItemId": 70001, + "Amount": 1 + }, + { + "Id": 10, + "ItemId": 70002, + "Amount": 1 + }, + { + "Id": 11, + "ItemId": 80001, + "Amount": 1 + }, + { + "Id": 12, + "ItemId": 80002, + "Amount": 1 + }, + { + "Id": 13, + "ItemId": 80003, + "Amount": 1 + }, + { + "Id": 14, + "ItemId": 80004, + "Amount": 1 + }, + { + "Id": 15, + "ItemId": 90001, + "Amount": 1 + }, + { + "Id": 16, + "ItemId": 100001, + "Amount": 1 + }, + { + "Id": 17, + "ItemId": 10001, + "Amount": 100 + }, + { + "Id": 18, + "ItemId": 10002, + "Amount": 200 + } + ], + "BobberConfig": [ + { + "Id": 50001, + "Model": "bobbers/expressfishing/bob_25003/bob_25003", + "Type": 2, + "Weight": 1, + "Displacement": 40, + "NightLight": 0 + }, + { + "Id": 50002, + "Model": "bobbers/expressfishing/bob_25162_25163/bob_25162", + "Type": 0, + "Weight": 1, + "Displacement": 40, + "NightLight": 0 + }, + { + "Id": 50003, + "Model": "bobbers/expressfishing/bob_25166_25167/bob_25166", + "Type": 0, + "Weight": 1, + "Displacement": 40, + "NightLight": 0 + }, + { + "Id": 50004, + "Model": "bobbers/expressfishing/bob_25001/bob_25001", + "Type": 0, + "Weight": 1, + "Displacement": 40, + "NightLight": 0 + } + ], + "FeederConfig": [ + { + "Id": 110001, + "Model": "Feeders/Feeder 1/FeedTrash 1", + "Type": 0, + "Capacity": 100, + "Weight": 5 + } + ], + "BaitConfig": [ + { + "Id": 70001, + "Model": "baits/worm_01/worm_01", + "EfficacyBase": 15, + "Length": 0, + "Weight": 250, + "Arr": [ + 250, + 1, + 2, + 3 + ], + "ArrStr": [ + "d", + "a", + "bb", + "e|12" + ] + }, + { + "Id": 70002, + "Model": "baits/fly/fly", + "EfficacyBase": 15, + "Length": 0, + "Weight": 120, + "Arr": [ + 120, + 4, + 3 + ], + "ArrStr": [ + "120", + "4", + "3" + ] + }, + { + "Id": 70003, + "Model": "baits/black_leech/black_leech", + "EfficacyBase": 15, + "Length": 0, + "Weight": 120, + "Arr": [ + 120 + ], + "ArrStr": [ + "kkk" + ] + }, + { + "Id": 70004, + "Model": "baits/bread/bread", + "EfficacyBase": 15, + "Length": 0, + "Weight": 120, + "Arr": [ + 120 + ], + "ArrStr": [ + "11|33", + "44|2" + ] + } + ] +} \ No newline at end of file diff --git a/Config/NetworkProtocol/Outer/GameMessage.proto b/Config/NetworkProtocol/Outer/GameMessage.proto index c47bc71..3dea31f 100644 --- a/Config/NetworkProtocol/Outer/GameMessage.proto +++ b/Config/NetworkProtocol/Outer/GameMessage.proto @@ -35,6 +35,22 @@ message Game2C_ItemChange // ICustomRouteMessage,GameRoute repeated int64 Removes = 3; //移除物品(移除时有) } +////////////// ******** 钓组 *******///////////// + +///请求安装或取下配件 +message C2Game_RigChangeRequest // ICustomRouteRequest,Game2C_RigChangeResponse,GameRoute +{ + int64 RodId = 1;//杆子id + int64 RigId = 2;//变更的配件 + bool IsAdd = 3;//是否添加 +} + +///请求安装配件响应 +message Game2C_RigChangeResponse // ICustomRouteResponse +{ + ItemBindInfo Rigs = 1; //变化钓组信息 +} + ////////////// ******** 鱼护 *******///////////// diff --git a/Config/NetworkProtocol/Outer/data/CommonProtoData.proto b/Config/NetworkProtocol/Outer/data/CommonProtoData.proto index ffe4920..0af1c58 100644 --- a/Config/NetworkProtocol/Outer/data/CommonProtoData.proto +++ b/Config/NetworkProtocol/Outer/data/CommonProtoData.proto @@ -9,8 +9,7 @@ message RoleBaseInfo string Country = 3; //国家 int32 Level = 4; //等级 int32 Exp = 5; //当前等级 - bool Vip = 6; //是否vip - VipInfo VipInfo = 7; //vip信息 + VipInfo VipInfo = 6; //vip信息 } @@ -45,15 +44,16 @@ message RoleSimpleInfo string Head = 3; //头像 string Country = 4; //国家 int32 Level = 5; //等级 - bool Vip = 6; //是否vip + int32 Vip = 6; //vip级别 int32 MapId = 7; //当前所在地图 } /// VIP信息 message VipInfo { - int64 OpenTime = 1; //开通时间 - int64 ExpirationTime = 2; //到期时间 + int32 Level = 1; //VIP信息 + int64 OpenTime = 2; //开通时间 + int64 ExpirationTime = 3; //到期时间 } diff --git a/Entity/Entity.csproj b/Entity/Entity.csproj index 8e26470..5a06389 100644 --- a/Entity/Entity.csproj +++ b/Entity/Entity.csproj @@ -29,6 +29,9 @@ + + + diff --git a/Entity/Game/Cache/PlayerBasicCache.cs b/Entity/Game/Cache/PlayerBasicCache.cs index 8205f08..af6a76a 100644 --- a/Entity/Game/Cache/PlayerBasicCache.cs +++ b/Entity/Game/Cache/PlayerBasicCache.cs @@ -29,7 +29,7 @@ public class PlayerBasicCache : Entity /// /// 是否是vip /// - public bool IsVip; + public int Vip; /// /// 缓存失效时间 diff --git a/Entity/Game/Item/Item.cs b/Entity/Game/Item/Item.cs index 57d0571..d70a420 100644 --- a/Entity/Game/Item/Item.cs +++ b/Entity/Game/Item/Item.cs @@ -3,12 +3,12 @@ using MongoDB.Bson.Serialization.Attributes; namespace NB.Game; -public enum ItemType +public enum ItemBasicType { - None = 0, - Item, - Equip, - Fish, + None, + Currency = 1, + Item = 2, + Fish = 3, } public class Item : Entity @@ -21,7 +21,7 @@ public class Item : Entity /// /// 配置id /// - [BsonElement("cid")] public int ConfigId; + [BsonElement("cid")] public uint ConfigId; /// /// 是否绑定 @@ -46,5 +46,5 @@ public class Item : Entity /// /// 物品所属的容器 /// - [BsonIgnore] PlayerItemContainer Container; + [BsonIgnore] PlayerItemContainerComponent Container; } \ No newline at end of file diff --git a/Entity/Game/Item/PlayerItemContainer.cs b/Entity/Game/Item/PlayerItemContainerComponent.cs similarity index 61% rename from Entity/Game/Item/PlayerItemContainer.cs rename to Entity/Game/Item/PlayerItemContainerComponent.cs index eb41e01..050b78f 100644 --- a/Entity/Game/Item/PlayerItemContainer.cs +++ b/Entity/Game/Item/PlayerItemContainerComponent.cs @@ -6,7 +6,7 @@ using NB.Game; namespace NB; -public sealed class PlayerItemContainer : Entity +public sealed class PlayerItemContainerComponent : Entity { /// /// 最大格子数量 @@ -24,14 +24,4 @@ public sealed class PlayerItemContainer : Entity /// [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] public Dictionary> FishingRig = new Dictionary>(); - - // /// - // /// 按物品id分组 - // /// - // [BsonIgnore] public readonly OneToManyList ItemsByConfigId = new OneToManyListPool(); - // - // /// - // /// 容器内按物品类型分组 - // /// - // [BsonIgnore] public readonly OneToManyList ItemsByType = new OneToManyListPool(); } \ No newline at end of file diff --git a/Entity/Game/Player/Player.cs b/Entity/Game/Player/Player.cs index e662cb6..bd2dbd6 100644 --- a/Entity/Game/Player/Player.cs +++ b/Entity/Game/Player/Player.cs @@ -34,7 +34,7 @@ public sealed class Player : Entity /// 当前经验 /// [BsonElement("exp")] public int Exp; - + /// /// 星数 @@ -47,41 +47,20 @@ public sealed class Player : Entity [BsonElement("high")] public int Highlight; /// - /// 角色vip信息 + /// vip状态 /// - [BsonElement("vInfo")] public PlayerVip Vip; + [BsonElement("vip")] public int Vip; /// - /// 钱包 + /// 获取时间 /// - [BsonElement("wallet")] public PlayerWallet Wallet; + [BsonElement("vTime")] public long VipGetTime; /// - /// 背包 + /// 失效时间 /// - [BsonElement("bag")] public PlayerItemContainer ItemContainer; + [BsonElement("vExTime")] public long VipExpirationTime; - /// - /// 鱼护 - /// - [BsonElement("fish")] public FishContainer FishContainer; - - /// - /// 技能 - /// - [BsonElement("skill")] public SkillContainer SkillContainer; - - /// - /// 成就 - /// - [BsonElement("achievement")] public AchievementContainer AchievementContainer; - - /// - /// 是否是vip - /// - [BsonIgnore] - public bool IsVip => Vip != null && Vip.ExpirationTime > TimeHelper.Now; [BsonIgnore] public long SessionRunTimeId; - } \ No newline at end of file diff --git a/Entity/Game/Player/PlayerWallet.cs b/Entity/Game/Player/PlayerWalletComponent.cs similarity index 53% rename from Entity/Game/Player/PlayerWallet.cs rename to Entity/Game/Player/PlayerWalletComponent.cs index c4ee134..0682333 100644 --- a/Entity/Game/Player/PlayerWallet.cs +++ b/Entity/Game/Player/PlayerWalletComponent.cs @@ -7,21 +7,11 @@ namespace NB.Game; /// /// 用户钱包 /// -public class PlayerWallet : Entity +public class PlayerWalletComponent : Entity { /// - /// 余额 - /// - public int Money; - - /// - /// 金币 - /// - public int Gold; - - /// - /// 其他货币 + /// 所有货币 /// [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] - public Dictionary Other = new(); + public Dictionary Currency = new(); } \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/BaitConfig.cs b/Entity/Generate/ConfigTable/Entity/BaitConfig.cs index 54a1f1c..45e4c9d 100644 --- a/Entity/Generate/ConfigTable/Entity/BaitConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/BaitConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class BaitConfigData : ASerialize, IConfigTable, IProto + public sealed partial class BaitConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static BaitConfigData _instance = null; - - public static BaitConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public BaitConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"BaitConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out BaitConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class BaitConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -96,6 +23,71 @@ namespace Fantasy [ProtoMember(4)] public uint Length { get; set; } // 长度(毫米) [ProtoMember(5)] - public uint Weight { get; set; } // 重量(克) - } -} \ No newline at end of file + public uint Weight { get; set; } // 重量(克) + [ProtoMember(6)] + public uint[] Arr { get; set; } = Array.Empty(); // 重量(克) + [ProtoMember(7)] + public string[] ArrStr { get; set; } = Array.Empty(); // 重量(克) + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static BaitConfig Get(uint key) + { + return Context.Get(key); + } + + public static BaitConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static BaitConfig Fist() + { + return Context.Fist(); + } + + public static BaitConfig Last() + { + return Context.Last(); + } + + public static BaitConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static BaitConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/BasicConfig.cs b/Entity/Generate/ConfigTable/Entity/BasicConfig.cs new file mode 100644 index 0000000..a9a9cbb --- /dev/null +++ b/Entity/Generate/ConfigTable/Entity/BasicConfig.cs @@ -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 BasicConfig : ASerialize, IProto, IConfigTable + { + + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 参数名 + [ProtoMember(3)] + public string[] Val { get; set; } = Array.Empty(); // 参数值 + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static BasicConfig Get(uint key) + { + return Context.Get(key); + } + + public static BasicConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static BasicConfig Fist() + { + return Context.Fist(); + } + + public static BasicConfig Last() + { + return Context.Last(); + } + + public static BasicConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static BasicConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/BobberConfig.cs b/Entity/Generate/ConfigTable/Entity/BobberConfig.cs index 8afe79f..c752882 100644 --- a/Entity/Generate/ConfigTable/Entity/BobberConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/BobberConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class BobberConfigData : ASerialize, IConfigTable, IProto + public sealed partial class BobberConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static BobberConfigData _instance = null; - - public static BobberConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public BobberConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"BobberConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out BobberConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class BobberConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -99,5 +26,66 @@ namespace Fantasy public uint Displacement { get; set; } // 位移 [ProtoMember(6)] public uint NightLight { get; set; } // 是否夜光 - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static BobberConfig Get(uint key) + { + return Context.Get(key); + } + + public static BobberConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static BobberConfig Fist() + { + return Context.Fist(); + } + + public static BobberConfig Last() + { + return Context.Last(); + } + + public static BobberConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static BobberConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/FeederConfig.cs b/Entity/Generate/ConfigTable/Entity/FeederConfig.cs index 7d092aa..83df9d8 100644 --- a/Entity/Generate/ConfigTable/Entity/FeederConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/FeederConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class FeederConfigData : ASerialize, IConfigTable, IProto + public sealed partial class FeederConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static FeederConfigData _instance = null; - - public static FeederConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public FeederConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"FeederConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out FeederConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class FeederConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -97,5 +24,66 @@ namespace Fantasy public uint Capacity { get; set; } // 能力 [ProtoMember(5)] public uint Weight { get; set; } // 重量(克) - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static FeederConfig Get(uint key) + { + return Context.Get(key); + } + + public static FeederConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static FeederConfig Fist() + { + return Context.Fist(); + } + + public static FeederConfig Last() + { + return Context.Last(); + } + + public static FeederConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static FeederConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/FishConfig.cs b/Entity/Generate/ConfigTable/Entity/FishConfig.cs index 2ed0c08..ed434cf 100644 --- a/Entity/Generate/ConfigTable/Entity/FishConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/FishConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class FishConfigData : ASerialize, IConfigTable, IProto + public sealed partial class FishConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static FishConfigData _instance = null; - - public static FishConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public FishConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"FishConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out FishConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class FishConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -101,5 +28,66 @@ namespace Fantasy public uint MaxWeight { get; set; } // 最大重量(克) [ProtoMember(7)] public uint Accept { get; set; } // 接受饵 - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static FishConfig Get(uint key) + { + return Context.Get(key); + } + + public static FishConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static FishConfig Fist() + { + return Context.Fist(); + } + + public static FishConfig Last() + { + return Context.Last(); + } + + public static FishConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static FishConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/HookConfig.cs b/Entity/Generate/ConfigTable/Entity/HookConfig.cs index 98722e1..5350f5f 100644 --- a/Entity/Generate/ConfigTable/Entity/HookConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/HookConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class HookConfigData : ASerialize, IConfigTable, IProto + public sealed partial class HookConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static HookConfigData _instance = null; - - public static HookConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public HookConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"HookConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out HookConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class HookConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -99,5 +26,66 @@ namespace Fantasy public uint Length { get; set; } // 长度(毫米) [ProtoMember(6)] public uint Weight { get; set; } // 重量(克) - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static HookConfig Get(uint key) + { + return Context.Get(key); + } + + public static HookConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static HookConfig Fist() + { + return Context.Fist(); + } + + public static HookConfig Last() + { + return Context.Last(); + } + + public static HookConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static HookConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/InitConfig.cs b/Entity/Generate/ConfigTable/Entity/InitConfig.cs new file mode 100644 index 0000000..b67b530 --- /dev/null +++ b/Entity/Generate/ConfigTable/Entity/InitConfig.cs @@ -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 InitConfig : ASerialize, IProto, IConfigTable + { + + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public uint ItemId { get; set; } // 物品Id + [ProtoMember(3)] + public int Amount { get; set; } // 数量 + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static InitConfig Get(uint key) + { + return Context.Get(key); + } + + public static InitConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static InitConfig Fist() + { + return Context.Fist(); + } + + public static InitConfig Last() + { + return Context.Last(); + } + + public static InitConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static InitConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/ItemConfig.cs b/Entity/Generate/ConfigTable/Entity/ItemConfig.cs new file mode 100644 index 0000000..69760bb --- /dev/null +++ b/Entity/Generate/ConfigTable/Entity/ItemConfig.cs @@ -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 ItemConfig : ASerialize, IProto, IConfigTable + { + + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Model { get; set; } // 模型 + [ProtoMember(3)] + public uint Type { get; set; } // 类型 + [ProtoMember(4)] + public uint Max { get; set; } // 最大堆叠数量 + [ProtoMember(5)] + public uint AutoUse { get; set; } // 获得自动使用 + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static ItemConfig Get(uint key) + { + return Context.Get(key); + } + + public static ItemConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static ItemConfig Fist() + { + return Context.Fist(); + } + + public static ItemConfig Last() + { + return Context.Last(); + } + + public static ItemConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static ItemConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/LineConfig.cs b/Entity/Generate/ConfigTable/Entity/LineConfig.cs index 1399198..afb75f2 100644 --- a/Entity/Generate/ConfigTable/Entity/LineConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/LineConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class LineConfigData : ASerialize, IConfigTable, IProto + public sealed partial class LineConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static LineConfigData _instance = null; - - public static LineConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public LineConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"LineConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out LineConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class LineConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -99,5 +26,66 @@ namespace Fantasy public uint Strength { get; set; } // 强度 [ProtoMember(6)] public uint Size { get; set; } // 尺寸 - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static LineConfig Get(uint key) + { + return Context.Get(key); + } + + public static LineConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static LineConfig Fist() + { + return Context.Fist(); + } + + public static LineConfig Last() + { + return Context.Last(); + } + + public static LineConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static LineConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/LureConfig.cs b/Entity/Generate/ConfigTable/Entity/LureConfig.cs index 764f5d2..f7b696e 100644 --- a/Entity/Generate/ConfigTable/Entity/LureConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/LureConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class LureConfigData : ASerialize, IConfigTable, IProto + public sealed partial class LureConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static LureConfigData _instance = null; - - public static LureConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public LureConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"LureConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out LureConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class LureConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -99,5 +26,66 @@ namespace Fantasy public uint Length { get; set; } // 长度(毫米) [ProtoMember(6)] public uint Weight { get; set; } // 重量(克) - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static LureConfig Get(uint key) + { + return Context.Get(key); + } + + public static LureConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static LureConfig Fist() + { + return Context.Fist(); + } + + public static LureConfig Last() + { + return Context.Last(); + } + + public static LureConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static LureConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/ReelConfig.cs b/Entity/Generate/ConfigTable/Entity/ReelConfig.cs index 16e0839..3c96a82 100644 --- a/Entity/Generate/ConfigTable/Entity/ReelConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/ReelConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class ReelConfigData : ASerialize, IConfigTable, IProto + public sealed partial class ReelConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static ReelConfigData _instance = null; - - public static ReelConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public ReelConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"ReelConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out ReelConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class ReelConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -99,5 +26,66 @@ namespace Fantasy public uint Size { get; set; } // 尺寸 [ProtoMember(6)] public uint Strength { get; set; } // 强度 - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static ReelConfig Get(uint key) + { + return Context.Get(key); + } + + public static ReelConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static ReelConfig Fist() + { + return Context.Fist(); + } + + public static ReelConfig Last() + { + return Context.Last(); + } + + public static ReelConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static ReelConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/RingConfig.cs b/Entity/Generate/ConfigTable/Entity/RingConfig.cs index a0e39c6..8627804 100644 --- a/Entity/Generate/ConfigTable/Entity/RingConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/RingConfig.cs @@ -5,91 +5,79 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class RingConfigData : ASerialize, IConfigTable, IProto + public sealed partial class RingConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static RingConfigData _instance = null; - - public static RingConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public RingConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"RingConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out RingConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class RingConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] public string Model { get; set; } // 模型 - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static RingConfig Get(uint key) + { + return Context.Get(key); + } + + public static RingConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static RingConfig Fist() + { + return Context.Fist(); + } + + public static RingConfig Last() + { + return Context.Last(); + } + + public static RingConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static RingConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/RodConfig.cs b/Entity/Generate/ConfigTable/Entity/RodConfig.cs index 2fabc5e..b21e903 100644 --- a/Entity/Generate/ConfigTable/Entity/RodConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/RodConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class RodConfigData : ASerialize, IConfigTable, IProto + public sealed partial class RodConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static RodConfigData _instance = null; - - public static RodConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public RodConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"RodConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out RodConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class RodConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -105,5 +32,66 @@ namespace Fantasy public uint MaxRange { get; set; } // 最大范围 [ProtoMember(9)] public uint ConstructionType { get; set; } // 结构类型 - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static RodConfig Get(uint key) + { + return Context.Get(key); + } + + public static RodConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static RodConfig Fist() + { + return Context.Fist(); + } + + public static RodConfig Last() + { + return Context.Last(); + } + + public static RodConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static RodConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/UnitConfig.cs b/Entity/Generate/ConfigTable/Entity/UnitConfig.cs deleted file mode 100644 index c0f11d9..0000000 --- a/Entity/Generate/ConfigTable/Entity/UnitConfig.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using ProtoBuf; -using Fantasy; -using System.Linq; -using System.Reflection; -using System.Collections.Generic; -using System.Collections.Concurrent; -using Fantasy.ConfigTable; -using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 - -namespace Fantasy -{ - [ProtoContract] - public sealed partial class UnitConfigData : ASerialize, IConfigTable, IProto - { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static UnitConfigData _instance = null; - - public static UnitConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public UnitConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - - if (check) - { - throw new Exception($"UnitConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out UnitConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class UnitConfig : ASerialize, IProto - { - [ProtoMember(1)] - public uint Id { get; set; } // Id - [ProtoMember(2)] - public string Name { get; set; } // 名称 - [ProtoMember(3)] - public string Model { get; set; } // 数据库类型 - [ProtoMember(4)] - public StringDictionaryConfig Dic { get; set; } // 字典类型 - } -} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Entity/WeightConfig.cs b/Entity/Generate/ConfigTable/Entity/WeightConfig.cs index c372e52..fc0d498 100644 --- a/Entity/Generate/ConfigTable/Entity/WeightConfig.cs +++ b/Entity/Generate/ConfigTable/Entity/WeightConfig.cs @@ -5,88 +5,15 @@ using System.Linq; using System.Reflection; using System.Collections.Generic; using System.Collections.Concurrent; -using Fantasy.ConfigTable; using Fantasy.Serialize; -// ReSharper disable CollectionNeverUpdated.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable CS0169 -#pragma warning disable CS8618 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +using Fantasy.ConfigTable; -namespace Fantasy +namespace NBF { [ProtoContract] - public sealed partial class WeightConfigData : ASerialize, IConfigTable, IProto + public sealed partial class WeightConfig : ASerialize, IProto, IConfigTable { - [ProtoMember(1)] - public List List { get; set; } = new List(); -#if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); -#else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); -#endif - private static WeightConfigData _instance = null; - - public static WeightConfigData Instance - { - get { return _instance ??= ConfigTableHelper.Load(); } - private set => _instance = value; - } - - public WeightConfig Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - if (check) - { - throw new Exception($"WeightConfig not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out WeightConfig config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { -#if FANTASY_NET - _configs.TryAdd(config.Id, config); -#else - _configs.Add(config.Id, config); -#endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class WeightConfig : ASerialize, IProto - { [ProtoMember(1)] public uint Id { get; set; } // Id [ProtoMember(2)] @@ -95,5 +22,66 @@ namespace Fantasy public uint Type { get; set; } // 类型 [ProtoMember(4)] public uint Weight { get; set; } // 重量(克) - } -} \ No newline at end of file + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext Context => ConfigTableHelper.Table(); + + public static WeightConfig Get(uint key) + { + return Context.Get(key); + } + + public static WeightConfig Get(Predicate match) + { + return Context.Get(match); + } + + public static WeightConfig Fist() + { + return Context.Fist(); + } + + public static WeightConfig Last() + { + return Context.Last(); + } + + public static WeightConfig Fist(Predicate match) + { + return Context.Fist(match); + } + + public static WeightConfig Last(Predicate match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func predicate) + { + return Context.Count(predicate); + } + + public static List GetList() + { + return Context.GetList(); + } + + public static List GetList(Predicate match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Entity/Generate/ConfigTable/Partial/UnitConfigData.cs b/Entity/Generate/ConfigTable/Partial/UnitConfigData.cs deleted file mode 100644 index 36e9c93..0000000 --- a/Entity/Generate/ConfigTable/Partial/UnitConfigData.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Fantasy; - -public sealed partial class UnitConfigData -{ - public override void EndInit() - { - Log.Debug("UnitConfigData EndInit"); - base.EndInit(); - } -} \ No newline at end of file diff --git a/Entity/Generate/NetworkProtocol/CommonProtoData.cs b/Entity/Generate/NetworkProtocol/CommonProtoData.cs index 4b8ed66..5198cd9 100644 --- a/Entity/Generate/NetworkProtocol/CommonProtoData.cs +++ b/Entity/Generate/NetworkProtocol/CommonProtoData.cs @@ -34,7 +34,6 @@ namespace Fantasy Country = default; Level = default; Exp = default; - Vip = default; VipInfo = default; #if FANTASY_NET || FANTASY_UNITY GetScene().MessagePoolComponent.Return(this); @@ -51,8 +50,6 @@ namespace Fantasy [ProtoMember(5)] public int Exp { get; set; } [ProtoMember(6)] - public bool Vip { get; set; } - [ProtoMember(7)] public VipInfo VipInfo { get; set; } } [ProtoContract] @@ -156,7 +153,7 @@ namespace Fantasy [ProtoMember(5)] public int Level { get; set; } [ProtoMember(6)] - public bool Vip { get; set; } + public int Vip { get; set; } [ProtoMember(7)] public int MapId { get; set; } } @@ -172,6 +169,7 @@ namespace Fantasy } public override void Dispose() { + Level = default; OpenTime = default; ExpirationTime = default; #if FANTASY_NET || FANTASY_UNITY @@ -179,8 +177,10 @@ namespace Fantasy #endif } [ProtoMember(1)] - public long OpenTime { get; set; } + public int Level { get; set; } [ProtoMember(2)] + public long OpenTime { get; set; } + [ProtoMember(3)] public long ExpirationTime { get; set; } } /// diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj b/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj index 732718c..be19e19 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj @@ -40,15 +40,10 @@ - - - + + - - - - - + @@ -58,4 +53,8 @@ + + + + diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs index afb7f09..49948f4 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs @@ -92,11 +92,6 @@ namespace Fantasy.DataBase return data == null ? 0 : Convert.ToInt64(data["Result"]); } - /// - /// Mongo 注释 - /// - public MongoClient Client => _mongoClient; - #endregion #region GetCollection diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs index 4644274..fe03298 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs @@ -82,7 +82,7 @@ namespace Fantasy.Async /// /// /// - public void Release(int coroutineLockType, long coroutineLockQueueKey) + public void Release(long coroutineLockType, long coroutineLockQueueKey) { if (IsDisposed) { diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs index b367448..67dc9ef 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs @@ -67,11 +67,15 @@ namespace Fantasy.Entitas return HashCode.Combine(CustomEventType, EntitiesType); } } - + /// /// Entity管理组件 /// +#if FANTASY_UNITY + public sealed class EntityComponent : Entity, ISceneUpdate, ISceneLateUpdate, IAssembly +#else public sealed class EntityComponent : Entity, ISceneUpdate, IAssembly +#endif { private readonly OneToManyList _assemblyList = new(); private readonly OneToManyList _assemblyHashCodes = new(); @@ -80,15 +84,19 @@ namespace Fantasy.Entitas private readonly Dictionary _updateSystems = new(); private readonly Dictionary _destroySystems = new(); private readonly Dictionary _deserializeSystems = new(); - private readonly Dictionary _frameUpdateSystem = new(); private readonly OneToManyList _assemblyCustomSystemList = new(); private readonly Dictionary _customEntitiesSystems = new Dictionary(); private readonly Dictionary _hashCodes = new Dictionary(); private readonly Queue _updateQueue = new Queue(); - private readonly Queue _frameUpdateQueue = new Queue(); + private readonly Dictionary _updateQueueDic = new Dictionary(); +#if FANTASY_UNITY + private readonly Dictionary _lateUpdateSystems = new(); + private readonly Queue _lateUpdateQueue = new Queue(); + private readonly Dictionary _lateUpdateQueueDic = new Dictionary(); +#endif internal async FTask Initialize() { @@ -157,10 +165,6 @@ namespace Fantasy.Entitas case IDestroySystem iDestroySystem: { entitiesType = iDestroySystem.EntitiesType(); - if (_destroySystems.ContainsKey(entitiesType)) - { - - } _destroySystems.Add(entitiesType, iDestroySystem); break; } @@ -176,12 +180,14 @@ namespace Fantasy.Entitas _updateSystems.Add(entitiesType, iUpdateSystem); break; } - case IFrameUpdateSystem iFrameUpdateSystem: +#if FANTASY_UNITY + case ILateUpdateSystem iLateUpdateSystem: { - entitiesType = iFrameUpdateSystem.EntitiesType(); - _frameUpdateSystem.Add(entitiesType, iFrameUpdateSystem); + entitiesType = iLateUpdateSystem.EntitiesType(); + _lateUpdateSystems.Add(entitiesType, iLateUpdateSystem); break; - } + } +#endif default: { Log.Error($"IEntitiesSystem not support type {entitiesSystemType}"); @@ -220,10 +226,12 @@ namespace Fantasy.Entitas _awakeSystems.Remove(type); _updateSystems.Remove(type); _destroySystems.Remove(type); +#if FANTASY_UNITY + _lateUpdateSystems.Remove(type); +#endif _deserializeSystems.Remove(type); - _frameUpdateSystem.Remove(type); } - + _assemblyList.RemoveByKey(assemblyIdentity); } @@ -333,7 +341,7 @@ namespace Fantasy.Entitas #region Update /// - /// 将实体加入更新队列,准备进行更新 + /// 将实体加入Update队列,准备进行Update /// /// 实体对象 public void StartUpdate(Entity entity) @@ -341,21 +349,18 @@ namespace Fantasy.Entitas var type = entity.Type; var entityRuntimeId = entity.RuntimeId; - if (_updateSystems.ContainsKey(type)) + if (!_updateSystems.ContainsKey(type)) { - var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId); - _updateQueue.Enqueue(updateQueueInfo); - _updateQueueDic.Add(entityRuntimeId, updateQueueInfo); - } - - if (_frameUpdateSystem.ContainsKey(type)) - { - _frameUpdateQueue.Enqueue(new FrameUpdateQueueInfo(type, entityRuntimeId)); + return; } + + var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId); + _updateQueue.Enqueue(updateQueueInfo); + _updateQueueDic.Add(entityRuntimeId, updateQueueInfo); } /// - /// 停止实体进行更新 + /// 停止实体Update /// /// 实体对象 public void StopUpdate(Entity entity) @@ -369,7 +374,7 @@ namespace Fantasy.Entitas } /// - /// 执行实体系统的更新逻辑 + /// 执行实体系统的Update /// public void Update() { @@ -410,44 +415,84 @@ namespace Fantasy.Entitas } } - /// - /// 执行实体系统的帧更新逻辑 - /// - public void FrameUpdate() - { - var count = _frameUpdateQueue.Count; + #endregion - while (count-- > 0) +#if FANTASY_UNITY + #region LateUpdate + + /// + /// 将实体加入LateUpdate队列,准备进行LateUpdate + /// + /// 实体对象 + public void StartLateUpdate(Entity entity) + { + var type = entity.Type; + var entityRuntimeId = entity.RuntimeId; + + if (!_lateUpdateSystems.ContainsKey(type)) { - var frameUpdateQueueStruct = _frameUpdateQueue.Dequeue(); - - if (!_frameUpdateSystem.TryGetValue(frameUpdateQueueStruct.Type, out var frameUpdateSystem)) + return; + } + + var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId); + _lateUpdateQueue.Enqueue(updateQueueInfo); + _lateUpdateQueueDic.Add(entityRuntimeId, updateQueueInfo); + } + + /// + /// 停止实体进行LateUpdate + /// + /// 实体对象 + 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; } - var entity = Scene.GetEntity(frameUpdateQueueStruct.RunTimeId); - + 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; } - - _frameUpdateQueue.Enqueue(frameUpdateQueueStruct); - + + _lateUpdateQueue.Enqueue(lateUpdateQueueStruct); + try { - frameUpdateSystem.Invoke(entity); + lateUpdateSystem.Invoke(entity); } catch (Exception e) { - Log.Error($"{frameUpdateQueueStruct.Type.FullName} FrameUpdate Error {e}"); + Log.Error($"{lateUpdateQueueStruct.Type.FullName} Update Error {e}"); } } } - #endregion - +#endif public long GetHashCode(Type type) { return _hashCodes[type]; @@ -459,14 +504,17 @@ namespace Fantasy.Entitas public override void Dispose() { _updateQueue.Clear(); - _frameUpdateQueue.Clear(); - + _updateQueueDic.Clear(); +#if FANTASY_UNITY + _lateUpdateQueue.Clear(); + _lateUpdateQueueDic.Clear(); + _lateUpdateSystems.Clear(); +#endif _assemblyList.Clear(); _awakeSystems.Clear(); _updateSystems.Clear(); _destroySystems.Clear(); _deserializeSystems.Clear(); - _frameUpdateSystem.Clear(); AssemblySystem.UnRegister(this); base.Dispose(); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Entity.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Entity.cs index 0458cca..99faad7 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Entity.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Entity.cs @@ -169,6 +169,9 @@ namespace Fantasy.Entitas { scene.EntityComponent.Awake(entity); scene.EntityComponent.StartUpdate(entity); +#if FANTASY_UNITY + scene.EntityComponent.StartLateUpdate(entity); +#endif } return entity; @@ -210,6 +213,9 @@ namespace Fantasy.Entitas { scene.EntityComponent.Awake(entity); scene.EntityComponent.StartUpdate(entity); +#if FANTASY_UNITY + scene.EntityComponent.StartLateUpdate(entity); +#endif } return entity; @@ -232,6 +238,9 @@ namespace Fantasy.Entitas AddComponent(entity); Scene.EntityComponent.Awake(entity); Scene.EntityComponent.StartUpdate(entity); +#if FANTASY_UNITY + Scene.EntityComponent.StartLateUpdate(entity); +#endif return entity; } @@ -248,6 +257,9 @@ namespace Fantasy.Entitas AddComponent(entity); Scene.EntityComponent.Awake(entity); Scene.EntityComponent.StartUpdate(entity); +#if FANTASY_UNITY + Scene.EntityComponent.StartLateUpdate(entity); +#endif return entity; } @@ -406,6 +418,9 @@ namespace Fantasy.Entitas AddComponent(entity); Scene.EntityComponent.Awake(entity); Scene.EntityComponent.StartUpdate(entity); +#if FANTASY_UNITY + Scene.EntityComponent.StartLateUpdate(entity); +#endif return entity; } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/ILateUpdateSystem.cs similarity index 52% rename from Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs rename to Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/ILateUpdateSystem.cs index c50061b..34b5f80 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/ILateUpdateSystem.cs @@ -1,31 +1,36 @@ +#if FANTASY_UNITY using System; namespace Fantasy.Entitas.Interface { - internal interface IFrameUpdateSystem : IEntitiesSystem { } + internal interface ILateUpdateSystem : IEntitiesSystem { } + /// - /// 帧更新时间的抽象接口 + /// 实体的LateUpdate事件的抽象接口 /// - /// - public abstract class FrameUpdateSystem : IFrameUpdateSystem where T : Entity + /// 实体的泛型类型 + public abstract class LateUpdateSystem : ILateUpdateSystem where T : Entity { /// /// 实体的类型 /// /// public Type EntitiesType() => typeof(T); + /// /// 事件的抽象方法,需要自己实现这个方法 /// /// 触发事件的实体实例 - protected abstract void FrameUpdate(T self); + protected abstract void LateUpdate(T self); + /// - /// 框架内部调用的触发FrameUpdate的方法 + /// 框架内部调用的触发Awake的方法。 /// - /// + /// 触发事件的实体实例 public void Invoke(Entity self) { - FrameUpdate((T) self); + LateUpdate((T)self); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/ByteHelper.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/ByteHelper.cs index 9d3d6e0..3e8492b 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/ByteHelper.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/ByteHelper.cs @@ -1,10 +1,8 @@ using System; -using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using Fantasy.Async; namespace Fantasy.Helper { @@ -13,237 +11,491 @@ namespace Fantasy.Helper /// public static class ByteHelper { + private static readonly string[] HexTableUpper = new string[256]; + private static readonly string[] HexTableLower = new string[256]; private static readonly string[] Suffix = { "Byte", "KB", "MB", "GB", "TB" }; + private static readonly long[] Divisors = { 1L, 1024L, 1024L * 1024, 1024L * 1024 * 1024, 1024L * 1024 * 1024 * 1024 }; - /// - /// 从指定的文件流中读取一个 64 位整数。 - /// - public static long ReadInt64(FileStream stream) + static ByteHelper() { - var buffer = new byte[8]; -#if FANTASY_NET - stream.ReadExactly(buffer, 0, 8); -#else - stream.Read(buffer, 0, 8); -#endif - return BitConverter.ToInt64(buffer, 0); - } - - /// - /// 从指定的文件流中读取一个 32 位整数。 - /// - public static int ReadInt32(FileStream stream) - { - var buffer = new byte[4]; -#if FANTASY_NET - stream.ReadExactly(buffer, 0, 4); -#else - stream.Read(buffer, 0, 4); -#endif - return BitConverter.ToInt32(buffer, 0); - } - - /// - /// 从指定的内存流中读取一个 64 位整数。 - /// - public static long ReadInt64(MemoryStream stream) - { - var buffer = new byte[8]; -#if FANTASY_NET - stream.ReadExactly(buffer, 0, 8); -#else - stream.Read(buffer, 0, 8); -#endif - return BitConverter.ToInt64(buffer, 0); - } - - /// - /// 从指定的内存流中读取一个 32 位整数。 - /// - public static int ReadInt32(MemoryStream stream) - { - var buffer = new byte[4]; -#if FANTASY_NET - stream.ReadExactly(buffer, 0, 4); -#else - stream.Read(buffer, 0, 4); -#endif - return BitConverter.ToInt32(buffer, 0); - } - - /// - /// 将字节转换为十六进制字符串表示。 - /// - public static string ToHex(this byte b) - { - return b.ToString("X2"); - } - - /// - /// 将字节数组转换为十六进制字符串表示。 - /// - public static string ToHex(this byte[] bytes) - { - var stringBuilder = new StringBuilder(); - foreach (var b in bytes) + // 预计算所有256个字节的十六进制表示 + for (var i = 0; i < 256; i++) { - stringBuilder.Append(b.ToString("X2")); + HexTableUpper[i] = i.ToString("X2"); // 大写:00, 01, ..., FF + HexTableLower[i] = i.ToString("x2"); // 小写:00, 01, ..., ff + } + } + + #region Read + + /// + /// 从指定的流中读取一个 64 位整数。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ReadInt64(this Stream stream) + { + Span buffer = stackalloc byte[8]; +#if FANTASY_NET + stream.ReadExactly(buffer); +#else + _ = stream.Read(buffer); +#endif + return MemoryMarshal.Read(buffer); + } + + /// + /// 从指定的流中读取一个 32 位整数。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadInt32(this Stream stream) + { + Span buffer = stackalloc byte[4]; +#if FANTASY_NET + stream.ReadExactly(buffer); +#else + _ = stream.Read(buffer); +#endif + return MemoryMarshal.Read(buffer); + } + + /// + /// 从指定的流中读取一个 16 位整数。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReadInt16(this Stream stream) + { + Span buffer = stackalloc byte[2]; +#if FANTASY_NET + stream.ReadExactly(buffer); +#else + _ = stream.Read(buffer); +#endif + return MemoryMarshal.Read(buffer); + } + + /// + /// 从指定的流中读取一个无符号 64 位整数。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ReadUInt64(this Stream stream) + { + Span buffer = stackalloc byte[8]; +#if FANTASY_NET + stream.ReadExactly(buffer); +#else + _ = stream.Read(buffer); +#endif + return MemoryMarshal.Read(buffer); + } + + /// + /// 从指定的流中读取一个无符号 32 位整数。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ReadUInt32(this Stream stream) + { + Span buffer = stackalloc byte[4]; +#if FANTASY_NET + stream.ReadExactly(buffer); +#else + _ = stream.Read(buffer); +#endif + return MemoryMarshal.Read(buffer); + } + + /// + /// 从指定的流中读取一个无符号 16 位整数。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ReadUInt16(this Stream stream) + { + Span buffer = stackalloc byte[2]; +#if FANTASY_NET + stream.ReadExactly(buffer); +#else + _ = stream.Read(buffer); +#endif + return MemoryMarshal.Read(buffer); + } + + #endregion + + #region WriteTo + + /// + /// 将值写入字节数组的指定偏移位置。 + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteTo(this byte[] bytes, int offset, T value) where T : unmanaged + { + if (offset < 0 || offset + Marshal.SizeOf() > bytes.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + MemoryMarshal.Write(bytes.AsSpan(offset), +#if FANTASY_NET || FANTASY_CONSOLE + in value +#endif +#if FANTASY_UNITY + ref value +#endif + ); + } + + /// + /// 将值写入Span的指定偏移位置。 + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteTo(this Span span, int offset, T value) where T : unmanaged + { + if (offset < 0 || offset + Marshal.SizeOf() > span.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + MemoryMarshal.Write(span.Slice(offset), +#if FANTASY_NET || FANTASY_CONSOLE + in value +#endif +#if FANTASY_UNITY + ref value +#endif + ); + } + + /// + /// 将值写入内存流 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteTo(this Stream stream, T value) where T : unmanaged + { + Span buffer = stackalloc byte[Marshal.SizeOf()]; + MemoryMarshal.Write(buffer, +#if FANTASY_NET || FANTASY_CONSOLE + in value +#endif +#if FANTASY_UNITY + ref value +#endif + ); + stream.Write(buffer); + } + + /// + /// 将值写入内存流的指定偏移位置。 + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteTo(this Stream stream, int offset, T value) where T : unmanaged + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (!stream.CanSeek) + { + throw new NotSupportedException("Stream must support seeking"); + } + + if (offset < 0) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + var originalPosition = stream.Position; + try + { + stream.Position = offset; + Span buffer = stackalloc byte[Marshal.SizeOf()]; + MemoryMarshal.Write(buffer, +#if FANTASY_NET || FANTASY_CONSOLE + in value +#endif +#if FANTASY_UNITY + ref value +#endif + ); + stream.Write(buffer); + } + finally + { + stream.Position = originalPosition; + } + } + + #endregion + + #region ReadFrom + + /// + /// 从字节数组的指定偏移位置读取值。 + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T ReadFrom(this byte[] bytes, int offset) where T : unmanaged + { + if (offset < 0 || offset + Marshal.SizeOf() > bytes.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + return MemoryMarshal.Read(bytes.AsSpan(offset)); + } + + /// + /// 从Span的指定偏移位置读取值。 + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T ReadFrom(this ReadOnlySpan span, int offset) where T : unmanaged + { + if (offset < 0 || offset + Marshal.SizeOf() > span.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + return MemoryMarshal.Read(span.Slice(offset)); + } + + /// + /// 从流的指定偏移位置读取值 + /// + /// + /// + /// 是否在读取完成后恢复到原始位置 + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T ReadFrom(this Stream stream, int offset, bool restorePosition = false) where T : unmanaged + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); } - return stringBuilder.ToString(); - } - - /// - /// 将字节数组按指定格式转换为十六进制字符串表示。 - /// - public static string ToHex(this byte[] bytes, string format) - { - var stringBuilder = new StringBuilder(); - foreach (var b in bytes) + if (!stream.CanSeek) { - stringBuilder.Append(b.ToString(format)); + throw new NotSupportedException("Stream must support seeking"); } - return stringBuilder.ToString(); - } - - /// - /// 将字节数组的指定范围按十六进制格式转换为字符串表示。 - /// - public static string ToHex(this byte[] bytes, int offset, int count) - { - var stringBuilder = new StringBuilder(); - for (var i = offset; i < offset + count; ++i) + if (offset < 0) { - stringBuilder.Append(bytes[i].ToString("X2")); + throw new ArgumentOutOfRangeException(nameof(offset)); } + + var originalPosition = restorePosition ? stream.Position : 0; - return stringBuilder.ToString(); + try + { + var sizeOf = Marshal.SizeOf(); + stream.Position = offset; + Span buffer = stackalloc byte[sizeOf]; +#if FANTASY_NET + stream.ReadExactly(buffer); +#else + var bytesRead = stream.Read(buffer); + if (bytesRead != sizeOf) + { + throw new EndOfStreamException($"Could not read {sizeOf} bytes from stream"); + } +#endif + return MemoryMarshal.Read(buffer); + } + finally + { + if (restorePosition) + { + stream.Position = originalPosition; + } + } } + #endregion + + #region GetBytes + /// - /// 将字节数组转换为默认编码的字符串表示。 + /// 将值转换为字节数组。 /// - public static string ToStr(this byte[] bytes) + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(this T value, Span buffer) where T : unmanaged { - return Encoding.Default.GetString(bytes); + if (buffer.Length < Marshal.SizeOf()) + { + throw new ArgumentException($"Buffer too small. Required: {Marshal.SizeOf()}, Actual: {buffer.Length}"); + } + + MemoryMarshal.Write(buffer, +#if FANTASY_NET || FANTASY_CONSOLE + in value +#endif +#if FANTASY_UNITY + ref value +#endif + ); } /// - /// 将字节数组的指定范围按默认编码转换为字符串表示。 + /// 将值转换为字节数组。 /// - public static string ToStr(this byte[] bytes, int index, int count) + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(this T value, byte[] buffer) where T : unmanaged { - return Encoding.Default.GetString(bytes, index, count); + value.GetBytes(buffer.AsSpan()); } /// - /// 将字节数组转换为 UTF-8 编码的字符串表示。 + /// 将值转换为字节数组。 /// - public static string Utf8ToStr(this byte[] bytes) + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytes(this T value) where T : unmanaged { - return Encoding.UTF8.GetString(bytes); + var result = new byte[Marshal.SizeOf()]; + MemoryMarshal.Write(result.AsSpan(), +#if FANTASY_NET || FANTASY_CONSOLE + in value +#endif +#if FANTASY_UNITY + ref value +#endif + ); + return result; } - /// - /// 将字节数组的指定范围按 UTF-8 编码转换为字符串表示。 - /// - public static string Utf8ToStr(this byte[] bytes, int index, int count) - { - return Encoding.UTF8.GetString(bytes, index, count); - } + #endregion + + #region ToReadableSpeed /// - /// 将无符号整数写入字节数组的指定偏移位置。 + /// 将字节数转换为可读的大小表示 /// - public static void WriteTo(this byte[] bytes, int offset, uint num) - { - bytes[offset] = (byte)(num & 0xff); - bytes[offset + 1] = (byte)((num & 0xff00) >> 8); - bytes[offset + 2] = (byte)((num & 0xff0000) >> 16); - bytes[offset + 3] = (byte)((num & 0xff000000) >> 24); - } - - /// - /// 将有符号整数写入字节数组的指定偏移位置。 - /// - public static void WriteTo(this byte[] bytes, int offset, int num) - { - bytes[offset] = (byte)(num & 0xff); - bytes[offset + 1] = (byte)((num & 0xff00) >> 8); - bytes[offset + 2] = (byte)((num & 0xff0000) >> 16); - bytes[offset + 3] = (byte)((num & 0xff000000) >> 24); - } - - /// - /// 将字节写入字节数组的指定偏移位置。 - /// - public static void WriteTo(this byte[] bytes, int offset, byte num) - { - bytes[offset] = num; - } - - /// - /// 将有符号短整数写入字节数组的指定偏移位置。 - /// - public static void WriteTo(this byte[] bytes, int offset, short num) - { - bytes[offset] = (byte)(num & 0xff); - bytes[offset + 1] = (byte)((num & 0xff00) >> 8); - } - - /// - /// 将无符号短整数写入字节数组的指定偏移位置。 - /// - public static void WriteTo(this byte[] bytes, int offset, ushort num) - { - bytes[offset] = (byte)(num & 0xff); - bytes[offset + 1] = (byte)((num & 0xff00) >> 8); - } - - /// - /// 将字节数转换为可读的速度表示。 - /// - /// 字节数 - /// 可读的速度表示 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToReadableSpeed(this long byteCount) { - var i = 0; - double dblSByte = byteCount; - if (byteCount <= 1024) + switch (byteCount) { - return $"{dblSByte:0.##}{Suffix[i]}"; + case <= 0: + { + return "0 Byte"; + } + // < 1TB,使用快速版本 + case < 1L << 40: + { + var minLevel = 0; + var temp = byteCount; + while (temp >= 1024 && minLevel < 4) + { + temp >>= 10; + minLevel++; + } + return $"{(double)byteCount / Divisors[minLevel]:0.##} {Suffix[minLevel]}"; + } + default: + { +#if NET6_0_OR_GREATER + var level = Math.Min((int)(Math.Log2(byteCount) / 10), Suffix.Length - 1); +#else + // .NET Framework / .NET Core < 6.0 替代方案 + var level = Math.Min((int)(Math.Log(byteCount) / Math.Log(2) / 10), Suffix.Length - 1); +#endif + var divisor = 1L << (level * 10); + var value = (double)byteCount / divisor; + return $"{value:0.##} {Suffix[level]}"; + } } - - for (i = 0; byteCount / 1024 > 0; i++, byteCount /= 1024) - { - dblSByte = byteCount / 1024.0; - } - - return $"{dblSByte:0.##}{Suffix[i]}"; } - + /// - /// 将字节数转换为可读的速度表示。 + /// 将字节数转换为可读的大小表示(无符号版本) /// - /// 字节数 - /// 可读的速度表示 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToReadableSpeed(this ulong byteCount) { - var i = 0; - double dblSByte = byteCount; - - if (byteCount <= 1024) + switch (byteCount) { - return $"{dblSByte:0.##}{Suffix[i]}"; + case 0: + { + return "0 Byte"; + } + // < 1TB,使用快速版本 + case < 1L << 40: + { + var minLevel = 0; + var temp = byteCount; + while (temp >= 1024 && minLevel < 4) + { + temp >>= 10; + minLevel++; + } + return $"{(double)byteCount / Divisors[minLevel]:0.##} {Suffix[minLevel]}"; + } + default: + { +#if NET6_0_OR_GREATER + var level = Math.Min((int)(Math.Log2(byteCount) / 10), Suffix.Length - 1); +#else + // .NET Framework / .NET Core < 6.0 替代方案 + var level = Math.Min((int)(Math.Log(byteCount) / Math.Log(2) / 10), Suffix.Length - 1); +#endif + var divisor = 1L << (level * 10); + var value = (double)byteCount / divisor; + return $"{value:0.##} {Suffix[level]}"; + } } + } - for (i = 0; byteCount / 1024 > 0; i++, byteCount /= 1024) - { - dblSByte = byteCount / 1024.0; - } + #endregion - return $"{dblSByte:0.##}{Suffix[i]}"; + #region MergeBytes + + /// + /// 合并字节数组到目标缓冲区(零分配版本)。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void MergeBytesTo(Span destination, ReadOnlySpan first, ReadOnlySpan second) + { + if (destination.Length < first.Length + second.Length) + throw new ArgumentException("Destination buffer too small"); + + first.CopyTo(destination); + second.CopyTo(destination.Slice(first.Length)); } /// @@ -252,137 +504,298 @@ namespace Fantasy.Helper /// 第一个字节数组 /// 第二个字节数组 /// 合并后的字节数组 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] MergeBytes(byte[] bytes, byte[] otherBytes) { + if (bytes == null) + { + throw new ArgumentNullException(nameof(bytes)); + } + + if (otherBytes == null) + { + throw new ArgumentNullException(nameof(otherBytes)); + } + + // 优化:如果其中一个为空,直接返回另一个的副本 + if (bytes.Length == 0) + { + return (byte[])otherBytes.Clone(); + } + + if (otherBytes.Length == 0) + { + return (byte[])bytes.Clone(); + } + var result = new byte[bytes.Length + otherBytes.Length]; - bytes.CopyTo(result, 0); - otherBytes.CopyTo(result, bytes.Length); + bytes.CopyTo(result.AsSpan()); + otherBytes.CopyTo(result.AsSpan(bytes.Length)); return result; } + #endregion + + #region ToHex + /// - /// 根据int值获取字节数组。 + /// 将字节转换为大写十六进制字符串。 /// - /// - /// - /// + /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void GetBytes(this int value, byte[] buffer) + public static string ToHex(this byte b) { - if (buffer.Length < 4) + return HexTableUpper[b]; + } + + /// + /// 将字节转换为小写十六进制字符串。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string ToHexLower(this byte b) + { + return HexTableLower[b]; + } + + /// + /// 将字节转换为指定格式的十六进制字符串。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string ToHex(this byte b, bool upperCase) + { + return upperCase ? HexTableUpper[b] : HexTableLower[b]; + } + + /// + /// 将字节数组转换为十六进制字符串表示。 + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string ToHex(this byte[] bytes, bool upperCase = true) + { + if (bytes == null) { - throw new ArgumentException("Buffer too small."); + throw new ArgumentNullException(nameof(bytes)); + } + + if (bytes.Length == 0) + { + return string.Empty; } -#if FANTASY_NET || FANTASY_CONSOLE - MemoryMarshal.Write(buffer.AsSpan(), in value); -#endif -#if FANTASY_UNITY - MemoryMarshal.Write(buffer.AsSpan(), ref value); -#endif + var hexTable = upperCase ? HexTableUpper : HexTableLower; + + return string.Create(bytes.Length * 2, (bytes, hexTable), (chars, state) => + { + var (buffer, table) = state; + var charIndex = 0; + ref var bytesRef = ref MemoryMarshal.GetReference(buffer.AsSpan()); + + for (var i = 0; i < buffer.Length; i++) + { + var hexStr = table[Unsafe.Add(ref bytesRef, i)]; + chars[charIndex++] = hexStr[0]; + chars[charIndex++] = hexStr[1]; + } + }); } /// - /// 根据int值获取字节数组。 + /// 将字节数组的指定范围按十六进制格式转换为字符串表示。 /// - /// - /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteBytes(this MemoryStream memoryStream, int value) + public static string ToHex(this byte[] bytes, int offset, int count, bool upperCase = true) { - using var memoryOwner = MemoryPool.Shared.Rent(4); - var memorySpan = memoryOwner.Memory.Span; -#if FANTASY_NET - MemoryMarshal.Write(memorySpan, in value); -#endif -#if FANTASY_UNITY - MemoryMarshal.Write(memorySpan, ref value); -#endif - memoryStream.Write(memorySpan); + if (bytes == null) + { + throw new ArgumentNullException(nameof(bytes)); + } + + if (offset < 0) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + if (count < 0 || offset + count > bytes.Length) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + + if (count == 0) + { + return string.Empty; + } + + var hexTable = upperCase ? HexTableUpper : HexTableLower; + + return string.Create(count * 2, (bytes, offset, count, hexTable), (chars, state) => + { + var (buffer, start, length, table) = state; + var charIndex = 0; + ref var bytesRef = ref MemoryMarshal.GetReference(buffer.AsSpan()); + + for (var i = 0; i < length; i++) + { + var hexStr = table[Unsafe.Add(ref bytesRef, start + i)]; + chars[charIndex++] = hexStr[0]; + chars[charIndex++] = hexStr[1]; + } + }); + } + + /// + /// 将字节数组的指定范围按十六进制格式转换为字符串表示。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string ToHex(this ReadOnlySpan bytes, bool upperCase = true) + { + if (bytes.Length == 0) + { + return string.Empty; + } + + var hexTable = upperCase ? HexTableUpper : HexTableLower; + + return string.Create(bytes.Length * 2, (MemoryMarshal.GetReference(bytes), bytes.Length, hexTable), (chars, + state) => + { + var (bytesRef, length, table) = state; + var charIndex = 0; + + for (var i = 0; i < length; i++) + { + var hexStr = table[Unsafe.Add(ref bytesRef, i)]; + chars[charIndex++] = hexStr[0]; + chars[charIndex++] = hexStr[1]; + } + }); } /// - /// 根据uint值获取字节数组。 + /// 将十六进制字符串转换为字节数组。 /// - /// - /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void GetBytes(ref this uint value, byte[] buffer) + public static byte[] FromHex(this string hexString) { - if (buffer.Length < 4) + return hexString.AsSpan().FromHex(); + } + + /// + /// 将十六进制字符串转换为字节数组。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] FromHex(this ReadOnlySpan hexSpan) + { + if (hexSpan.Length == 0) { - throw new ArgumentException("Buffer too small."); + return Array.Empty(); } - -#if FANTASY_NET - MemoryMarshal.Write(buffer.AsSpan(), in value); -#endif -#if FANTASY_UNITY - MemoryMarshal.Write(buffer.AsSpan(), ref value); -#endif - } - - /// - /// 根据uint值获取字节数组。 - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteBytes(this MemoryStream memoryStream, uint value) - { - using var memoryOwner = MemoryPool.Shared.Rent(4); - var memorySpan = memoryOwner.Memory.Span; -#if FANTASY_NET - MemoryMarshal.Write(memorySpan, in value); -#endif -#if FANTASY_UNITY - MemoryMarshal.Write(memorySpan, ref value); -#endif - memoryStream.Write(memorySpan); - } - - /// - /// 根据int值获取字节数组。 - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void GetBytes(this long value, byte[] buffer) - { - if (buffer.Length < 8) + + if (hexSpan.Length % 2 != 0) { - throw new ArgumentException("Buffer too small."); + throw new ArgumentException("Hex string must have even length"); } -#if FANTASY_NET - MemoryMarshal.Write(buffer.AsSpan(), in value); -#endif -#if FANTASY_UNITY - MemoryMarshal.Write(buffer.AsSpan(), ref value); -#endif + + var result = new byte[hexSpan.Length / 2]; + + for (var i = 0; i < result.Length; i++) + { + var high = HexCharToValue(hexSpan[i * 2]); + var low = HexCharToValue(hexSpan[i * 2 + 1]); + result[i] = (byte)((high << 4) | low); + } + + return result; } + /// - /// 根据uint值获取字节数组。 + /// 将十六进制字符串转换到现有字节数组。 /// - /// - /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteBytes(this MemoryStream memoryStream, long value) + public static void FromHexTo(this string hexString, Span destination) { - using var memoryOwner = MemoryPool.Shared.Rent(8); - var memorySpan = memoryOwner.Memory.Span; -#if FANTASY_NET - MemoryMarshal.Write(memorySpan, in value); -#endif -#if FANTASY_UNITY - MemoryMarshal.Write(memorySpan, ref value); -#endif - memoryStream.Write(memorySpan); + if (string.IsNullOrEmpty(hexString)) + { + return; + } + + if (hexString.Length % 2 != 0) + { + throw new ArgumentException("Hex string must have even length", nameof(hexString)); + } + + if (destination.Length < hexString.Length / 2) + { + throw new ArgumentException("Destination buffer too small", nameof(destination)); + } + + for (var i = 0; i < hexString.Length / 2; i++) + { + var high = HexCharToValue(hexString[i * 2]); + var low = HexCharToValue(hexString[i * 2 + 1]); + destination[i] = (byte)((high << 4) | low); + } } + + + /// + /// 将十六进制字符转换为数值。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int HexCharToValue(char c) + { + return c switch + { + >= '0' and <= '9' => c - '0', + >= 'A' and <= 'F' => c - 'A' + 10, + >= 'a' and <= 'f' => c - 'a' + 10, + _ => throw new ArgumentException($"Invalid hex character: {c}") + }; + } + + + /// + /// 将字节数组转换为默认编码的字符串表示。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string ToStr(this byte[] bytes) + { + return Encoding.Default.GetString(bytes); + } + + /// + /// 将字节数组的指定范围按默认编码转换为字符串表示。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string ToStr(this byte[] bytes, int index, int count) + { + return Encoding.Default.GetString(bytes, index, count); + } + + /// + /// 将字节数组转换为 UTF-8 编码的字符串表示。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string Utf8ToStr(this byte[] bytes) + { + return Encoding.UTF8.GetString(bytes); + } + + /// + /// 将字节数组的指定范围按 UTF-8 编码转换为字符串表示。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string Utf8ToStr(this byte[] bytes, int index, int count) + { + return Encoding.UTF8.GetString(bytes, index, count); + } + + + #endregion } } \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/EncryptHelper.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/EncryptHelper.cs index be950bc..5cbe7c7 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/EncryptHelper.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/EncryptHelper.cs @@ -45,7 +45,7 @@ namespace Fantasy.Helper public static string FileMD5(FileStream fileStream) { var md5 = MD5.Create(); - return md5.ComputeHash(fileStream).ToHex("x2"); + return md5.ComputeHash(fileStream).ToHex(false); } /// @@ -57,7 +57,7 @@ namespace Fantasy.Helper { var md5 = MD5.Create(); bytes = md5.ComputeHash(bytes); - return bytes.ToHex("x2"); + return bytes.ToHex(false); } } } \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/FileHelper.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/FileHelper.cs index 66ff5ae..00c18ec 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/FileHelper.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/FileHelper.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -17,7 +18,7 @@ namespace Fantasy.Helper /// 完整路径。 public static string GetFullPath(string relativePath) { - return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath)); + return Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, relativePath)); } /// diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HashCodeHelper.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HashCodeHelper.cs index 7f2a5af..4ea6f29 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HashCodeHelper.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HashCodeHelper.cs @@ -1,5 +1,6 @@ -using System.Security.Cryptography; -using System.Text; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming namespace Fantasy.Helper @@ -9,8 +10,6 @@ namespace Fantasy.Helper /// public static partial class HashCodeHelper { - private static readonly SHA256 Sha256Hash = SHA256.Create(); - /// /// 计算两个字符串的HashCode /// @@ -24,112 +23,7 @@ namespace Fantasy.Helper hash = hash * 31 + b.GetHashCode(); return hash; } -#if FANTASY_NET || !FANTASY_WEBGL - /// - /// 使用bkdr算法生成一个long的值 - /// - /// - /// - public static unsafe long GetBKDRHashCode(string str) - { - ulong hash = 0; - // 如果要修改这个种子、建议选择一个质数来做种子 - const uint seed = 13131; // 31 131 1313 13131 131313 etc.. - fixed (char* p = str) - { - for (var i = 0; i < str.Length; i++) - { - var c = p[i]; - var high = (byte)(c >> 8); - var low = (byte)(c & byte.MaxValue); - hash = hash * seed + high; - hash = hash * seed + low; - } - } - return (long)hash; - } - /// - /// 使用MurmurHash3算法生成一个uint的值 - /// - /// - /// - public static unsafe uint MurmurHash3(string str) - { - const uint seed = 0xc58f1a7b; - uint hash = seed; - uint c1 = 0xcc9e2d51; - uint c2 = 0x1b873593; - - fixed (char* p = str) - { - var current = p; - - for (var i = 0; i < str.Length; i++) - { - var k1 = (uint)(*current); - k1 *= c1; - k1 = (k1 << 15) | (k1 >> (32 - 15)); - k1 *= c2; - - hash ^= k1; - hash = (hash << 13) | (hash >> (32 - 13)); - hash = hash * 5 + 0xe6546b64; - - current++; - } - } - - hash ^= (uint)str.Length; - hash ^= hash >> 16; - hash *= 0x85ebca6b; - hash ^= hash >> 13; - hash *= 0xc2b2ae35; - hash ^= hash >> 16; - return hash; - } - - /// - /// 使用MurmurHash3算法生成一个long的值 - /// - /// - /// - public static unsafe long ComputeHash64(string str) - { - const ulong seed = 0xc58f1a7bc58f1a7bUL; // 64-bit seed - var hash = seed; - var c1 = 0x87c37b91114253d5UL; - var c2 = 0x4cf5ad432745937fUL; - - fixed (char* p = str) - { - var current = p; - - for (var i = 0; i < str.Length; i++) - { - var k1 = (ulong)(*current); - k1 *= c1; - k1 = (k1 << 31) | (k1 >> (64 - 31)); - k1 *= c2; - - hash ^= k1; - hash = (hash << 27) | (hash >> (64 - 27)); - hash = hash * 5 + 0x52dce729; - - current++; - } - } - - hash ^= (ulong)str.Length; - hash ^= hash >> 33; - hash *= 0xff51afd7ed558ccdUL; - hash ^= hash >> 33; - hash *= 0xc4ceb9fe1a85ec53UL; - hash ^= hash >> 33; - return (long)hash; - } -#endif -#if FANTASY_WEBGL /// /// 使用bkdr算法生成一个long的值 /// @@ -137,18 +31,23 @@ namespace Fantasy.Helper /// public static long GetBKDRHashCode(string str) { - long hash = 0; - // 如果要修改这个种子、建议选择一个质数来做种子 - const uint seed = 13131; // 31 131 1313 13131 131313 etc.. - foreach (var c in str) + ulong hash = 0; + const uint seed = 13131; // 如果要修改这个种子、建议选择一个质数来做种子 31 131 1313 13131 131313 etc.. + var span = str.AsSpan(); + ref var local = ref MemoryMarshal.GetReference(span); + + for (var i = 0; i < span.Length; i++) { + var c = Unsafe.Add(ref local, i); var high = (byte)(c >> 8); var low = (byte)(c & byte.MaxValue); hash = hash * seed + high; hash = hash * seed + low; } - return hash; + + return (long)hash; } + /// /// 使用MurmurHash3算法生成一个uint的值 /// @@ -160,10 +59,13 @@ namespace Fantasy.Helper uint hash = seed; uint c1 = 0xcc9e2d51; uint c2 = 0x1b873593; - - foreach (var t in str) + + var span = str.AsSpan(); + ref var local = ref MemoryMarshal.GetReference(span); + + for (var i = 0; i < span.Length; i++) { - var k1 = (uint)(t); + var k1 = (uint)Unsafe.Add(ref local, i); k1 *= c1; k1 = (k1 << 15) | (k1 >> (32 - 15)); k1 *= c2; @@ -181,7 +83,7 @@ namespace Fantasy.Helper hash ^= hash >> 16; return hash; } - + /// /// 使用MurmurHash3算法生成一个long的值 /// @@ -193,10 +95,13 @@ namespace Fantasy.Helper var hash = seed; var c1 = 0x87c37b91114253d5UL; var c2 = 0x4cf5ad432745937fUL; - - foreach (var t in str) + + var span = str.AsSpan(); + ref var local = ref MemoryMarshal.GetReference(span); + + for (var i = 0; i < span.Length; i++) { - var k1 = (ulong)(t); + var k1 = (ulong)Unsafe.Add(ref local, i); k1 *= c1; k1 = (k1 << 31) | (k1 >> (64 - 31)); k1 *= c2; @@ -214,16 +119,218 @@ namespace Fantasy.Helper hash ^= hash >> 33; return (long)hash; } -#endif + /// /// 根据字符串计算一个Hash值 /// - /// + /// + /// /// - public static int ComputeSha256HashAsInt(string rawData) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Hash32(string obj, uint seed = 0) => Hash32(obj.AsSpan(), seed); + + /// + /// 根据字符串计算一个Hash值 + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Hash32(in T obj, uint seed = 0) where T : unmanaged => Hash32( + MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf()), + seed); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Hash32(ReadOnlySpan buffer, uint seed = 0) where T : unmanaged => + Hash32(MemoryMarshal.Cast(buffer), seed); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Hash32(ReadOnlySpan buffer, uint seed = 0) { - var bytes = Sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); - return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; + int length = buffer.Length; + ref byte local1 = ref MemoryMarshal.GetReference(buffer); + uint num1; + if (buffer.Length >= 16) + { + uint num2 = seed + 606290984U; + uint num3 = seed + 2246822519U; + uint num4 = seed; + uint num5 = seed - 2654435761U; + for (; length >= 16; length -= 16) + { + const nint elementOffset1 = 4; + const nint elementOffset2 = 8; + const nint elementOffset3 = 12; + nint byteOffset = buffer.Length - length; + ref byte local2 = ref Unsafe.AddByteOffset(ref local1, byteOffset); + uint num6 = num2 + Unsafe.ReadUnaligned(ref local2) * 2246822519U; + num2 = (uint)((((int)num6 << 13) | (int)(num6 >> 19)) * -1640531535); + uint num7 = num3 + + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, elementOffset1)) * + 2246822519U; + num3 = (uint)((((int)num7 << 13) | (int)(num7 >> 19)) * -1640531535); + uint num8 = num4 + + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, elementOffset2)) * + 2246822519U; + num4 = (uint)((((int)num8 << 13) | (int)(num8 >> 19)) * -1640531535); + uint num9 = num5 + + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, elementOffset3)) * + 2246822519U; + num5 = (uint)((((int)num9 << 13) | (int)(num9 >> 19)) * -1640531535); + } + + num1 = (uint)((((int)num2 << 1) | (int)(num2 >> 31)) + (((int)num3 << 7) | (int)(num3 >> 25)) + + (((int)num4 << 12) | (int)(num4 >> 20)) + (((int)num5 << 18) | (int)(num5 >> 14)) + + buffer.Length); + } + else + num1 = (uint)((int)seed + 374761393 + buffer.Length); + + for (; length >= 4; length -= 4) + { + nint byteOffset = buffer.Length - length; + uint num10 = Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local1, byteOffset)); + uint num11 = num1 + num10 * 3266489917U; + num1 = (uint)((((int)num11 << 17) | (int)(num11 >> 15)) * 668265263); + } + + nint byteOffset1 = buffer.Length - length; + ref byte local3 = ref Unsafe.AddByteOffset(ref local1, byteOffset1); + for (int index = 0; index < length; ++index) + { + nint byteOffset2 = index; + uint num12 = Unsafe.AddByteOffset(ref local3, byteOffset2); + uint num13 = num1 + num12 * 374761393U; + num1 = (uint)((((int)num13 << 11) | (int)(num13 >> 21)) * -1640531535); + } + +#if NET7_0_OR_GREATER + int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777; + int num15 = (num14 ^ (num14 >>> 13)) * -1028477379; + return num15 ^ (num15 >>> 16); +#else + int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777; + int num15 = (num14 ^ (int)((uint)num14 >> 13)) * -1028477379; + return num15 ^ (int)((uint)num15 >> 16); +#endif + } + + /// + /// 根据字符串计算一个Hash值 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long Hash64(string obj, ulong seed = 0) => Hash64(obj.AsSpan(), seed); + + /// + /// 根据字符串计算一个Hash值 + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long Hash64(in T obj, ulong seed = 0) where T : unmanaged => Hash64( + MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf()), + seed); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static long Hash64(ReadOnlySpan buffer, ulong seed = 0) where T : unmanaged => + Hash64(MemoryMarshal.Cast(buffer), seed); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static long Hash64(ReadOnlySpan buffer, ulong seed = 0) + { + ref var local1 = ref MemoryMarshal.GetReference(buffer); + var length = buffer.Length; + ulong num1; + if (buffer.Length >= 32) + { + var num2 = seed + 6983438078262162902UL; + var num3 = seed + 14029467366897019727UL; + var num4 = seed; + var num5 = seed - 11400714785074694791UL; + for (; length >= 32; length -= 32) + { + ref var local2 = ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length)); + var num6 = num2 + Unsafe.ReadUnaligned(ref local2) * 14029467366897019727UL; + num2 = (ulong)((((long)num6 << 31) | (long)(num6 >> 33)) * -7046029288634856825L); + var num7 = num3 + + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(8U))) * + 14029467366897019727UL; + num3 = (ulong)((((long)num7 << 31) | (long)(num7 >> 33)) * -7046029288634856825L); + var num8 = num4 + + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(16U))) * + 14029467366897019727UL; + num4 = (ulong)((((long)num8 << 31) | (long)(num8 >> 33)) * -7046029288634856825L); + var num9 = num5 + + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(24U))) * + 14029467366897019727UL; + num5 = (ulong)((((long)num9 << 31) | (long)(num9 >> 33)) * -7046029288634856825L); + } + + var num10 = (((long)num2 << 1) | (long)(num2 >> 63)) + (((long)num3 << 7) | (long)(num3 >> 57)) + + (((long)num4 << 12) | (long)(num4 >> 52)) + (((long)num5 << 18) | (long)(num5 >> 46)); + var num11 = num2 * 14029467366897019727UL; + var num12 = (((long)num11 << 31) | (long)(num11 >> 33)) * -7046029288634856825L; + var num13 = (num10 ^ num12) * -7046029288634856825L + -8796714831421723037L; + var num14 = num3 * 14029467366897019727UL; + var num15 = (((long)num14 << 31) | (long)(num14 >> 33)) * -7046029288634856825L; + var num16 = (num13 ^ num15) * -7046029288634856825L + -8796714831421723037L; + var num17 = num4 * 14029467366897019727UL; + var num18 = (((long)num17 << 31) | (long)(num17 >> 33)) * -7046029288634856825L; + var num19 = (num16 ^ num18) * -7046029288634856825L + -8796714831421723037L; + var num20 = num5 * 14029467366897019727UL; + var num21 = (((long)num20 << 31) | (long)(num20 >> 33)) * -7046029288634856825L; + num1 = (ulong)((num19 ^ num21) * -7046029288634856825L + -8796714831421723037L); + } + else + num1 = seed + 2870177450012600261UL; + + var num22 = num1 + (ulong)buffer.Length; + for (; length >= 8; length -= 8) + { + var num23 = Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local1, + (IntPtr)(buffer.Length - length))) * 14029467366897019727UL; + var num24 = (ulong)((((long)num23 << 31) | (long)(num23 >> 33)) * -7046029288634856825L); + var num25 = num22 ^ num24; + num22 = (ulong)((((long)num25 << 27) | (long)(num25 >> 37)) * -7046029288634856825L + + -8796714831421723037L); + } + + if (length >= 4) + { + ulong num26 = + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length))); + var num27 = num22 ^ (num26 * 11400714785074694791UL); + num22 = (ulong)((((long)num27 << 23) | (long)(num27 >> 41)) * -4417276706812531889L + + 1609587929392839161L); + length -= 4; + } + + for (var byteOffset = 0; byteOffset < length; ++byteOffset) + { + ulong num28 = + Unsafe.AddByteOffset(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length)), + (IntPtr)byteOffset); + var num29 = num22 ^ (num28 * 2870177450012600261UL); + num22 = (ulong)((((long)num29 << 11) | (long)(num29 >> 53)) * -7046029288634856825L); + } + +#if NET7_0_OR_GREATER + var num30 = (long)num22; + var num31 = (num30 ^ (num30 >>> 33)) * -4417276706812531889L; + var num32 = (num31 ^ (num31 >>> 29)) * 1609587929392839161L; + return num32 ^ (num32 >>> 32); +#else + var num30 = (long)num22; + var num31 = (num30 ^ (long)((ulong)num30 >> 33)) * -4417276706812531889L; + var num32 = (num31 ^ (long)((ulong)num31 >> 29)) * 1609587929392839161L; + return num32 ^ (long)((ulong)num32 >> 32); +#endif } } } \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/NetworkHelper.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/NetworkHelper.cs index 6a35a61..867ba91 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/NetworkHelper.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/NetworkHelper.cs @@ -54,7 +54,7 @@ namespace Fantasy.Helper return null; } } - + /// /// 克隆一个IPEndPoint /// @@ -66,7 +66,7 @@ namespace Fantasy.Helper var ip = (IPEndPoint)endPoint; return new IPEndPoint(ip.Address, ip.Port); } - + /// /// 比较两个IPEndPoint是否相等 /// @@ -79,7 +79,7 @@ namespace Fantasy.Helper var ip = (IPEndPoint)endPoint; return ip.Address.Equals(ipEndPoint.Address) && ip.Port == ipEndPoint.Port; } - + /// /// 比较两个IPEndPoint是否相等 /// @@ -91,7 +91,6 @@ namespace Fantasy.Helper { return endPoint.Address.Equals(ipEndPoint.Address) && endPoint.Port == ipEndPoint.Port; } - #if !FANTASY_WEBGL /// /// 将SocketAddress写入到Byte[]中 @@ -100,13 +99,13 @@ namespace Fantasy.Helper /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void SocketAddressToByte(this SocketAddress socketAddress, byte[] buffer, int offset) + public static void SocketAddressToByte(this SocketAddress socketAddress, byte[] buffer, int offset) { if (socketAddress == null) { throw new ArgumentNullException(nameof(socketAddress), "The SocketAddress cannot be null."); } - + if (buffer == null) { throw new ArgumentNullException(nameof(buffer), "The buffer cannot be null."); @@ -114,20 +113,21 @@ namespace Fantasy.Helper if (buffer.Length < socketAddress.Size + offset + 8) { - throw new ArgumentException("The buffer length is insufficient. It must be at least the size of the SocketAddress plus 8 bytes.", nameof(buffer)); + throw new ArgumentException( + "The buffer length is insufficient. It must be at least the size of the SocketAddress plus 8 bytes.", + nameof(buffer)); } - - fixed (byte* pBuffer = buffer) + + var span = buffer.AsSpan(offset); + var addressFamilyValue = (int)socketAddress.Family; + var socketAddressSizeValue = socketAddress.Size; + + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(span), addressFamilyValue); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), 4), socketAddressSizeValue); + + for (var i = 0; i < socketAddress.Size - 2; i++) { - var pOffsetBuffer = pBuffer + offset; - var addressFamilyValue = (int)socketAddress.Family; - var socketAddressSizeValue = socketAddress.Size; - Buffer.MemoryCopy(&addressFamilyValue, pOffsetBuffer, buffer.Length - offset, sizeof(int)); - Buffer.MemoryCopy(&socketAddressSizeValue, pOffsetBuffer + 4, buffer.Length - offset -4, sizeof(int)); - for (var i = 0; i < socketAddress.Size - 2; i++) - { - pOffsetBuffer[8 + i] = socketAddress[i + 2]; - } + Unsafe.Add(ref MemoryMarshal.GetReference(span), 8 + i) = socketAddress[i + 2]; } } @@ -141,40 +141,41 @@ namespace Fantasy.Helper /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe int ByteToSocketAddress(byte[] buffer, int offset, out SocketAddress socketAddress) + public static int ByteToSocketAddress(byte[] buffer, int offset, out SocketAddress socketAddress) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer), "The buffer cannot be null."); } - + if (buffer.Length < 8) { - throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", nameof(buffer)); + throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", + nameof(buffer)); } - + try { - fixed (byte* pBuffer = buffer) + var span = buffer.AsSpan(offset); + ref var spanRef = ref MemoryMarshal.GetReference(span); + + var addressFamily = (AddressFamily)Unsafe.ReadUnaligned(ref spanRef); + var socketAddressSize = Unsafe.ReadUnaligned(ref Unsafe.Add(ref spanRef, 4)); + + if (buffer.Length < offset + 8 + socketAddressSize) { - var pOffsetBuffer = pBuffer + offset; - var addressFamily = (AddressFamily)Marshal.ReadInt32((IntPtr)pOffsetBuffer); - var socketAddressSize = Marshal.ReadInt32((IntPtr)(pOffsetBuffer + 4)); - - if (buffer.Length < offset + 8 + socketAddressSize) - { - throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", nameof(buffer)); - } - - socketAddress = new SocketAddress(addressFamily, socketAddressSize); - - for (var i = 0; i < socketAddressSize - 2; i++) - { - socketAddress[i + 2] = *(pOffsetBuffer + 8 + i); - } - - return 8 + offset + socketAddressSize; + throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", + nameof(buffer)); } + + socketAddress = new SocketAddress(addressFamily, socketAddressSize); + + for (var i = 0; i < socketAddressSize - 2; i++) + { + socketAddress[i + 2] = Unsafe.Add(ref spanRef, 8 + i); + } + + return 8 + offset + socketAddressSize; } catch (ArgumentNullException ex) { @@ -199,35 +200,36 @@ namespace Fantasy.Helper /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe int ByteToSocketAddress(ReadOnlyMemory buffer, int offset, out SocketAddress socketAddress) + public static int ByteToSocketAddress(ReadOnlyMemory buffer, int offset, out SocketAddress socketAddress) { if (buffer.Length < 8) { - throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", nameof(buffer)); + throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", + nameof(buffer)); } try { - fixed (byte* pBuffer = buffer.Span) + var span = buffer.Span.Slice(offset); + ref var spanRef = ref MemoryMarshal.GetReference(span); + + var addressFamily = (AddressFamily)Unsafe.ReadUnaligned(ref spanRef); + var socketAddressSize = Unsafe.ReadUnaligned(ref Unsafe.Add(ref spanRef, 4)); + + if (buffer.Length < offset + 8 + socketAddressSize) { - var pOffsetBuffer = pBuffer + offset; - var addressFamily = (AddressFamily)Marshal.ReadInt32((IntPtr)pOffsetBuffer); - var socketAddressSize = Marshal.ReadInt32((IntPtr)(pOffsetBuffer + 4)); - - if (buffer.Length < offset + 8 + socketAddressSize) - { - throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", nameof(buffer)); - } - - socketAddress = new SocketAddress(addressFamily, socketAddressSize); - - for (var i = 0; i < socketAddressSize - 2; i++) - { - socketAddress[i + 2] = *(pOffsetBuffer + 8 + i); - } - - return 8 + offset + socketAddressSize; + throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", + nameof(buffer)); } + + socketAddress = new SocketAddress(addressFamily, socketAddressSize); + + for (var i = 0; i < socketAddressSize - 2; i++) + { + socketAddress[i + 2] = Unsafe.Add(ref spanRef, 8 + i); + } + + return 8 + offset + socketAddressSize; } catch (ArgumentNullException ex) { @@ -249,7 +251,7 @@ namespace Fantasy.Helper /// /// /// - public static unsafe IPEndPoint GetIPEndPoint(this SocketAddress socketAddress) + public static IPEndPoint GetIPEndPoint(this SocketAddress socketAddress) { switch (socketAddress.Family) { @@ -260,6 +262,7 @@ namespace Fantasy.Helper { ipBytes[i] = socketAddress[4 + i]; } + var port = (socketAddress[2] << 8) + socketAddress[3]; var ip = new IPAddress(ipBytes); return new IPEndPoint(ip, port); @@ -268,24 +271,23 @@ namespace Fantasy.Helper { var ipBytes = new byte[16]; Span socketAddressSpan = stackalloc byte[28]; - + for (var i = 0; i < 28; i++) { socketAddressSpan[i] = socketAddress[i]; } - - fixed (byte* pSocketAddress = socketAddressSpan) + + ref var spanRef = ref MemoryMarshal.GetReference(socketAddressSpan); + + for (var i = 0; i < 16; i++) { - for (var i = 0; i < 16; i++) - { - ipBytes[i] = *(pSocketAddress + 8 + i); - } - - var port = (*(pSocketAddress + 2) << 8) + *(pSocketAddress + 3); - var scopeId = Marshal.ReadInt64((IntPtr)(pSocketAddress + 24)); - var ip = new IPAddress(ipBytes, scopeId); - return new IPEndPoint(ip, port); + ipBytes[i] = Unsafe.Add(ref spanRef, 8 + i); } + + var port = (Unsafe.Add(ref spanRef, 2) << 8) + Unsafe.Add(ref spanRef, 3); + var scopeId = Unsafe.ReadUnaligned(ref Unsafe.Add(ref spanRef, 24)); + var ip = new IPAddress(ipBytes, scopeId); + return new IPEndPoint(ip, port); } default: { @@ -308,13 +310,13 @@ namespace Fantasy.Helper { continue; } - + foreach (var add in networkInterface.GetIPProperties().UnicastAddresses) { list.Add(add.Address.ToString()); } } - + return list.ToArray(); } @@ -363,7 +365,7 @@ namespace Fantasy.Helper { return; } - + /* 目前这个问题只有Windows下才会出现。 服务器端在发送数据时捕获到了一个异常, @@ -374,11 +376,11 @@ namespace Fantasy.Helper 想详细了解看下https://blog.csdn.net/sunzhen6251/article/details/124168805*/ const uint IOC_IN = 0x80000000; const uint IOC_VENDOR = 0x18000000; - const int SIO_UDP_CONNRESET = unchecked((int) (IOC_IN | IOC_VENDOR | 12)); - - socket.IOControl(SIO_UDP_CONNRESET, new[] {Convert.ToByte(false)}, null); + const int SIO_UDP_CONNRESET = unchecked((int)(IOC_IN | IOC_VENDOR | 12)); + + socket.IOControl(SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null); } - + /// /// 将 Socket 缓冲区大小设置为操作系统限制。 /// @@ -440,4 +442,4 @@ namespace Fantasy.Helper } } } -#endif \ No newline at end of file +#endif diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/RandomHelper.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/RandomHelper.cs index c90a16c..b07ffb8 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/RandomHelper.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/RandomHelper.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using Fantasy.LowLevel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #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. namespace Fantasy.Helper @@ -307,5 +309,107 @@ namespace Fantasy.Helper return num.ToString(); } } + + #region FixedBytes + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes1 + { + private byte _e0; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes2 + { + private FixedBytes1 _e0; + private FixedBytes1 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes4 + { + private FixedBytes2 _e0; + private FixedBytes2 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes8 + { + private FixedBytes4 _e0; + private FixedBytes4 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes16 + { + private FixedBytes8 _e0; + private FixedBytes8 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes32 + { + private FixedBytes16 _e0; + private FixedBytes16 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes64 + { + private FixedBytes32 _e0; + private FixedBytes32 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes128 + { + private FixedBytes64 _e0; + private FixedBytes64 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes256 + { + private FixedBytes128 _e0; + private FixedBytes128 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes512 + { + private FixedBytes256 _e0; + private FixedBytes256 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + [StructLayout(LayoutKind.Sequential)] + public struct FixedBytes1024 + { + private FixedBytes512 _e0; + private FixedBytes512 _e1; + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); + } + + #endregion } #endif \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryHelper.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryHelper.cs index 4251d53..c60da0b 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryHelper.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryHelper.cs @@ -47,6 +47,15 @@ namespace Fantasy.IdFactory } } + /// + /// 获得当前的IdFactoryType + /// + /// + public static IdFactoryType GetIdFactoryType() + { + return _idFactoryType; + } + internal static IEntityIdFactory EntityIdFactory(uint sceneId, byte worldId) { switch (_idFactoryType) diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/Log.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/Log.cs index 8069fff..3b9cc15 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/Log.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/Log.cs @@ -27,23 +27,7 @@ namespace Fantasy return; } - var processMode = ProcessMode.None; - - switch (ProcessDefine.Options.Mode) - { - case "Develop": - { - processMode = ProcessMode.Develop; - break; - } - case "Release": - { - processMode = ProcessMode.Release; - break; - } - } - - _logCore.Initialize(processMode); + _logCore.Initialize(ProgramDefine.RuntimeMode); } #endif /// diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/FantasyMemory.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/FantasyMemory.cs deleted file mode 100644 index cadfd16..0000000 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/FantasyMemory.cs +++ /dev/null @@ -1,267 +0,0 @@ -#if FANTASY_NET -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using mimalloc; -#if NET7_0_OR_GREATER -using System.Runtime.Intrinsics; -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#endif - -namespace Fantasy.LowLevel -{ - public static unsafe class FantasyMemory - { - private static delegate* managed _alloc; - private static delegate* managed _allocZeroed; - private static delegate* managed _free; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Initialize() - { - // KCP 使用 FantasyMemory - kcp.KCP.ikcp_allocator(&Alloc, &Free); - - try - { - _ = MiMalloc.mi_version(); - } - catch - { - Log.Info("mimalloc的二进制文件丢失"); - return; - } - - try - { - var ptr = MiMalloc.mi_malloc(MiMalloc.MI_SMALL_SIZE_MAX); - MiMalloc.mi_free(ptr); - } - catch - { - Log.Info("mimalloc权限不足,\r\n可能的问题:\r\n1. 禁止了虚拟内存分配 -> 允许虚拟内存分配;\r\n2. 没有硬盘读写权限 -> 管理员获取所有权限"); - return; - } - - Custom(&MiAlloc, &MiAllocZeroed, &MiFree); - - return; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void* MiAlloc(nuint size) => MiMalloc.mi_malloc(size); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void* MiAllocZeroed(nuint size) - { - var ptr = MiAlloc(size); - Unsafe.InitBlockUnaligned(ptr, 0, (uint)size); - return ptr; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void MiFree(void* ptr) => MiMalloc.mi_free(ptr); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Custom(delegate* alloc, delegate* allocZeroed, delegate* free) - { - _alloc = alloc; - _allocZeroed = allocZeroed; - _free = free; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static nuint Align(nuint size) => AlignUp(size, (nuint)sizeof(nint)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static nuint AlignUp(nuint size, nuint alignment) => (size + (alignment - 1)) & ~(alignment - 1); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static nuint AlignDown(nuint size, nuint alignment) => size - (size & (alignment - 1)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void* Alloc(nuint byteCount) - { - if (_alloc != null) - return _alloc(byteCount); -#if NET6_0_OR_GREATER - return NativeMemory.Alloc(byteCount); -#else - return (void*)Marshal.AllocHGlobal((nint)byteCount); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void* AllocZeroed(nuint byteCount) - { - if (_allocZeroed != null) - return _allocZeroed(byteCount); - void* ptr; - if (_alloc != null) - { - ptr = _alloc(byteCount); - Unsafe.InitBlockUnaligned(ptr, 0, (uint)byteCount); - return ptr; - } -#if NET6_0_OR_GREATER - return NativeMemory.AllocZeroed(byteCount, 1); -#else - ptr = (void*)Marshal.AllocHGlobal((nint)byteCount); - Unsafe.InitBlockUnaligned(ptr, 0, (uint)byteCount); - return ptr; -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Free(void* ptr) - { - if (_free != null) - { - _free(ptr); - return; - } -#if NET6_0_OR_GREATER - NativeMemory.Free(ptr); -#else - Marshal.FreeHGlobal((nint)ptr); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Copy(void* destination, void* source, nuint byteCount) => Unsafe.CopyBlockUnaligned(destination, source, (uint)byteCount); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Move(void* destination, void* source, nuint byteCount) => Buffer.MemoryCopy(source, destination, byteCount, byteCount); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Set(void* startAddress, byte value, nuint byteCount) => Unsafe.InitBlockUnaligned(startAddress, value, (uint)byteCount); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool Compare(void* left, void* right, nuint byteCount) - { - ref var first = ref *(byte*)left; - ref var second = ref *(byte*)right; - if (byteCount >= (nuint)sizeof(nuint)) - { - if (!Unsafe.AreSame(ref first, ref second)) - { -#if NET7_0_OR_GREATER - if (Vector128.IsHardwareAccelerated) - { -#if NET8_0_OR_GREATER - if (Vector512.IsHardwareAccelerated && byteCount >= (nuint)Vector512.Count) - { - nuint offset = 0; - var lengthToExamine = byteCount - (nuint)Vector512.Count; - if (lengthToExamine != 0) - { - do - { - if (Vector512.LoadUnsafe(ref first, offset) != Vector512.LoadUnsafe(ref second, offset)) - return false; - offset += (nuint)Vector512.Count; - } while (lengthToExamine > offset); - } - return Vector512.LoadUnsafe(ref first, lengthToExamine) == Vector512.LoadUnsafe(ref second, lengthToExamine); - } -#endif - if (Vector256.IsHardwareAccelerated && byteCount >= (nuint)Vector256.Count) - { - nuint offset = 0; - var lengthToExamine = byteCount - (nuint)Vector256.Count; - if (lengthToExamine != 0) - { - do - { - if (Vector256.LoadUnsafe(ref first, offset) != Vector256.LoadUnsafe(ref second, offset)) - return false; - offset += (nuint)Vector256.Count; - } while (lengthToExamine > offset); - } - return Vector256.LoadUnsafe(ref first, lengthToExamine) == Vector256.LoadUnsafe(ref second, lengthToExamine); - } - if (byteCount >= (nuint)Vector128.Count) - { - nuint offset = 0; - var lengthToExamine = byteCount - (nuint)Vector128.Count; - if (lengthToExamine != 0) - { - do - { - if (Vector128.LoadUnsafe(ref first, offset) != Vector128.LoadUnsafe(ref second, offset)) - return false; - offset += (nuint)Vector128.Count; - } while (lengthToExamine > offset); - } - return Vector128.LoadUnsafe(ref first, lengthToExamine) == Vector128.LoadUnsafe(ref second, lengthToExamine); - } - } - if (sizeof(nint) == 8 && Vector128.IsHardwareAccelerated) - { - var offset = byteCount - (nuint)sizeof(nuint); - var differentBits = Unsafe.ReadUnaligned(ref first) - Unsafe.ReadUnaligned(ref second); - differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset)); - return differentBits == 0; - } - else -#endif - { - nuint offset = 0; - var lengthToExamine = byteCount - (nuint)sizeof(nuint); - if (lengthToExamine > 0) - { - do - { -#if NET7_0_OR_GREATER - if (Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) != Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset))) -#else - if (Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)offset)) != Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)offset))) -#endif - return false; - offset += (nuint)sizeof(nuint); - } while (lengthToExamine > offset); - } -#if NET7_0_OR_GREATER - return Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, lengthToExamine)) == Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, lengthToExamine)); -#else - return Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)lengthToExamine)) == Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)lengthToExamine)); -#endif - } - } - - return true; - } - - if (byteCount < sizeof(uint) || sizeof(nint) != 8) - { - uint differentBits = 0; - var offset = byteCount & 2; - if (offset != 0) - { - differentBits = Unsafe.ReadUnaligned(ref first); - differentBits -= Unsafe.ReadUnaligned(ref second); - } - - if ((byteCount & 1) != 0) -#if NET7_0_OR_GREATER - differentBits |= Unsafe.AddByteOffset(ref first, offset) - (uint)Unsafe.AddByteOffset(ref second, offset); -#else - differentBits |= Unsafe.AddByteOffset(ref first, (nint)offset) - (uint)Unsafe.AddByteOffset(ref second, (nint)offset); -#endif - return differentBits == 0; - } - else - { - var offset = byteCount - sizeof(uint); - var differentBits = Unsafe.ReadUnaligned(ref first) - Unsafe.ReadUnaligned(ref second); -#if NET7_0_OR_GREATER - differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset)); -#else - differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)offset)); -#endif - return differentBits == 0; - } - } - } -} -#endif diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/FixedBytes.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/FixedBytes.cs deleted file mode 100644 index 7c5a7a4..0000000 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/FixedBytes.cs +++ /dev/null @@ -1,107 +0,0 @@ -#if FANTASY_NET || !FANTASY_WEBGL -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - -namespace Fantasy.LowLevel -{ - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes1 - { - private byte _e0; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes2 - { - private FixedBytes1 _e0; - private FixedBytes1 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes4 - { - private FixedBytes2 _e0; - private FixedBytes2 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes8 - { - private FixedBytes4 _e0; - private FixedBytes4 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes16 - { - private FixedBytes8 _e0; - private FixedBytes8 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes32 - { - private FixedBytes16 _e0; - private FixedBytes16 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes64 - { - private FixedBytes32 _e0; - private FixedBytes32 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes128 - { - private FixedBytes64 _e0; - private FixedBytes64 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes256 - { - private FixedBytes128 _e0; - private FixedBytes128 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes512 - { - private FixedBytes256 _e0; - private FixedBytes256 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FixedBytes1024 - { - private FixedBytes512 _e0; - private FixedBytes512 _e1; - - public Span AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As(ref Unsafe.AsRef(in this)), Unsafe.SizeOf()); - } -} -#endif \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/XxHash.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/XxHash.cs deleted file mode 100644 index dff36b3..0000000 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/LowLevel/XxHash.cs +++ /dev/null @@ -1,171 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -#pragma warning disable CS1591 - -namespace Fantasy.LowLevel -{ - public static class XxHash - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Hash32(string obj, uint seed = 0) => Hash32(obj.AsSpan(), seed); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Hash32(in T obj, uint seed = 0) where T : unmanaged => Hash32(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf()), seed); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Hash32(ReadOnlySpan buffer, uint seed = 0) where T : unmanaged => Hash32(MemoryMarshal.Cast(buffer), seed); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Hash32(ReadOnlySpan buffer, uint seed = 0) - { - int length = buffer.Length; - ref byte local1 = ref MemoryMarshal.GetReference(buffer); - uint num1; - if (buffer.Length >= 16) - { - uint num2 = seed + 606290984U; - uint num3 = seed + 2246822519U; - uint num4 = seed; - uint num5 = seed - 2654435761U; - for (; length >= 16; length -= 16) - { - const nint elementOffset1 = 4; - const nint elementOffset2 = 8; - const nint elementOffset3 = 12; - nint byteOffset = buffer.Length - length; - ref byte local2 = ref Unsafe.AddByteOffset(ref local1, byteOffset); - uint num6 = num2 + Unsafe.ReadUnaligned(ref local2) * 2246822519U; - num2 = (uint)((((int)num6 << 13) | (int)(num6 >> 19)) * -1640531535); - uint num7 = num3 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, elementOffset1)) * 2246822519U; - num3 = (uint)((((int)num7 << 13) | (int)(num7 >> 19)) * -1640531535); - uint num8 = num4 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, elementOffset2)) * 2246822519U; - num4 = (uint)((((int)num8 << 13) | (int)(num8 >> 19)) * -1640531535); - uint num9 = num5 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, elementOffset3)) * 2246822519U; - num5 = (uint)((((int)num9 << 13) | (int)(num9 >> 19)) * -1640531535); - } - - num1 = (uint)((((int)num2 << 1) | (int)(num2 >> 31)) + (((int)num3 << 7) | (int)(num3 >> 25)) + (((int)num4 << 12) | (int)(num4 >> 20)) + (((int)num5 << 18) | (int)(num5 >> 14)) + buffer.Length); - } - else - num1 = (uint)((int)seed + 374761393 + buffer.Length); - - for (; length >= 4; length -= 4) - { - nint byteOffset = buffer.Length - length; - uint num10 = Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local1, byteOffset)); - uint num11 = num1 + num10 * 3266489917U; - num1 = (uint)((((int)num11 << 17) | (int)(num11 >> 15)) * 668265263); - } - - nint byteOffset1 = buffer.Length - length; - ref byte local3 = ref Unsafe.AddByteOffset(ref local1, byteOffset1); - for (int index = 0; index < length; ++index) - { - nint byteOffset2 = index; - uint num12 = Unsafe.AddByteOffset(ref local3, byteOffset2); - uint num13 = num1 + num12 * 374761393U; - num1 = (uint)((((int)num13 << 11) | (int)(num13 >> 21)) * -1640531535); - } - -#if NET7_0_OR_GREATER - int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777; - int num15 = (num14 ^ (num14 >>> 13)) * -1028477379; - return num15 ^ (num15 >>> 16); -#else - int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777; - int num15 = (num14 ^ (int)((uint)num14 >> 13)) * -1028477379; - return num15 ^ (int)((uint)num15 >> 16); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long Hash64(string obj, ulong seed = 0) => Hash64(obj.AsSpan(), seed); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long Hash64(in T obj, ulong seed = 0) where T : unmanaged => Hash64(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf()), seed); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long Hash64(ReadOnlySpan buffer, ulong seed = 0) where T : unmanaged => Hash64(MemoryMarshal.Cast(buffer), seed); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long Hash64(ReadOnlySpan buffer, ulong seed = 0) - { - ref var local1 = ref MemoryMarshal.GetReference(buffer); - var length = buffer.Length; - ulong num1; - if (buffer.Length >= 32) - { - var num2 = seed + 6983438078262162902UL; - var num3 = seed + 14029467366897019727UL; - var num4 = seed; - var num5 = seed - 11400714785074694791UL; - for (; length >= 32; length -= 32) - { - ref var local2 = ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length)); - var num6 = num2 + Unsafe.ReadUnaligned(ref local2) * 14029467366897019727UL; - num2 = (ulong)((((long)num6 << 31) | (long)(num6 >> 33)) * -7046029288634856825L); - var num7 = num3 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(8U))) * 14029467366897019727UL; - num3 = (ulong)((((long)num7 << 31) | (long)(num7 >> 33)) * -7046029288634856825L); - var num8 = num4 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(16U))) * 14029467366897019727UL; - num4 = (ulong)((((long)num8 << 31) | (long)(num8 >> 33)) * -7046029288634856825L); - var num9 = num5 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(24U))) * 14029467366897019727UL; - num5 = (ulong)((((long)num9 << 31) | (long)(num9 >> 33)) * -7046029288634856825L); - } - - var num10 = (((long)num2 << 1) | (long)(num2 >> 63)) + (((long)num3 << 7) | (long)(num3 >> 57)) + (((long)num4 << 12) | (long)(num4 >> 52)) + (((long)num5 << 18) | (long)(num5 >> 46)); - var num11 = num2 * 14029467366897019727UL; - var num12 = (((long)num11 << 31) | (long)(num11 >> 33)) * -7046029288634856825L; - var num13 = (num10 ^ num12) * -7046029288634856825L + -8796714831421723037L; - var num14 = num3 * 14029467366897019727UL; - var num15 = (((long)num14 << 31) | (long)(num14 >> 33)) * -7046029288634856825L; - var num16 = (num13 ^ num15) * -7046029288634856825L + -8796714831421723037L; - var num17 = num4 * 14029467366897019727UL; - var num18 = (((long)num17 << 31) | (long)(num17 >> 33)) * -7046029288634856825L; - var num19 = (num16 ^ num18) * -7046029288634856825L + -8796714831421723037L; - var num20 = num5 * 14029467366897019727UL; - var num21 = (((long)num20 << 31) | (long)(num20 >> 33)) * -7046029288634856825L; - num1 = (ulong)((num19 ^ num21) * -7046029288634856825L + -8796714831421723037L); - } - else - num1 = seed + 2870177450012600261UL; - - var num22 = num1 + (ulong)buffer.Length; - for (; length >= 8; length -= 8) - { - var num23 = Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length))) * 14029467366897019727UL; - var num24 = (ulong)((((long)num23 << 31) | (long)(num23 >> 33)) * -7046029288634856825L); - var num25 = num22 ^ num24; - num22 = (ulong)((((long)num25 << 27) | (long)(num25 >> 37)) * -7046029288634856825L + -8796714831421723037L); - } - - if (length >= 4) - { - ulong num26 = Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length))); - var num27 = num22 ^ (num26 * 11400714785074694791UL); - num22 = (ulong)((((long)num27 << 23) | (long)(num27 >> 41)) * -4417276706812531889L + 1609587929392839161L); - length -= 4; - } - - for (var byteOffset = 0; byteOffset < length; ++byteOffset) - { - ulong num28 = Unsafe.AddByteOffset(ref Unsafe.AddByteOffset(ref local1, (IntPtr)(buffer.Length - length)), (IntPtr)byteOffset); - var num29 = num22 ^ (num28 * 2870177450012600261UL); - num22 = (ulong)((((long)num29 << 11) | (long)(num29 >> 53)) * -7046029288634856825L); - } - -#if NET7_0_OR_GREATER - var num30 = (long)num22; - var num31 = (num30 ^ (num30 >>> 33)) * -4417276706812531889L; - var num32 = (num31 ^ (num31 >>> 29)) * 1609587929392839161L; - return num32 ^ (num32 >>> 32); -#else - var num30 = (long)num22; - var num31 = (num30 ^ (long)((ulong)num30 >> 33)) * -4417276706812531889L; - var num32 = (num31 ^ (long)((ulong)num31 >> 29)) * 1609587929392839161L; - return num32 ^ (long)((ulong)num32 >> 32); -#endif - } - } -} \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs index 4a367b2..839cf6b 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs @@ -65,7 +65,7 @@ namespace Fantasy.Network.Interface if (entity is not TEntity tEntity) { - Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}"); return; } @@ -128,7 +128,7 @@ namespace Fantasy.Network.Interface if (entity is not TEntity tEntity) { - Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}"); return; } @@ -216,7 +216,7 @@ namespace Fantasy.Network.Interface if (entity is not TEntity tEntity) { - Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}"); return; } @@ -281,7 +281,7 @@ namespace Fantasy.Network.Interface if (entity is not TEntity tEntity) { - Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}"); return; } @@ -368,7 +368,7 @@ namespace Fantasy.Network.Interface if (entity is not TEntity tEntity) { - Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}"); return; } @@ -433,7 +433,7 @@ namespace Fantasy.Network.Interface if (entity is not TEntity tEntity) { - Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + Log.Error($"{this.GetType().Name} Route type conversion error: {entity.GetType().Name} to {typeof(TEntity).Name}"); return; } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/InnerMessage.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/InnerMessage.cs index 9a095a4..643c92b 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/InnerMessage.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/InnerMessage.cs @@ -5,7 +5,6 @@ using ProtoBuf; #if FANTASY_NET using Fantasy.Network.Roaming; #endif - #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. // ReSharper disable InconsistentNaming // ReSharper disable PropertyCanBeMadeInitOnly.Global @@ -22,7 +21,6 @@ namespace Fantasy.InnerMessage return Fantasy.Network.OpCode.BenchmarkMessage; } } - [ProtoContract] public partial class BenchmarkRequest : AMessage, IRequest { @@ -30,11 +28,12 @@ namespace Fantasy.InnerMessage { return Fantasy.Network.OpCode.BenchmarkRequest; } - - [ProtoIgnore] public BenchmarkResponse ResponseType { get; set; } - [ProtoMember(1)] public long RpcId { get; set; } + [ProtoIgnore] + public BenchmarkResponse ResponseType { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } } - + [ProtoContract] public partial class BenchmarkResponse : AMessage, IResponse { @@ -42,22 +41,22 @@ namespace Fantasy.InnerMessage { return Fantasy.Network.OpCode.BenchmarkResponse; } - - [ProtoMember(1)] public long RpcId { get; set; } - [ProtoMember(2)] public uint ErrorCode { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } } - public sealed partial class Response : AMessage, IResponse { public uint OpCode() { return Fantasy.Network.OpCode.DefaultResponse; } - - [ProtoMember(1)] public long RpcId { get; set; } - [ProtoMember(2)] public uint ErrorCode { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } } - [ProtoContract] public sealed partial class RouteResponse : AMessage, IRouteResponse { @@ -65,11 +64,11 @@ namespace Fantasy.InnerMessage { return Fantasy.Network.OpCode.DefaultRouteResponse; } - - [ProtoMember(1)] public long RpcId { get; set; } - [ProtoMember(2)] public uint ErrorCode { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } } - [ProtoContract] public partial class PingRequest : AMessage, IRequest { @@ -77,11 +76,12 @@ namespace Fantasy.InnerMessage { return Fantasy.Network.OpCode.PingRequest; } - - [ProtoIgnore] public PingResponse ResponseType { get; set; } - [ProtoMember(1)] public long RpcId { get; set; } + [ProtoIgnore] + public PingResponse ResponseType { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } } - + [ProtoContract] public partial class PingResponse : AMessage, IResponse { @@ -89,334 +89,231 @@ namespace Fantasy.InnerMessage { return Fantasy.Network.OpCode.PingResponse; } - - [ProtoMember(1)] public long RpcId { get; set; } - [ProtoMember(2)] public uint ErrorCode { get; set; } - [ProtoMember(3)] public long Now; + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + [ProtoMember(3)] + public long Now; } - [ProtoContract] public partial class I_AddressableAdd_Request : AMessage, IRouteRequest { - [ProtoIgnore] public I_AddressableAdd_Response ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableAddRequest; - } - - public long RouteTypeOpCode() - { - return 1; - } - - [ProtoMember(1)] public long AddressableId { get; set; } - [ProtoMember(2)] public long RouteId { get; set; } - [ProtoMember(3)] public bool IsLock { get; set; } + [ProtoIgnore] + public I_AddressableAdd_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableAddRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + [ProtoMember(2)] + public long RouteId { get; set; } + [ProtoMember(3)] + public bool IsLock { get; set; } } - [ProtoContract] public partial class I_AddressableAdd_Response : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableAddResponse; - } - - [ProtoMember(1)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableAddResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } } - [ProtoContract] public partial class I_AddressableGet_Request : AMessage, IRouteRequest { - [ProtoIgnore] public I_AddressableGet_Response ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableGetRequest; - } - - public long RouteTypeOpCode() - { - return 1; - } - - [ProtoMember(1)] public long AddressableId { get; set; } + [ProtoIgnore] + public I_AddressableGet_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableGetRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } } - [ProtoContract] public partial class I_AddressableGet_Response : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableGetResponse; - } - - [ProtoMember(2)] public uint ErrorCode { get; set; } - [ProtoMember(1)] public long RouteId { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableGetResponse; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + [ProtoMember(1)] + public long RouteId { get; set; } } - [ProtoContract] public partial class I_AddressableRemove_Request : AMessage, IRouteRequest { - [ProtoIgnore] public I_AddressableRemove_Response ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableRemoveRequest; - } - - public long RouteTypeOpCode() - { - return 1; - } - - [ProtoMember(1)] public long AddressableId { get; set; } + [ProtoIgnore] + public I_AddressableRemove_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableRemoveRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } } - [ProtoContract] public partial class I_AddressableRemove_Response : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableRemoveResponse; - } - - [ProtoMember(1)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableRemoveResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } } - [ProtoContract] public partial class I_AddressableLock_Request : AMessage, IRouteRequest { - [ProtoIgnore] public I_AddressableLock_Response ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableLockRequest; - } - - public long RouteTypeOpCode() - { - return 1; - } - - [ProtoMember(1)] public long AddressableId { get; set; } + [ProtoIgnore] + public I_AddressableLock_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableLockRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } } - [ProtoContract] public partial class I_AddressableLock_Response : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableLockResponse; - } - - [ProtoMember(1)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableLockResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } } - [ProtoContract] public partial class I_AddressableUnLock_Request : AMessage, IRouteRequest { - [ProtoIgnore] public I_AddressableUnLock_Response ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableUnLockRequest; - } - - public long RouteTypeOpCode() - { - return 1; - } - - [ProtoMember(1)] public long AddressableId { get; set; } - [ProtoMember(2)] public long RouteId { get; set; } - [ProtoMember(3)] public string Source { get; set; } + [ProtoIgnore] + public I_AddressableUnLock_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableUnLockRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + [ProtoMember(2)] + public long RouteId { get; set; } + [ProtoMember(3)] + public string Source { get; set; } } - [ProtoContract] public partial class I_AddressableUnLock_Response : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.AddressableUnLockResponse; - } - - [ProtoMember(1)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableUnLockResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } } #if FANTASY_NET [ProtoContract] public sealed class I_LinkRoamingRequest : AMessage, IRouteRequest { - [ProtoIgnore] public I_LinkRoamingResponse ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.LinkRoamingRequest; - } - - public long RouteTypeOpCode() - { - return 1; - } - - [ProtoMember(1)] public long RoamingId { get; set; } - [ProtoMember(2)] public int RoamingType { get; set; } - [ProtoMember(3)] public long ForwardSessionRouteId { get; set; } - [ProtoMember(4)] public long SceneRouteId { get; set; } + [ProtoIgnore] + public I_LinkRoamingResponse ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.LinkRoamingRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long RoamingId { get; set; } + [ProtoMember(2)] + public int RoamingType { get; set; } + [ProtoMember(3)] + public long ForwardSessionRouteId { get; set; } + [ProtoMember(4)] + public long SceneRouteId { get; set; } } - [ProtoContract] public sealed class I_LinkRoamingResponse : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.LinkRoamingResponse; - } - - [ProtoMember(1)] public long TerminusId { get; set; } - [ProtoMember(2)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.LinkRoamingResponse; } + [ProtoMember(1)] + public long TerminusId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } } - [ProtoContract] public sealed class I_UnLinkRoamingRequest : AMessage, IRouteRequest { - [ProtoIgnore] public I_UnLinkRoamingResponse ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.UnLinkRoamingRequest; - } - - public long RouteTypeOpCode() - { - return 1; - } - - [ProtoMember(1)] public long RoamingId { get; set; } - [ProtoMember(2)] public bool DisposeRoaming { get; set; } + [ProtoIgnore] + public I_UnLinkRoamingResponse ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.UnLinkRoamingRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long RoamingId { get; set; } + [ProtoMember(2)] + public bool DisposeRoaming { get; set; } } - [ProtoContract] public sealed class I_UnLinkRoamingResponse : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.UnLinkRoamingResponse; - } - - [ProtoMember(1)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.UnLinkRoamingResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } } - [ProtoContract] public partial class I_LockTerminusIdRequest : AMessage, IRouteRequest { - [ProtoIgnore] public I_LockTerminusIdResponse ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.LockTerminusIdRequest; - } - - [ProtoMember(1)] public long SessionRuntimeId { get; set; } - [ProtoMember(2)] public int RoamingType { get; set; } + [ProtoIgnore] + public I_LockTerminusIdResponse ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.LockTerminusIdRequest; } + [ProtoMember(1)] + public long SessionRuntimeId { get; set; } + [ProtoMember(2)] + public int RoamingType { get; set; } } - [ProtoContract] public partial class I_LockTerminusIdResponse : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.LockTerminusIdResponse; - } - - [ProtoMember(1)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.LockTerminusIdResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } } - [ProtoContract] public sealed class I_UnLockTerminusIdRequest : AMessage, IRouteRequest { - [ProtoIgnore] public I_UnLockTerminusIdResponse ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.UnLockTerminusIdRequest; - } - - public long RouteTypeOpCode() - { - return 1; - } - - [ProtoMember(1)] public long SessionRuntimeId { get; set; } - [ProtoMember(2)] public int RoamingType { get; set; } - [ProtoMember(3)] public long TerminusId { get; set; } - [ProtoMember(4)] public long TargetSceneRouteId { get; set; } + [ProtoIgnore] + public I_UnLockTerminusIdResponse ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.UnLockTerminusIdRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long SessionRuntimeId { get; set; } + [ProtoMember(2)] + public int RoamingType { get; set; } + [ProtoMember(3)] + public long TerminusId { get; set; } + [ProtoMember(4)] + public long TargetSceneRouteId { get; set; } } - [ProtoContract] public sealed class I_UnLockTerminusIdResponse : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.UnLockTerminusIdResponse; - } - - [ProtoMember(1)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.UnLockTerminusIdResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } } - /// /// 漫游传送终端的请求 /// public partial class I_TransferTerminusRequest : AMessage, IRouteRequest { - [BsonIgnore] public I_TransferTerminusResponse ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.TransferTerminusRequest; - } - + [BsonIgnore] + public I_TransferTerminusResponse ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.TransferTerminusRequest; } public Terminus Terminus { get; set; } } - public partial class I_TransferTerminusResponse : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.TransferTerminusResponse; - } - + public uint OpCode() { return Fantasy.Network.OpCode.TransferTerminusResponse; } public uint ErrorCode { get; set; } } - /// /// 用于服务器之间获取漫游的TerminusId。 /// [ProtoContract] public partial class I_GetTerminusIdRequest : AMessage, IRouteRequest { - [ProtoIgnore] public I_GetTerminusIdResponse ResponseType { get; set; } - - public uint OpCode() - { - return Fantasy.Network.OpCode.GetTerminusIdRequest; - } - - [ProtoMember(1)] public int RoamingType { get; set; } - [ProtoMember(2)] public long SessionRuntimeId { get; set; } + [ProtoIgnore] + public I_GetTerminusIdResponse ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.GetTerminusIdRequest; } + [ProtoMember(1)] + public int RoamingType { get; set; } + [ProtoMember(2)] + public long SessionRuntimeId { get; set; } } - [ProtoContract] public partial class I_GetTerminusIdResponse : AMessage, IRouteResponse { - public uint OpCode() - { - return Fantasy.Network.OpCode.GetTerminusIdResponse; - } - - [ProtoMember(1)] public long TerminusId { get; set; } - [ProtoMember(2)] public uint ErrorCode { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.GetTerminusIdResponse; } + [ProtoMember(1)] + public long TerminusId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } } #endif } \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs index e4d1540..b1c6c84 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs @@ -73,21 +73,21 @@ namespace Fantasy.PacketParser return false; } - fixed (byte* bufferPtr = buffer) - { - MessagePacketLength = *(int*)bufferPtr; + var span = buffer.AsSpan(); + ref var bufferRef = ref MemoryMarshal.GetReference(span); + + MessagePacketLength = Unsafe.ReadUnaligned(ref bufferRef); - if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) - { - // 检查消息体长度是否超出限制 - throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); - } - - ProtocolCode = *(uint*)(bufferPtr + Packet.PacketLength); - RpcId = *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation); - RouteId = *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation); + if (MessagePacketLength > ProgramDefine.MaxMessageSize || count < MessagePacketLength) + { + // 检查消息体长度是否超出限制 + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); } + ProtocolCode = Unsafe.ReadUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength)); + RpcId = Unsafe.ReadUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation)); + RouteId = Unsafe.ReadUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation)); + packInfo = InnerPackInfo.Create(Network); packInfo.RpcId = RpcId; packInfo.RouteId = RouteId; @@ -102,19 +102,19 @@ namespace Fantasy.PacketParser } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream) + private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream) { - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; - *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; - } + var buffer = memoryStream.GetBuffer(); + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); + + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation), routeId); return memoryStream; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message) + private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message) { var memoryStreamLength = 0; var messageType = message.GetType(); @@ -142,19 +142,19 @@ namespace Fantasy.PacketParser packetBodyCount = -1; } - if (packetBodyCount > Packet.PacketBodyMaxLength) + if (packetBodyCount > ProgramDefine.MaxMessageSize) { // 检查消息体长度是否超出限制 - throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes"); } - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(int*)bufferPtr = packetBodyCount; - *(uint*)(bufferPtr + Packet.PacketLength) = opCode; - *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; - *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; - } + var buffer = memoryStream.GetBuffer(); + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); + + Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation), routeId); return memoryStream; } @@ -173,7 +173,7 @@ namespace Fantasy.PacketParser /// /// /// - public override unsafe bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo) + public override bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo) { packInfo = null; @@ -188,19 +188,19 @@ namespace Fantasy.PacketParser return false; } - fixed (byte* bufferPtr = buffer) + var span = buffer.AsSpan(); + ref var bufferRef = ref MemoryMarshal.GetReference(span); + + MessagePacketLength = Unsafe.ReadUnaligned(ref bufferRef); + + if (MessagePacketLength > ProgramDefine.MaxMessageSize || count < MessagePacketLength) { - MessagePacketLength = *(int*)bufferPtr; - - if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) - { - // 检查消息体长度是否超出限制 - throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); - } - - ProtocolCode = *(uint*)(bufferPtr + Packet.PacketLength); - RpcId = *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation); + // 检查消息体长度是否超出限制 + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); } + + ProtocolCode = Unsafe.ReadUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength)); + RpcId = Unsafe.ReadUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation)); packInfo = OuterPackInfo.Create(Network); packInfo.RpcId = RpcId; @@ -213,20 +213,22 @@ namespace Fantasy.PacketParser { return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream); } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) + private MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) { - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; - } - + var buffer = memoryStream.GetBuffer(); +#if FANTASY_UNITY + ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan()); +#else + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); +#endif + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId); return memoryStream; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe MemoryStreamBuffer Pack(ref uint rpcId, IMessage message) + private MemoryStreamBuffer Pack(ref uint rpcId, IMessage message) { var memoryStreamLength = 0; var messageType = message.GetType(); @@ -254,18 +256,21 @@ namespace Fantasy.PacketParser packetBodyCount = -1; } - if (packetBodyCount > Packet.PacketBodyMaxLength) + if (packetBodyCount > ProgramDefine.MaxMessageSize) { // 检查消息体长度是否超出限制 - throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes"); } - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(int*)bufferPtr = packetBodyCount; - *(uint*)(bufferPtr + Packet.PacketLength) = opCode; - *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; - } + var buffer = memoryStream.GetBuffer(); +#if FANTASY_UNITY + ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan()); +#else + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); +#endif + Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId); return memoryStream; } @@ -298,16 +303,19 @@ namespace Fantasy.PacketParser return false; } - MessagePacketLength = BitConverter.ToInt32(buffer, 0); + var span = buffer.AsSpan(); + ref var bufferRef = ref MemoryMarshal.GetReference(span); - if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) + MessagePacketLength = Unsafe.ReadUnaligned(ref bufferRef); + + if (MessagePacketLength > ProgramDefine.MaxMessageSize || count < MessagePacketLength) { // 检查消息体长度是否超出限制 throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); } - ProtocolCode = BitConverter.ToUInt32(buffer, Packet.PacketLength); - RpcId = BitConverter.ToUInt32(buffer, Packet.OuterPacketRpcIdLocation); + ProtocolCode = Unsafe.ReadUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength)); + RpcId = Unsafe.ReadUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation)); packInfo = OuterPackInfo.Create(Network); packInfo.RpcId = RpcId; @@ -363,23 +371,21 @@ namespace Fantasy.PacketParser packetBodyCount = -1; } - if (packetBodyCount > Packet.PacketBodyMaxLength) + if (packetBodyCount > ProgramDefine.MaxMessageSize) { // 检查消息体长度是否超出限制 - throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes"); } - var buffer = memoryStream.GetBuffer().AsSpan(); -#if FANTASY_NET - MemoryMarshal.Write(buffer, in packetBodyCount); - MemoryMarshal.Write(buffer.Slice(Packet.PacketLength, sizeof(uint)), in opCode); - MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), in rpcId); -#endif + var buffer = memoryStream.GetBuffer(); #if FANTASY_UNITY - MemoryMarshal.Write(buffer, ref packetBodyCount); - MemoryMarshal.Write(buffer.Slice(Packet.PacketLength, sizeof(uint)), ref opCode); - MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), ref rpcId); -#endif + ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan()); +#else + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); +#endif + Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId); return memoryStream; } } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs index a6e66ca..0047c39 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs @@ -1,5 +1,6 @@ #if FANTASY_NET using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Fantasy.Helper; using Fantasy.Network; using Fantasy.Network.Interface; @@ -22,7 +23,7 @@ namespace Fantasy.PacketParser /// 打包完成会返回一个MemoryStreamBuffer /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe MemoryStreamBuffer Pack(Scene scene, uint rpcId, IMessage message, out int memoryStreamLength) + public static MemoryStreamBuffer Pack(Scene scene, uint rpcId, IMessage message, out int memoryStreamLength) { memoryStreamLength = 0; var messageType = message.GetType(); @@ -51,18 +52,18 @@ namespace Fantasy.PacketParser packetBodyCount = -1; } - if (packetBodyCount > Packet.PacketBodyMaxLength) + if (packetBodyCount > ProgramDefine.MaxMessageSize) { // 检查消息体长度是否超出限制 - throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes"); } - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(int*)bufferPtr = packetBodyCount; - *(uint*)(bufferPtr + Packet.PacketLength) = opCode; - *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; - } + var buffer = memoryStream.GetBuffer(); + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); + + Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId); return memoryStream; } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs index 758ec17..dc2203b 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs @@ -47,56 +47,61 @@ namespace Fantasy.PacketParser #if FANTASY_NET internal sealed class InnerReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser { - public override unsafe bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo) + public override bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo) { packInfo = null; var readOnlySpan = buffer.Span; var bufferLength = buffer.Length - Offset; - + if (bufferLength == 0) { // 没有剩余的数据需要处理、等待下一个包再处理。 Offset = 0; return false; } - + if (IsUnPackHead) { - fixed (byte* bufferPtr = readOnlySpan) - fixed (byte* messagePtr = MessageHead) - { - // 在当前buffer中拿到包头的数据 - var innerPacketHeadLength = Packet.InnerPacketHeadLength - MessageHeadOffset; - var copyLength = Math.Min(bufferLength, innerPacketHeadLength); - Buffer.MemoryCopy(bufferPtr + Offset, messagePtr + MessageHeadOffset, innerPacketHeadLength, copyLength); - Offset += copyLength; - MessageHeadOffset += copyLength; - // 检查是否有完整包头 - if (MessageHeadOffset == Packet.InnerPacketHeadLength) - { - // 通过指针直接读取协议编号、messagePacketLength protocolCode rpcId routeId - MessagePacketLength = *(int*)messagePtr; - // 检查消息体长度是否超出限制 - if (MessagePacketLength > Packet.PacketBodyMaxLength) - { - throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); - } + // 在当前buffer中拿到包头的数据 + var innerPacketHeadLength = Packet.InnerPacketHeadLength - MessageHeadOffset; + var copyLength = Math.Min(bufferLength, innerPacketHeadLength); - PackInfo = InnerPackInfo.Create(Network); - var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, Packet.InnerPacketHeadLength + MessagePacketLength); - PackInfo.RpcId = *(uint*)(messagePtr + Packet.InnerPacketRpcIdLocation); - PackInfo.ProtocolCode = *(uint*)(messagePtr + Packet.PacketLength); - PackInfo.RouteId = *(long*)(messagePtr + Packet.InnerPacketRouteRouteIdLocation); - memoryStream.Write(MessageHead); - IsUnPackHead = false; - bufferLength -= copyLength; - MessageHeadOffset = 0; - } - else + readOnlySpan.Slice(Offset, copyLength).CopyTo(MessageHead.AsSpan(MessageHeadOffset, copyLength)); + + Offset += copyLength; + MessageHeadOffset += copyLength; + // 检查是否有完整包头 + if (MessageHeadOffset == Packet.InnerPacketHeadLength) + { + // 通过现代API直接读取协议编号、messagePacketLength protocolCode rpcId routeId + ref var messageRef = ref MemoryMarshal.GetArrayDataReference(MessageHead); + MessagePacketLength = Unsafe.ReadUnaligned(ref messageRef); + // 检查消息体长度是否超出限制 + if (MessagePacketLength > ProgramDefine.MaxMessageSize) { - Offset = 0; - return false; + throw new ScanException( + $"The received information exceeds the maximum limit = {MessagePacketLength}"); } + + PackInfo = InnerPackInfo.Create(Network); + var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, + Packet.InnerPacketHeadLength + MessagePacketLength); + PackInfo.RpcId = + Unsafe.ReadUnaligned(ref Unsafe.Add(ref messageRef, Packet.InnerPacketRpcIdLocation)); + PackInfo.ProtocolCode = + Unsafe.ReadUnaligned(ref Unsafe.Add(ref messageRef, Packet.PacketLength)); + PackInfo.RouteId = + Unsafe.ReadUnaligned(ref Unsafe.Add(ref messageRef, + Packet.InnerPacketRouteRouteIdLocation)); + memoryStream.Write(MessageHead); + IsUnPackHead = false; + bufferLength -= copyLength; + MessageHeadOffset = 0; + } + else + { + Offset = 0; + return false; } } @@ -133,6 +138,7 @@ namespace Fantasy.PacketParser MessageBodyOffset = 0; return true; } + Offset = 0; return false; } @@ -143,19 +149,19 @@ namespace Fantasy.PacketParser } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream) + private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream) { - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; - *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; - } + var buffer = memoryStream.GetBuffer(); + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); + + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation), routeId); return memoryStream; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message) + private MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message) { var memoryStreamLength = 0; var messageType = message.GetType(); @@ -184,19 +190,19 @@ namespace Fantasy.PacketParser packetBodyCount = -1; } - if (packetBodyCount > Packet.PacketBodyMaxLength) + if (packetBodyCount > ProgramDefine.MaxMessageSize) { // 检查消息体长度是否超出限制 - throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes"); } - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(int*)bufferPtr = packetBodyCount; - *(uint*)(bufferPtr + Packet.PacketLength) = opCode; - *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; - *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; - } + var buffer = memoryStream.GetBuffer(); + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); + + Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation), rpcId); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRouteRouteIdLocation), routeId); return memoryStream; } @@ -204,7 +210,7 @@ namespace Fantasy.PacketParser #endif internal sealed class OuterReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser { - public override unsafe bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo) + public override bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo) { packInfo = null; var readOnlySpan = buffer.Span; @@ -216,46 +222,53 @@ namespace Fantasy.PacketParser Offset = 0; return false; } - + if (IsUnPackHead) { - fixed (byte* bufferPtr = readOnlySpan) - fixed (byte* messagePtr = MessageHead) - { - // 在当前buffer中拿到包头的数据 - var outerPacketHeadLength = Packet.OuterPacketHeadLength - MessageHeadOffset; - var copyLength = Math.Min(bufferLength, outerPacketHeadLength); - Buffer.MemoryCopy(bufferPtr + Offset, messagePtr + MessageHeadOffset, outerPacketHeadLength, copyLength); - Offset += copyLength; - MessageHeadOffset += copyLength; - // 检查是否有完整包头 - if (MessageHeadOffset == Packet.OuterPacketHeadLength) - { - // 通过指针直接读取协议编号、messagePacketLength protocolCode rpcId routeId - MessagePacketLength = *(int*)messagePtr; - // 检查消息体长度是否超出限制 - if (MessagePacketLength > Packet.PacketBodyMaxLength) - { - throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); - } + // 在当前buffer中拿到包头的数据 + var outerPacketHeadLength = Packet.OuterPacketHeadLength - MessageHeadOffset; + var copyLength = Math.Min(bufferLength, outerPacketHeadLength); - PackInfo = OuterPackInfo.Create(Network); - PackInfo.ProtocolCode = *(uint*)(messagePtr + Packet.PacketLength); - PackInfo.RpcId = *(uint*)(messagePtr + Packet.OuterPacketRpcIdLocation); - var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, Packet.OuterPacketHeadLength + MessagePacketLength); - memoryStream.Write(MessageHead); - IsUnPackHead = false; - bufferLength -= copyLength; - MessageHeadOffset = 0; - } - else + readOnlySpan.Slice(Offset, copyLength).CopyTo(MessageHead.AsSpan(MessageHeadOffset, copyLength)); + + Offset += copyLength; + MessageHeadOffset += copyLength; + // 检查是否有完整包头 + if (MessageHeadOffset == Packet.OuterPacketHeadLength) + { + // 通过现代API直接读取协议编号、messagePacketLength protocolCode rpcId routeId +#if FANTASY_UNITY + ref var messageRef = ref MemoryMarshal.GetReference(buffer.Span); +#else + ref var messageRef = ref MemoryMarshal.GetArrayDataReference(MessageHead); +#endif + MessagePacketLength = Unsafe.ReadUnaligned(ref messageRef); + // 检查消息体长度是否超出限制 + if (MessagePacketLength > ProgramDefine.MaxMessageSize) { - Offset = 0; - return false; + throw new ScanException( + $"The received information exceeds the maximum limit = {MessagePacketLength}"); } + + PackInfo = OuterPackInfo.Create(Network); + PackInfo.ProtocolCode = + Unsafe.ReadUnaligned(ref Unsafe.Add(ref messageRef, Packet.PacketLength)); + PackInfo.RpcId = + Unsafe.ReadUnaligned(ref Unsafe.Add(ref messageRef, Packet.OuterPacketRpcIdLocation)); + var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, + Packet.OuterPacketHeadLength + MessagePacketLength); + memoryStream.Write(MessageHead); + IsUnPackHead = false; + bufferLength -= copyLength; + MessageHeadOffset = 0; + } + else + { + Offset = 0; + return false; } } - + if (MessagePacketLength == -1) { // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 @@ -299,12 +312,15 @@ namespace Fantasy.PacketParser } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) + private MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) { - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; - } + var buffer = memoryStream.GetBuffer(); +#if FANTASY_UNITY + ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan()); +#else + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); +#endif + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId); return memoryStream; } @@ -338,18 +354,21 @@ namespace Fantasy.PacketParser packetBodyCount = -1; } - if (packetBodyCount > Packet.PacketBodyMaxLength) + if (packetBodyCount > ProgramDefine.MaxMessageSize) { // 检查消息体长度是否超出限制 - throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes"); } - fixed (byte* bufferPtr = memoryStream.GetBuffer()) - { - *(int*)bufferPtr = packetBodyCount; - *(uint*)(bufferPtr + Packet.PacketLength) = opCode; - *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; - } + var buffer = memoryStream.GetBuffer(); +#if FANTASY_UNITY + ref var bufferRef = ref MemoryMarshal.GetReference(buffer.AsSpan()); +#else + ref var bufferRef = ref MemoryMarshal.GetArrayDataReference(buffer); +#endif + Unsafe.WriteUnaligned(ref bufferRef, packetBodyCount); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.PacketLength), opCode); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref bufferRef, Packet.OuterPacketRpcIdLocation), rpcId); return memoryStream; } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs index f010858..fb28df6 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs @@ -77,10 +77,10 @@ namespace Fantasy.PacketParser packetBodyCount = -1; } - if (packetBodyCount > Packet.PacketBodyMaxLength) + if (packetBodyCount > ProgramDefine.MaxMessageSize) { // 检查消息体长度是否超出限制 - throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + throw new Exception($"Message content exceeds {ProgramDefine.MaxMessageSize} bytes"); } var buffer = memoryStream.GetBuffer(); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Packet.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Packet.cs index 7198af7..1067996 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Packet.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Packet.cs @@ -5,10 +5,6 @@ namespace Fantasy.PacketParser /// public struct Packet { - /// - /// 消息体最大长度 - /// - public const int PacketBodyMaxLength = ushort.MaxValue * 16; /// /// 消息体长度在消息头占用的长度 /// diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs index 88d7dd9..2c963ff 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs @@ -53,6 +53,7 @@ namespace Fantasy.Scheduler case OpCodeType.OuterPingRequest: { // 注意心跳目前只有外网才才会有、内网之间不需要心跳。 + session.LastReceiveTime = TimeHelper.Now; _pingResponse.Now = session.LastReceiveTime; diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs index 9ca4eba..b3806fa 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs @@ -43,9 +43,8 @@ namespace Fantasy.Network.HTTP if (e.ErrorCode == 5) { var sb = new StringBuilder(); - sb.AppendLine("CMD管理员中输入下面其中一个命令,具体根据您是HTTPS或HTTP决定:"); - sb.AppendLine($"HTTP请输入如下:netsh http add urlacl url=http://{bindIp}:{port}/ user=Everyone"); - sb.AppendLine($"HTTPS请输入如下:netsh http add urlacl url=https://{bindIp}:{port}/ user=Everyone"); + sb.AppendLine("CMD管理员中输入下面命令:"); + sb.AppendLine($"netsh http add urlacl url=http://{bindIp}:{port}/ user=Everyone"); throw new Exception(sb.ToString(), e); } @@ -60,10 +59,7 @@ namespace Fantasy.Network.HTTP private void StartAsync(string bindIp, int port) { var builder = WebApplication.CreateBuilder(); - // 配置日志级别为 Warning 或更高 builder.Logging.ClearProviders(); - builder.Logging.AddConsole(); - builder.Logging.SetMinimumLevel(LogLevel.Warning); // 将Scene注册到 DI 容器中,传递给控制器 builder.Services.AddSingleton(Scene); // 注册Scene同步过滤器 @@ -75,38 +71,15 @@ namespace Fantasy.Network.HTTP { addControllers.AddApplicationPart(assembly); } - var listenUrl = ""; var app = builder.Build(); - // 检测当前路径下是否有证书文件 - var certificatePath = Path.Combine(AppContext.BaseDirectory, $"certificate{bindIp}{port}"); - if (Directory.Exists(certificatePath)) - { - // 加载包含证书链的 PEM 文件 - var pemCertChain = File.ReadAllText(Path.Combine(certificatePath, "chain.pem")); - var pemPrivateKey = File.ReadAllText(Path.Combine(certificatePath, "private-key.pem")); - // 配置 HTTPS 监听并使用证书 - builder.WebHost.ConfigureKestrel(kestrelServerOptions => - { - kestrelServerOptions.ConfigureHttpsDefaults(https => - { - https.ServerCertificate = X509Certificate2.CreateFromPem(pemCertChain, pemPrivateKey); - }); - }); - listenUrl = $"https://{bindIp}:{port}/"; - app.Urls.Add(listenUrl); - app.UseHttpsRedirection(); - } - else - { - // 不安全的HTTP地址 - listenUrl = $"http://{bindIp}:{port}/"; - app.Urls.Add(listenUrl); - } + var listenUrl = $"http://{bindIp}:{port}/";; + app.Urls.Add(listenUrl); // 启用开发者工具 if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } + // 路由注册 app.MapControllers(); // 开启监听 diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs index aa1947d..47316cb 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs @@ -17,12 +17,12 @@ namespace KCP /// /// KCP output destination /// KCP output size (excluding reserved) - public delegate void KcpCallback(byte[] buffer, int length); + internal delegate void KcpCallback(byte[] buffer, int length); /// /// Kcp /// - public sealed unsafe class Kcp : IDisposable + internal sealed unsafe class Kcp : IDisposable { /// /// Kcp diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/c/kcp.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/c/kcp.cs index a202cfd..c5c36f0 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/c/kcp.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/c/kcp.cs @@ -16,7 +16,7 @@ namespace kcp /// /// https://github.com/skywind3000/kcp /// - public static unsafe partial class KCP + internal static unsafe partial class KCP { //===================================================================== // KCP BASIC @@ -165,50 +165,50 @@ namespace kcp return ((int)(later - earlier)); } - //--------------------------------------------------------------------- - // manage segment - //--------------------------------------------------------------------- - public static delegate* managed ikcp_malloc_hook = null; - public static delegate* managed ikcp_free_hook = null; + // //--------------------------------------------------------------------- + // // manage segment + // //--------------------------------------------------------------------- + // public static delegate* managed ikcp_malloc_hook = null; + // public static delegate* managed ikcp_free_hook = null; - // internal malloc - public static void* ikcp_malloc(nuint size) - { - if (ikcp_malloc_hook != null) - return ikcp_malloc_hook(size); - return malloc(size); - } + // // internal malloc + // public static void* ikcp_malloc(nuint size) + // { + // if (ikcp_malloc_hook != null) + // return ikcp_malloc_hook(size); + // return malloc(size); + // } - // internal free - public static void ikcp_free(void* ptr) - { - if (ikcp_free_hook != null) - { - ikcp_free_hook(ptr); - } - else - { - free(ptr); - } - } + // // internal free + // public static void ikcp_free(void* ptr) + // { + // if (ikcp_free_hook != null) + // { + // ikcp_free_hook(ptr); + // } + // else + // { + // free(ptr); + // } + // } - // redefine allocator - public static void ikcp_allocator(delegate* managed new_malloc, delegate* managed new_free) - { - ikcp_malloc_hook = new_malloc; - ikcp_free_hook = new_free; - } + // // redefine allocator + // public static void ikcp_allocator(delegate* managed new_malloc, delegate* managed new_free) + // { + // ikcp_malloc_hook = new_malloc; + // ikcp_free_hook = new_free; + // } // allocate a new kcp segment public static IKCPSEG* ikcp_segment_new(IKCPCB* kcp, int size) { - return (IKCPSEG*)ikcp_malloc((nuint)(sizeof(IKCPSEG) + size)); + return (IKCPSEG*)malloc((nuint)(sizeof(IKCPSEG) + size)); } // delete a segment public static void ikcp_segment_delete(IKCPCB* kcp, IKCPSEG* seg) { - ikcp_free(seg); + free(seg); } // output segment @@ -226,7 +226,7 @@ namespace kcp //--------------------------------------------------------------------- public static IKCPCB* ikcp_create(uint conv, int reserved, ref byte[] buffer) { - IKCPCB* kcp = (IKCPCB*)ikcp_malloc((nuint)sizeof(IKCPCB)); + IKCPCB* kcp = (IKCPCB*)malloc((nuint)sizeof(IKCPCB)); if (kcp == null) return null; kcp->conv = conv; kcp->snd_una = 0; @@ -318,7 +318,7 @@ namespace kcp if (kcp->acklist != null) { - ikcp_free(kcp->acklist); + free(kcp->acklist); } kcp->nrcv_buf = 0; @@ -327,7 +327,7 @@ namespace kcp kcp->nsnd_que = 0; kcp->ackcount = 0; kcp->acklist = null; - ikcp_free(kcp); + free(kcp); } } @@ -669,7 +669,7 @@ namespace kcp uint newblock; newblock = newsize <= 8 ? 8 : _iceilpow2_(newsize); - acklist = (uint*)ikcp_malloc((nuint)(newblock * sizeof(uint) * 2)); + acklist = (uint*)malloc((nuint)(newblock * sizeof(uint) * 2)); if (acklist == null) { @@ -686,7 +686,7 @@ namespace kcp acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1]; } - ikcp_free(kcp->acklist); + free(kcp->acklist); } kcp->acklist = acklist; diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/define/system.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/define/system.cs index 053b8c5..fec2d37 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/define/system.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/define/system.cs @@ -9,9 +9,9 @@ using System.Runtime.InteropServices; namespace kcp { - public static unsafe partial class KCP + internal static unsafe partial class KCP { - public static void* malloc(nuint size) + private static void* malloc(nuint size) { #if NET6_0_OR_GREATER return NativeMemory.Alloc((nuint)size); @@ -20,7 +20,7 @@ namespace kcp #endif } - public static void free(void* memory) + private static void free(void* memory) { #if NET6_0_OR_GREATER NativeMemory.Free(memory); @@ -29,13 +29,13 @@ namespace kcp #endif } - public static void memcpy(void* dst, void* src, nuint size) => Unsafe.CopyBlockUnaligned(dst, src, (uint)size); + private static void memcpy(void* dst, void* src, nuint size) => Unsafe.CopyBlockUnaligned(dst, src, (uint)size); - public static void memset(void* dst, byte val, nuint size) => Unsafe.InitBlockUnaligned(dst, val, (uint)size); + private static void memset(void* dst, byte val, nuint size) => Unsafe.InitBlockUnaligned(dst, val, (uint)size); [Conditional("DEBUG")] - public static void assert(bool condition) => Debug.Assert(condition); + private static void assert(bool condition) => Debug.Assert(condition); - public static void abort() => Environment.Exit(-1); + private static void abort() => Environment.Exit(-1); } } \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/include/kcp.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/include/kcp.cs index 98a83d9..838cc09 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/include/kcp.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/include/kcp.cs @@ -8,13 +8,13 @@ using System.Runtime.InteropServices; namespace kcp { [StructLayout(LayoutKind.Sequential)] - public unsafe struct IQUEUEHEAD + internal unsafe struct IQUEUEHEAD { public IQUEUEHEAD* next; public IQUEUEHEAD* prev; } - public static unsafe partial class KCP + internal static unsafe partial class KCP { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void iqueue_init(IQUEUEHEAD* head) @@ -65,7 +65,7 @@ namespace kcp } [StructLayout(LayoutKind.Sequential)] - public unsafe struct IKCPSEG + internal unsafe struct IKCPSEG { public IQUEUEHEAD node; public uint conv; @@ -84,7 +84,7 @@ namespace kcp } [StructLayout(LayoutKind.Sequential)] - public unsafe struct IKCPCB + internal unsafe struct IKCPCB { public uint conv, mtu, mss, state; public uint snd_una, snd_nxt, rcv_nxt; @@ -109,7 +109,7 @@ namespace kcp public int nocwnd, stream; } - public static partial class KCP + internal static partial class KCP { public const uint IKCP_LOG_OUTPUT = 1; public const uint IKCP_LOG_INPUT = 2; diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs index a400c34..f0f8868 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs @@ -27,14 +27,14 @@ using KCP; #pragma warning disable CS8602 // Dereference of a possibly null reference. namespace Fantasy.Network.KCP { - public sealed class KCPClientNetworkUpdateSystem : UpdateSystem + internal sealed class KCPClientNetworkUpdateSystem : UpdateSystem { protected override void Update(KCPClientNetwork self) { self.CheckUpdate(); } } - public sealed class KCPClientNetwork : AClientNetwork + internal sealed class KCPClientNetwork : AClientNetwork { private Kcp _kcp; private Socket _socket; @@ -50,7 +50,7 @@ namespace Fantasy.Network.KCP private BufferPacketParser _packetParser; private readonly Pipe _pipe = new Pipe(); private readonly byte[] _sendBuff = new byte[5]; - private readonly byte[] _receiveBuffer = new byte[Packet.PacketBodyMaxLength + 20]; + private readonly byte[] _receiveBuffer = new byte[ProgramDefine.MaxMessageSize + 20]; private readonly List _updateTimeOutTime = new List(); private readonly SortedSet _updateTimer = new SortedSet(); private readonly SocketAsyncEventArgs _connectEventArgs = new SocketAsyncEventArgs(); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs index 2a070a9..d7ca536 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs @@ -62,7 +62,7 @@ namespace Fantasy.Network.KCP } } - public static class KCPFactory + internal static class KCPFactory { public const int FANTASY_KCP_RESERVED_HEAD = 5; diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs index 28ddace..5ad606e 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs @@ -1,7 +1,7 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member namespace Fantasy.Network.KCP -#pragma warning disable CS1591 { - public enum KcpHeader : byte + internal enum KcpHeader : byte { None = 0x00, RequestConnection = 0x01, diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkByPipe.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkByPipe.cs index 54b550d..407e8c9 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkByPipe.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkByPipe.cs @@ -23,7 +23,7 @@ using Fantasy.Network.Interface; namespace Fantasy.Network.KCP { - public sealed class KCPServerNetworkUpdateSystem : UpdateSystem + internal sealed class KCPServerNetworkUpdateSystem : UpdateSystem { protected override void Update(KCPServerNetwork self) { @@ -31,7 +31,7 @@ namespace Fantasy.Network.KCP } } - public struct PendingConnection + internal struct PendingConnection { public readonly uint ChannelId; public readonly uint TimeOutId; @@ -388,7 +388,7 @@ namespace Fantasy.Network.KCP { continue; } - + if (channel.IsDisposed) { _connectionChannel.Remove(channelId); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs index 19db7a7..4216fa7 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs @@ -17,13 +17,13 @@ namespace Fantasy.Network.KCP /// /// KCP 服务器网络通道,用于处理服务器与客户端之间的数据通信。 /// - public class KCPServerNetworkChannel : ANetworkServerChannel + internal class KCPServerNetworkChannel : ANetworkServerChannel { private bool _isInnerDispose; private readonly int _maxSndWnd; private KCPServerNetwork _kcpServerNetwork; private readonly BufferPacketParser _packetParser; - private readonly byte[] _receiveBuffer = new byte[Packet.PacketBodyMaxLength + 20]; + private readonly byte[] _receiveBuffer = new byte[ProgramDefine.MaxMessageSize + 20]; public Kcp Kcp { get; private set; } public uint ChannelId { get; private set; } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs index c7b6ecc..995c8aa 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs @@ -40,7 +40,7 @@ namespace Fantasy.Network case NetworkProtocolType.WebSocket: { var network = Entity.Create(scene, false, true); - network.Initialize(networkTarget, bindIp, port); + network.Initialize(networkTarget, port); return network; } case NetworkProtocolType.HTTP: diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs index 45e69e8..ef0b78f 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs @@ -46,6 +46,11 @@ namespace Fantasy.Network.WebSocket { _isInnerDispose = true; + if (_clientWebSocket.State == WebSocketState.Open || _clientWebSocket.State == WebSocketState.CloseReceived) + { + _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client Closing", CancellationToken.None).GetAwaiter().GetResult(); + } + if (!_cancellationTokenSource.IsCancellationRequested) { try @@ -59,11 +64,13 @@ namespace Fantasy.Network.WebSocket } ClearConnectTimeout(); - WebSocketClientDisposeAsync().Coroutine(); _onConnectDisconnect?.Invoke(); _packetParser.Dispose(); _packetParser = null; _isSending = false; + + _clientWebSocket.Dispose(); + _clientWebSocket = null; } catch (Exception e) { @@ -75,18 +82,6 @@ namespace Fantasy.Network.WebSocket } } - private async FTask WebSocketClientDisposeAsync() - { - if (_clientWebSocket == null) - { - return; - } - - await _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); - _clientWebSocket.Dispose(); - _clientWebSocket = null; - } - public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) { if (IsInit) @@ -150,10 +145,16 @@ namespace Fantasy.Network.WebSocket var memory = _pipe.Writer.GetMemory(8192); // 这里接收的数据不一定是一个完整的包。如果大于8192就会分成多个包。 var receiveResult = await _clientWebSocket.ReceiveAsync(memory, _cancellationTokenSource.Token); - + // 服务器发送了关闭帧,客户端需要响应关闭帧 if (receiveResult.MessageType == WebSocketMessageType.Close) { - break; + if (_clientWebSocket.State == WebSocketState.CloseReceived) + { + await _clientWebSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Response Closure", + CancellationToken.None); + } + Dispose(); + return; } var count = receiveResult.Count; diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs index 09feb2b..779eff7 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs @@ -17,7 +17,7 @@ public class WebSocketServerNetwork : ANetwork private HttpListener _httpListener; private readonly Dictionary _connectionChannel = new Dictionary(); - public void Initialize(NetworkTarget networkTarget, string bindIp, int port) + public void Initialize(NetworkTarget networkTarget, int port) { base.Initialize(NetworkType.Server, NetworkProtocolType.WebSocket, networkTarget); @@ -25,13 +25,15 @@ public class WebSocketServerNetwork : ANetwork { _random = new Random(); _httpListener = new HttpListener(); - StartAcceptAsync(bindIp, port).Coroutine(); + StartAcceptAsync(port).Coroutine(); } catch (HttpListenerException e) { if (e.ErrorCode == 5) { - throw new Exception($"CMD管理员中输入: netsh http add urlacl url=http://*:8080/ user=Everyone", e); + throw new Exception($"如果看下如下错误请尝试下面的办法:" + + $"1.用管理员运行CMD 输入命令: netsh http add urlacl url=http://+:8080/ user=Everyone。" + + $"2.用管理员身份运行编辑器或者程序。", e); } Log.Error(e); @@ -64,11 +66,42 @@ public class WebSocketServerNetwork : ANetwork base.Dispose(); } - private async FTask StartAcceptAsync(string bindIp, int port) + private static bool IsValidWebSocketRequest(HttpListenerRequest request) { - var listenUrl = ""; - var certificatePath = Path.Combine(AppContext.BaseDirectory, $"certificate{bindIp}{port}"); - listenUrl = Directory.Exists(certificatePath) ? $"https://{bindIp}:{port}/" : $"http://{bindIp}:{port}/"; + // 检查必需的WebSocket握手头部 + var connectionHeader = request.Headers["Connection"]; + var upgradeHeader = request.Headers["Upgrade"]; + + if (string.IsNullOrEmpty(connectionHeader) || string.IsNullOrEmpty(upgradeHeader)) + { + return false; + } + + // Connection头部应该包含"Upgrade" (不区分大小写) + if (!connectionHeader.ToLower().Contains("upgrade")) + { + return false; + } + + // Upgrade头部应该是"websocket" (不区分大小写) + if (!upgradeHeader.ToLower().Contains("websocket")) + { + return false; + } + + // 检查WebSocket版本 (可选但推荐) + var versionHeader = request.Headers["Sec-WebSocket-Version"]; + if (!string.IsNullOrEmpty(versionHeader) && versionHeader != "13") + { + return false; + } + + return true; + } + + private async FTask StartAcceptAsync(int port) + { + var listenUrl = $"http://+:{port}/"; _httpListener.Prefixes.Add(listenUrl); _httpListener.Start(); Log.Info($"SceneConfigId = {Scene.SceneConfigId} WebSocketServer Listen {listenUrl}"); @@ -77,15 +110,23 @@ public class WebSocketServerNetwork : ANetwork try { var httpListenerContext = await _httpListener.GetContextAsync(); + // 验证WebSocket握手请求头部 + if (!IsValidWebSocketRequest(httpListenerContext.Request)) + { + httpListenerContext.Response.StatusCode = 400; + httpListenerContext.Response.StatusDescription = "Bad Request - Invalid WebSocket headers"; + httpListenerContext.Response.Close(); + continue; + } var webSocketContext = await httpListenerContext.AcceptWebSocketAsync(null); var channelId = 0xC0000000 | (uint) _random.Next(); - while (_connectionChannel.ContainsKey(channelId)) { channelId = 0xC0000000 | (uint) _random.Next(); } - - _connectionChannel.Add(channelId, new WebSocketServerNetworkChannel(this, channelId, webSocketContext, httpListenerContext.Request.RemoteEndPoint)); + + var webSocketServerNetworkChannel = new WebSocketServerNetworkChannel(this, channelId, webSocketContext, httpListenerContext.Request.RemoteEndPoint); + _connectionChannel.Add(channelId, webSocketServerNetworkChannel); } catch (Exception e) { diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs index 3b8ee90..040745f 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs @@ -42,6 +42,20 @@ public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel } _isInnerDispose = true; + + if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.CloseReceived) + { + try + { + _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure", + CancellationToken.None).GetAwaiter().GetResult(); + } + catch (Exception) + { + // 关闭过程中的异常可以忽略 + } + } + if (!_cancellationTokenSource.IsCancellationRequested) { try @@ -53,13 +67,9 @@ public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel // 通常情况下,此处的异常可以忽略 } } + _sendBuffers.Clear(); _network.RemoveChannel(Id); - if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.CloseReceived) - { - _webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure", - _cancellationTokenSource.Token).GetAwaiter().GetResult(); - } _webSocket.Dispose(); _isSending = false; base.Dispose(); @@ -76,11 +86,16 @@ public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel var memory = _pipe.Writer.GetMemory(8192); // 这里接收的数据不一定是一个完整的包。如果大于8192就会分成多个包。 var receiveResult = await _webSocket.ReceiveAsync(memory, _cancellationTokenSource.Token); - + // 客户端发送了关闭帧,服务器需要响应关闭帧 if (receiveResult.MessageType == WebSocketMessageType.Close) { + if (_webSocket.State == WebSocketState.CloseReceived) + { + await _webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Response Closure", + CancellationToken.None); + } Dispose(); - break; + return; } var count = receiveResult.Count; @@ -112,6 +127,9 @@ public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel } await _pipe.Writer.CompleteAsync(); + + // 接收循环结束,自动释放连接 + Dispose(); } private async FTask PipeWriterFlushAsync(int count) diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Roaming/Component/SessionRoamingComponent.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Roaming/Component/SessionRoamingComponent.cs index c5ce55a..6834834 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Roaming/Component/SessionRoamingComponent.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Roaming/Component/SessionRoamingComponent.cs @@ -184,7 +184,118 @@ public sealed class SessionRoamingComponent : Entity #endregion - #region Message + #region OuterMessage + + /// + /// 发送一个消息给漫游终 + /// + /// + public void Send(IRoamingMessage message) + { + Call(message.RouteType, message).Coroutine(); + } + + /// + /// 发送一个消息给漫游终端 + /// + /// + /// + public void Send(int roamingType, IRouteMessage message) + { + Call(roamingType, message).Coroutine(); + } + + /// + /// 发送一个RPC消息给漫游终端 + /// + /// + /// + public async FTask Call(IRoamingMessage message) + { + return await Call(message.RouteType, message); + } + + /// + /// 发送一个RPC消息给漫游终端 + /// + /// + /// + /// + public async FTask Call(int roamingType, IRouteMessage message) + { + if (!_roaming.TryGetValue(roamingType, out var roaming)) + { + return MessageDispatcherComponent.CreateResponse(message.GetType(), InnerErrorCode.ErrNotFoundRoaming); + } + + var failCount = 0; + var runtimeId = RuntimeId; + var routeId = roaming.TerminusId; + var requestType = message.GetType(); + + IResponse iRouteResponse = null; + + using (await RoamingMessageLock.Wait(roaming.RoamingType, "RoamingComponent Call MemoryStream")) + { + while (!IsDisposed) + { + if (routeId == 0) + { + routeId = await roaming.GetTerminusId(); + } + + if (routeId == 0) + { + return MessageDispatcherComponent.CreateResponse(requestType, InnerErrorCode.ErrNotFoundRoaming); + } + + iRouteResponse = await NetworkMessagingComponent.CallInnerRoute(routeId, message); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRoamingTimeout; + } + + switch (iRouteResponse.ErrorCode) + { + case InnerErrorCode.ErrRouteTimeout: + case InnerErrorCode.ErrRoamingTimeout: + { + return iRouteResponse; + } + case InnerErrorCode.ErrNotFoundRoute: + case InnerErrorCode.ErrNotFoundRoaming: + { + if (++failCount > 20) + { + Log.Error($"RoamingComponent.Call failCount > 20 route send message fail, LinkRoamingId: {routeId}"); + return iRouteResponse; + } + + await TimerComponent.Net.WaitAsync(100); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrNotFoundRoaming; + } + + routeId = 0; + continue; + } + default: + { + return iRouteResponse; // 对于其他情况,直接返回响应,无需额外处理 + } + } + } + } + + return iRouteResponse; + } + + #endregion + + #region InnerMessage internal async FTask Send(int roamingType, Type requestType, APackInfo packInfo) { diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs index 1edc1cf..595fa75 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs @@ -1,12 +1,13 @@ +#if FANTASY_NET using Fantasy.Entitas; using Fantasy.Entitas.Interface; using Fantasy.Helper; +using Fantasy.Platform.Net; using Fantasy.Timer; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. #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 -#if FANTASY_NET namespace Fantasy.Network; public class SessionIdleCheckerComponentAwakeSystem : AwakeSystem @@ -57,7 +58,7 @@ public class SessionIdleCheckerComponent : Entity /// /// 以毫秒为单位的检查间隔。 /// 以毫秒为单位的空闲超时时间。 - public void Start(int interval, int timeOut) + internal void Start(int interval, int timeOut) { _timeOut = timeOut; _session = (Session)Parent; @@ -66,10 +67,21 @@ public class SessionIdleCheckerComponent : Entity _timerId = TimerComponent.Net.RepeatedTimer(interval, Check); } + /// + /// 重新开始心跳检查 + /// + /// 以毫秒为单位的检查间隔。 + /// 以毫秒为单位的空闲超时时间。 + public void Restart(int interval, int timeOut) + { + Stop(); + Start(interval, timeOut); + } + /// /// 停止空闲检查功能。 /// - public void Stop() + private void Stop() { if (_timerId == 0) { @@ -96,8 +108,9 @@ public class SessionIdleCheckerComponent : Entity { return; } - +#if FANTASY_DEBUG Log.Warning($"session timeout id:{Id} timeNow:{timeNow} _session.LastReceiveTime:{_session.LastReceiveTime} _timeOut:{_timeOut}"); +#endif _session.Dispose(); } } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs index 83c7cbf..fa981ce 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs @@ -1,6 +1,7 @@ // ReSharper disable MemberCanBePrivate.Global using System; +using System.Collections.Generic; using Fantasy.Async; using Fantasy.Entitas; using Fantasy.Entitas.Interface; @@ -32,9 +33,20 @@ namespace Fantasy.Network public long TimeOutTimerId; public TimerComponent TimerComponent; public EntityReference Session; - private readonly PingRequest _pingRequest = new PingRequest(); + private readonly PingRequest _pingRequest = new PingRequest(); - public int Ping { get; private set; } + // Ping滑动窗口及其累加和 + private int _pingSum; + private int _maxPingSamples; + private readonly Queue _pingSamples = new Queue(); + /// + /// 当前Ping延迟(毫秒,滑动均值) + /// + public int PingMilliseconds { get; private set; } + /// + /// 当前Ping延迟(秒,浮点数,通常用于调试) + /// + public float PingSeconds => PingMilliseconds / 1000f; public override void Dispose() { @@ -44,7 +56,6 @@ namespace Fantasy.Network } Stop(); - Ping = 0; Session = null; TimeOut = 0; LastTime = 0; @@ -58,13 +69,15 @@ namespace Fantasy.Network /// 以毫秒为单位的心跳请求发送间隔。 /// 设置与服务器的通信超时时间,如果超过这个时间限制,将自动断开会话(Session)。 /// 用于检测与服务器连接超时频率。 - public void Start(int interval, int timeOut = 5000, int timeOutInterval = 3000) + /// Ping包的采样数量 + public void Start(int interval, int timeOut = 5000, int timeOutInterval = 3000, int maxPingSamples = 8) { TimeOut = timeOut + interval; Session = (Session)Parent; SelfRunTimeId = RuntimeId; LastTime = TimeHelper.Now; - + _maxPingSamples = maxPingSamples; + if (TimerComponent == null) { Log.Error("请在Unity的菜单执行Fantasy->Generate link.xml再重新打包"); @@ -109,6 +122,10 @@ namespace Fantasy.Network { TimerComponent?.Unity.Remove(ref TimeOutTimerId); } + + _pingSum = 0; + PingMilliseconds = 0; + _pingSamples.Clear(); } /// @@ -143,8 +160,23 @@ namespace Fantasy.Network var responseTime = TimeHelper.Now; LastTime = responseTime; - Ping = (int)(responseTime - requestTime) / 2; - TimeHelper.TimeDiff = pingResponse.Now + Ping - responseTime; + + // 计算Ping(毫秒) + var rtt = (int)(responseTime - requestTime); + var ping = rtt / 2; + + // 平滑滑动均值 + _pingSamples.Enqueue(ping); + _pingSum += ping; + if (_pingSamples.Count > _maxPingSamples) + { + _pingSum -= _pingSamples.Dequeue(); + } + + PingMilliseconds = Math.Max(0, _pingSamples.Count > 0 ? _pingSum / _pingSamples.Count : 0); + + // 校正服务器时间(可选) + TimeHelper.TimeDiff = pingResponse.Now + ping - responseTime; } catch (Exception) { diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Session.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Session.cs index dd2b4ea..02789e7 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Session.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Session.cs @@ -1,5 +1,4 @@ // ReSharper disable RedundantUsingDirective - using System; using System.Collections.Generic; using System.IO; @@ -18,7 +17,6 @@ using Fantasy.Serialize; using Fantasy.Network.Route; using Fantasy.Platform.Net; using Fantasy.Network.Roaming; - #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #endif // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract @@ -38,18 +36,15 @@ namespace Fantasy.Network { private uint _rpcId; internal long LastReceiveTime; - /// /// 关联的网络连接通道 /// internal INetworkChannel Channel { get; private set; } - /// /// 当前Session的终结点信息 /// public IPEndPoint RemoteEndPoint { get; private set; } - - private ANetworkMessageScheduler NetworkMessageScheduler { get; set; } + private ANetworkMessageScheduler NetworkMessageScheduler { get; set;} internal readonly Dictionary> RequestCallback = new(); /// /// Session的Dispose委托 @@ -59,8 +54,7 @@ namespace Fantasy.Network internal RouteComponent RouteComponent; internal SessionRoamingComponent SessionRoamingComponent; internal AddressableRouteComponent AddressableRouteComponent; - internal static Session Create(ANetworkMessageScheduler networkMessageScheduler, ANetworkServerChannel channel, - NetworkTarget networkTarget) + internal static Session Create(ANetworkMessageScheduler networkMessageScheduler, ANetworkServerChannel channel, NetworkTarget networkTarget) { var session = Entity.Create(channel.Scene, false, true); session.Channel = channel; @@ -71,11 +65,10 @@ namespace Fantasy.Network // 在外部网络目标下,添加会话空闲检查组件 if (networkTarget == NetworkTarget.Outer) { - var interval = ProcessDefine.SessionIdleCheckerInterval; - var timeOut = ProcessDefine.SessionIdleCheckerTimeout; + var interval = ProgramDefine.SessionIdleCheckerInterval; + var timeOut = ProgramDefine.SessionIdleCheckerTimeout; session.AddComponent().Start(interval, timeOut); } - return session; } #endif @@ -159,7 +152,7 @@ namespace Fantasy.Network { return; } - + _rpcId = 0; LastReceiveTime = 0; Channel = null; @@ -177,11 +170,11 @@ namespace Fantasy.Network { requestCallback.SetException(new Exception($"session is dispose: {Id}")); } - + RequestCallback.Clear(); OnDispose?.Invoke(); } - + /// /// 发送一个消息 /// @@ -194,10 +187,10 @@ namespace Fantasy.Network { return; } - + Channel.Send(rpcId, routeId, null, message); } - + /// /// 发送一个消息 /// @@ -213,7 +206,7 @@ namespace Fantasy.Network Channel.Send(rpcId, routeId, null, routeMessage); } - + /// /// 发送一个RPC消息 /// @@ -226,14 +219,14 @@ namespace Fantasy.Network { return null; } - + var requestCallback = FTask.Create(); - var rpcId = ++_rpcId; + var rpcId = ++_rpcId; RequestCallback.Add(rpcId, requestCallback); Send(request, rpcId, routeId); return requestCallback; } - + /// /// 发送一个RPC消息 /// @@ -246,9 +239,9 @@ namespace Fantasy.Network { return null; } - + var requestCallback = FTask.Create(); - var rpcId = ++_rpcId; + var rpcId = ++_rpcId; RequestCallback.Add(rpcId, requestCallback); Send(request, rpcId, routeId); return requestCallback; @@ -275,5 +268,31 @@ namespace Fantasy.Network Log.Error(e); } } +#if FANTASY_NET + /// + /// 重新开始心跳检查 + /// + /// + /// + public void RestartIdleChecker(int interval, int timeOut) + { + var sessionIdleCheckerComponent = GetComponent(); + if (sessionIdleCheckerComponent == null) + { + Log.Error("SessionIdleCheckerComponent is null"); + return; + } + + sessionIdleCheckerComponent.Restart(interval, timeOut); + } + + /// + /// 重新开始心跳检查(使用框架配置的参数) + /// + public void RestartIdleChecker() + { + RestartIdleChecker(ProgramDefine.SessionIdleCheckerInterval, ProgramDefine.SessionIdleCheckerTimeout); + } +#endif } -} \ No newline at end of file +} diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/Entry.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/Entry.cs index 2cddb8b..c0b3aa6 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/Entry.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/Entry.cs @@ -33,7 +33,7 @@ namespace Fantasy.Platform.Console Log.Error("Fantasy has already been initialized and does not need to be initialized again!"); return; } - + Log.Info($"Fantasy Version:{Define.VERSION}"); // 初始化程序集管理系统 await AssemblySystem.InnerInitialize(assemblies); // 初始化序列化 diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigLoader.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigLoader.cs new file mode 100644 index 0000000..d359cf5 --- /dev/null +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigLoader.cs @@ -0,0 +1,537 @@ +#if FANTASY_NET +using System.Text; +using System.Xml; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.IdFactory; +using Fantasy.Network; +using Fantasy.Platform.Net; + +namespace Fantasy; + +/// +/// Fantasy框架XML配置文件加载器 +/// +public static class ConfigLoader +{ + /// + /// 从XML配置文件初始化所有配置 + /// + /// + /// + public static async FTask InitializeFromXml(string configPath) + { + var configText = await FileHelper.GetTextByRelativePath(configPath); + var doc = new XmlDocument(); + doc.LoadXml(configText); + + var root = doc.DocumentElement; + if (root?.LocalName != "fantasy") + { + throw new InvalidOperationException("Invalid Fantasy config file format"); + } + + // 创建命名空间管理器 + + var nsManager = new XmlNamespaceManager(doc.NameTable); + nsManager.AddNamespace("f", "http://fantasy.net/config"); + + // 加载运行时配置 + + LoadRuntimeConfig(root, nsManager); + + var configTableNode = root.SelectSingleNode("f:configTable", nsManager); + if (configTableNode != null) + { + var configTablePath = configTableNode.Attributes?["path"]?.Value; + if (string.IsNullOrEmpty(configTablePath)) + { + throw new InvalidOperationException("The configTable in the Fantasy configuration file lacks path configuration"); + } + await LoadJsonConfig(configTablePath); + return; + } + + var serverNode = root.SelectSingleNode("f:server", nsManager); + if (serverNode == null) + { + throw new InvalidOperationException("Missing server configuration in Fantasy config file"); + } + + // 加载框架需要的四个配置文件 + LoadMachineConfig(serverNode, nsManager); + LoadProcessConfig(serverNode, nsManager); + LoadWorldConfig(serverNode, nsManager); + LoadSceneConfig(serverNode, nsManager); + // 验证所有配置的完整性和正确性 + CheckConfig(); + } + + #region LoadJsonConfig + + private static async FTask LoadJsonConfig(string configTablePath) + { + var machineConfigFullPath = FileHelper.GetFullPath($"{configTablePath}/MachineConfigData.Json"); + + if (!File.Exists(machineConfigFullPath)) + { + throw new InvalidOperationException($"MachineConfigData.Json not found in the {machineConfigFullPath} directory"); + } + + var processConfigFullPath = FileHelper.GetFullPath($"{configTablePath}/ProcessConfigData.Json"); + + if (!File.Exists(processConfigFullPath)) + { + throw new InvalidOperationException($"ProcessConfigData.Json not found in the {processConfigFullPath} directory"); + } + + var worldConfigFullPath = FileHelper.GetFullPath($"{configTablePath}/WorldConfigData.Json"); + + if (!File.Exists(worldConfigFullPath)) + { + throw new InvalidOperationException($"WorldConfigData.Json not found in the {worldConfigFullPath} directory"); + } + + var sceneConfigFullPath = FileHelper.GetFullPath($"{configTablePath}/SceneConfigData.Json"); + + if (!File.Exists(sceneConfigFullPath)) + { + throw new InvalidOperationException($"SceneConfigData.Json not found in the {sceneConfigFullPath} directory"); + } + + MachineConfigData.Initialize(await File.ReadAllTextAsync(machineConfigFullPath, Encoding.UTF8)); + ProcessConfigData.Initialize(await File.ReadAllTextAsync(processConfigFullPath, Encoding.UTF8)); + WorldConfigData.Initialize(await File.ReadAllTextAsync(worldConfigFullPath, Encoding.UTF8)); + SceneConfigData.Initialize(await File.ReadAllTextAsync(sceneConfigFullPath, Encoding.UTF8)); + + // 验证所有配置的完整性和正确性 + CheckConfig(); + } + + #endregion + + #region LoadXMLConfig + + private static void LoadMachineConfig(XmlNode serverNode, XmlNamespaceManager nsManager) + { + var machinesNode = serverNode.SelectSingleNode("f:machines", nsManager); + if (machinesNode == null) + { + throw new InvalidOperationException("Missing machines configuration - at least one machine must be configured"); + } + + var machineNodes = machinesNode.SelectNodes("f:machine", nsManager); + if (machineNodes == null || machineNodes.Count == 0) + { + throw new InvalidOperationException("No machine configurations found - at least one machine must be configured"); + } + + var machineList = new List(); + foreach (XmlNode machineNode in machineNodes) + { + var machine = new MachineConfig + { + Id = uint.Parse(GetRequiredAttribute(machineNode, "id")), + OuterIP = GetRequiredAttribute(machineNode, "outerIP"), + OuterBindIP = GetRequiredAttribute(machineNode, "outerBindIP"), + InnerBindIP = GetRequiredAttribute(machineNode, "innerBindIP") + }; + machineList.Add(machine); + } + + MachineConfigData.Initialize(machineList); + } + + private static void LoadProcessConfig(XmlNode serverNode, XmlNamespaceManager nsManager) + { + var processesNode = serverNode.SelectSingleNode("f:processes", nsManager); + if (processesNode == null) + { + throw new InvalidOperationException("Missing processes configuration - at least one process must be configured"); + } + + var processNodes = processesNode.SelectNodes("f:process", nsManager); + if (processNodes == null || processNodes.Count == 0) + { + throw new InvalidOperationException("No process configurations found - at least one process must be configured"); + } + + var processList = new List(); + foreach (XmlNode processNode in processNodes) + { + var process = new ProcessConfig + { + Id = uint.Parse(GetRequiredAttribute(processNode, "id")), + MachineId = uint.Parse(GetRequiredAttribute(processNode, "machineId")), + StartupGroup = uint.Parse(GetRequiredAttribute(processNode, "startupGroup")) + }; + processList.Add(process); + } + + ProcessConfigData.Initialize(processList); + } + + private static void LoadWorldConfig(XmlNode serverNode, XmlNamespaceManager nsManager) + { + var worldsNode = serverNode.SelectSingleNode("f:worlds", nsManager); + if (worldsNode == null) + { + throw new InvalidOperationException("Missing worlds configuration - at least one world must be configured"); + } + + var worldNodes = worldsNode.SelectNodes("f:world", nsManager); + if (worldNodes == null || worldNodes.Count == 0) + { + throw new InvalidOperationException("No world configurations found - at least one world must be configured"); + } + + var worldList = new List(); + foreach (XmlNode worldNode in worldNodes) + { + var world = new WorldConfig + { + Id = uint.Parse(GetRequiredAttribute(worldNode, "id")), + WorldName = GetRequiredAttribute(worldNode, "worldName"), + DbConnection = GetOptionalAttribute(worldNode, "dbConnection") ?? string.Empty, + DbName = GetRequiredAttribute(worldNode, "dbName"), + DbType = GetRequiredAttribute(worldNode, "dbType") + }; + worldList.Add(world); + } + + WorldConfigData.Initialize(worldList); + } + + private static void LoadSceneConfig(XmlNode serverNode, XmlNamespaceManager nsManager) + { + var scenesNode = serverNode.SelectSingleNode("f:scenes", nsManager); + if (scenesNode == null) + { + throw new InvalidOperationException("Missing scenes configuration - at least one scene must be configured"); + } + + var sceneNodes = scenesNode.SelectNodes("f:scene", nsManager); + if (sceneNodes == null || sceneNodes.Count == 0) + { + throw new InvalidOperationException("No scene configurations found - at least one scene must be configured"); + } + + var sceneList = new List(); + foreach (XmlNode sceneNode in sceneNodes) + { + var scene = new SceneConfig + { + Id = uint.Parse(GetRequiredAttribute(sceneNode, "id")), + ProcessConfigId = uint.Parse(GetRequiredAttribute(sceneNode, "processConfigId")), + WorldConfigId = uint.Parse(GetRequiredAttribute(sceneNode, "worldConfigId")), + SceneRuntimeMode = GetRequiredAttribute(sceneNode, "sceneRuntimeMode"), + SceneTypeString = GetRequiredAttribute(sceneNode, "sceneTypeString"), + NetworkProtocol = GetOptionalAttribute(sceneNode, "networkProtocol") ?? string.Empty, + OuterPort = int.Parse(GetOptionalAttribute(sceneNode, "outerPort") ?? "0"), + InnerPort = int.Parse(GetRequiredAttribute(sceneNode, "innerPort")), + SceneType = int.Parse(GetRequiredAttribute(sceneNode, "sceneType")) + }; + sceneList.Add(scene); + } + + SceneConfigData.Initialize(sceneList); + } + + private static string GetRequiredAttribute(XmlNode node, string attributeName) + { + return node.Attributes?[attributeName]?.Value ?? throw new InvalidOperationException($"Required attribute '{attributeName}' is missing or null"); + } + + private static string? GetOptionalAttribute(XmlNode? node, string attributeName) + { + return node?.Attributes?[attributeName]?.Value; + } + + #endregion + + #region CheckConfig + + private static void CheckConfig() + { + // 检查Machine配置 + CheckMachineConfig(); + // 检查Process配置 + CheckProcessConfig(); + // 检查World配置 + CheckWorldConfig(); + // 检查Scene配置 + CheckSceneConfig(); + // 检查引用关系 + CheckConfigReferences(); + // 检查端口冲突 + CheckPortConflicts(); + } + + private static void CheckMachineConfig() + { + var machines = MachineConfigData.Instance.List; + var machineIds = new HashSet(); + + foreach (var machine in machines) + { + // 检查ID重复 + if (!machineIds.Add(machine.Id)) + { + throw new InvalidOperationException($"Duplicate machine ID: {machine.Id}"); + } + + // 检查必填字段 + if (string.IsNullOrWhiteSpace(machine.OuterIP)) + { + throw new InvalidOperationException($"Machine {machine.Id}: OuterIP cannot be null or empty"); + } + + if (string.IsNullOrWhiteSpace(machine.OuterBindIP)) + { + throw new InvalidOperationException($"Machine {machine.Id}: OuterBindIP cannot be null or empty"); + } + + if (string.IsNullOrWhiteSpace(machine.InnerBindIP)) + { + throw new InvalidOperationException($"Machine {machine.Id}: InnerBindIP cannot be null or empty"); + } + } + } + + private static void CheckProcessConfig() + { + var processes = ProcessConfigData.Instance.List; + var processIds = new HashSet(); + + foreach (var process in processes) + { + // 检查ID重复 + if (!processIds.Add(process.Id)) + { + throw new InvalidOperationException($"Duplicate process ID: {process.Id}"); + } + + // 检查必填字段 + if (process.Id == 0) + { + throw new InvalidOperationException("Process ID cannot be 0"); + } + + if (process.MachineId == 0) + { + throw new InvalidOperationException($"Process {process.Id}: MachineId cannot be 0"); + } + } + } + + private static void CheckWorldConfig() + { + var worlds = WorldConfigData.Instance.List; + var worldIds = new HashSet(); + + foreach (var world in worlds) + { + // 检查ID重复 + if (!worldIds.Add(world.Id)) + { + throw new InvalidOperationException($"Duplicate world ID: {world.Id}"); + } + + // 检查必填字段 + if (string.IsNullOrWhiteSpace(world.WorldName)) + { + throw new InvalidOperationException($"World {world.Id}: WorldName cannot be null or empty"); + } + + if (string.IsNullOrWhiteSpace(world.DbName)) + { + throw new InvalidOperationException($"World {world.Id}: DbName cannot be null or empty"); + } + + if (string.IsNullOrWhiteSpace(world.DbType)) + { + throw new InvalidOperationException($"World {world.Id}: DbType cannot be null or empty"); + } + } + } + + private static void CheckSceneConfig() + { + var scenes = SceneConfigData.Instance.List; + var sceneIds = new HashSet(); + + foreach (var scene in scenes) + { + // 检查ID重复 + if (!sceneIds.Add(scene.Id)) + { + throw new InvalidOperationException($"Duplicate scene ID: {scene.Id}"); + } + + // 检查必填字段 + if (scene.ProcessConfigId == 0) + { + throw new InvalidOperationException($"Scene {scene.Id}: ProcessConfigId cannot be 0"); + } + + if (scene.WorldConfigId == 0) + { + throw new InvalidOperationException($"Scene {scene.Id}: WorldConfigId cannot be 0"); + } + + if (string.IsNullOrWhiteSpace(scene.SceneRuntimeMode)) + { + throw new InvalidOperationException($"Scene {scene.Id}: SceneRuntimeMode cannot be null or empty"); + } + + if (string.IsNullOrWhiteSpace(scene.SceneTypeString)) + { + throw new InvalidOperationException($"Scene {scene.Id}: SceneTypeString cannot be null or empty"); + } + + if (scene.InnerPort == 0) + { + throw new InvalidOperationException($"Scene {scene.Id}: InnerPort cannot be 0"); + } + + if (scene.SceneType == 0) + { + throw new InvalidOperationException($"Scene {scene.Id}: SceneType cannot be 0"); + } + + // 检查NetworkProtocol配置 + if (scene.OuterPort > 0 && string.IsNullOrWhiteSpace(scene.NetworkProtocol)) + { + throw new InvalidOperationException($"Scene {scene.Id}: NetworkProtocol must be set when OuterPort > 0"); + } + + // 检查Scene ID范围(仅在IdFactoryType.World模式下) + CheckSceneIdRange(scene); + } + } + + private static void CheckConfigReferences() + { + // 检查Process的MachineId引用 + foreach (var process in ProcessConfigData.Instance.List) + { + if (MachineConfigData.Instance.List.All(m => m.Id != process.MachineId)) + { + throw new InvalidOperationException($"Process {process.Id}: Referenced MachineId {process.MachineId} not found"); + } + } + + // 检查Scene的ProcessConfigId和WorldConfigId引用 + foreach (var scene in SceneConfigData.Instance.List) + { + if (ProcessConfigData.Instance.List.All(p => p.Id != scene.ProcessConfigId)) + { + throw new InvalidOperationException($"Scene {scene.Id}: Referenced ProcessConfigId {scene.ProcessConfigId} not found"); + } + + if (WorldConfigData.Instance.List.All(w => w.Id != scene.WorldConfigId)) + { + throw new InvalidOperationException($"Scene {scene.Id}: Referenced WorldConfigId {scene.WorldConfigId} not found"); + } + } + } + + private static void CheckPortConflicts() + { + // 按机器分组检查端口冲突 + var machinePortMap = new Dictionary>(); // MachineId -> (Port -> SceneId) + + foreach (var scene in SceneConfigData.Instance.List) + { + // 获取Scene所属的机器ID + var process = ProcessConfigData.Instance.Get(scene.ProcessConfigId); + var machineId = process.MachineId; + + if (!machinePortMap.ContainsKey(machineId)) + { + machinePortMap[machineId] = new Dictionary(); + } + + var machinePorts = machinePortMap[machineId]; + + // 检查同一Scene内InnerPort和OuterPort是否冲突 + if (scene.OuterPort > 0 && scene.InnerPort == scene.OuterPort) + { + throw new InvalidOperationException($"Scene {scene.Id}: InnerPort and OuterPort cannot use the same port {scene.InnerPort}"); + } + + // 检查InnerPort在同一机器下是否与其他端口冲突 + if (machinePorts.TryGetValue(scene.InnerPort, out var conflictSceneId1)) + { + throw new InvalidOperationException($"Scene {scene.Id}: InnerPort {scene.InnerPort} conflicts with another port from Scene {conflictSceneId1} on Machine {machineId}"); + } + machinePorts[scene.InnerPort] = scene.Id; + + // 检查OuterPort在同一机器下是否与其他端口冲突(如果不为0) + if (scene.OuterPort > 0) + { + if (machinePorts.TryGetValue(scene.OuterPort, out var conflictSceneId)) + { + throw new InvalidOperationException($"Scene {scene.Id}: OuterPort {scene.OuterPort} conflicts with another port from Scene {conflictSceneId} on Machine {machineId}"); + } + machinePorts[scene.OuterPort] = scene.Id; + } + } + } + + private static void CheckSceneIdRange(SceneConfig scene) + { + // 检查当前是否为World模式的ID工厂 + if (IdFactoryHelper.GetIdFactoryType() != IdFactoryType.World) + { + return; // 非World模式不需要检查 + } + + var worldConfigId = scene.WorldConfigId; + var minAllowedId = worldConfigId * 1000 + 1; + var maxAllowedId = worldConfigId * 1000 + 255; + + if (scene.Id < minAllowedId) + { + throw new InvalidOperationException($"Scene {scene.Id}: ID must be >= {minAllowedId} (WorldConfigId {worldConfigId} * 1000 + 1)"); + } + + if (scene.Id > maxAllowedId) + { + throw new InvalidOperationException($"Scene {scene.Id}: ID must be <= {maxAllowedId} (WorldConfigId {worldConfigId} * 1000 + 255)"); + } + } + + #endregion + + #region LoadRuntimeConfig + + private static void LoadRuntimeConfig(XmlNode root, XmlNamespaceManager nsManager) + { + // 加载IdFactory配置 + + XmlNode? idFactoryNode = root.SelectSingleNode("f:idFactory", nsManager); + string idFactoryType = GetOptionalAttribute(idFactoryNode, "type") ?? "World"; + IdFactoryHelper.Initialize(Enum.Parse(idFactoryType)); + + // 加载网络配置 + + XmlNode? networkNode = root.SelectSingleNode("f:network", nsManager); + ProgramDefine.InnerNetwork = Enum.Parse(GetOptionalAttribute(networkNode, "inner") ?? "TCP"); + ProgramDefine.MaxMessageSize = int.Parse(GetOptionalAttribute(networkNode, "maxMessageSize") ?? "1048560"); + + // 加载会话配置 + + XmlNode? sessionNode = root.SelectSingleNode("f:session", nsManager); + ProgramDefine.SessionIdleCheckerTimeout = int.Parse(GetOptionalAttribute(sessionNode, "idleTimeout") ?? "8000"); + ProgramDefine.SessionIdleCheckerInterval = int.Parse(GetOptionalAttribute(sessionNode, "idleInterval") ?? "5000"); + + Log.Info($"Current inner network protocol:{ProgramDefine.InnerNetwork.ToString()}"); + Log.Info($"Max Message Size(byte):{ProgramDefine.MaxMessageSize}"); + Log.Info($"Current session idle timeout:{ProgramDefine.SessionIdleCheckerTimeout}"); + Log.Info($"Session-check interval:{ProgramDefine.SessionIdleCheckerInterval} "); + } + + #endregion +} +#endif diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs index e09b00e..b32996f 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs @@ -30,7 +30,29 @@ namespace Fantasy.Platform.Net /// public static void Initialize(string machineConfigJson) { - Instance = machineConfigJson.Deserialize(); + try + { + Instance = machineConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + catch (Exception e) + { + throw new InvalidOperationException($"MachineConfigData.Json format error {e.Message}"); + } + } + /// + /// 初始化MachineConfig + /// + /// + public static void Initialize(List list) + { + Instance = new MachineConfigData + { + List = list + }; foreach (var config in Instance.List) { Instance._configs.TryAdd(config.Id, config); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs index 4a400b0..73301ce 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs @@ -26,12 +26,34 @@ namespace Fantasy.Platform.Net /// public static ProcessConfigData Instance { get; private set; } /// - /// 初始化MachineConfig + /// 初始化ProcessConfig /// /// public static void Initialize(string processConfigJson) { - Instance = processConfigJson.Deserialize(); + try + { + Instance = processConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + catch (Exception e) + { + throw new InvalidOperationException($"ProcessConfigData.Json format error {e.Message}"); + } + } + /// + /// 初始化ProcessConfig + /// + /// + public static void Initialize(List list) + { + Instance = new ProcessConfigData + { + List = list + }; foreach (var config in Instance.List) { Instance._configs.TryAdd(config.Id, config); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs index e939419..14f8a1a 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs @@ -42,7 +42,27 @@ namespace Fantasy.Platform.Net /// public static void Initialize(string sceneConfigJson) { - Instance = sceneConfigJson.Deserialize(); + try + { + Instance = sceneConfigJson.Deserialize(); + Initialize(); + } + catch (Exception e) + { + throw new InvalidOperationException($"SceneConfigData.Json format error {e.Message}"); + } + } + /// + /// 初始化SceneConfig + /// + public static void Initialize(List sceneConfigs) + { + Instance = new SceneConfigData() { List = sceneConfigs }; + Initialize(); + } + + private static void Initialize() + { foreach (var config in Instance.List) { config.Initialize(); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs index 9b0ede5..30ff6bb 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs @@ -30,7 +30,29 @@ namespace Fantasy.Platform.Net /// public static void Initialize(string worldConfigJson) { - Instance = worldConfigJson.Deserialize(); + try + { + Instance = worldConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + catch (Exception e) + { + throw new InvalidOperationException($"WorldConfigData.Json format error {e.Message}"); + } + } + /// + /// 初始化WorldConfig + /// + /// + public static void Initialize(List list) + { + Instance = new WorldConfigData + { + List = list + }; foreach (var config in Instance.List) { Instance._configs.TryAdd(config.Id, config); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Entry.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Entry.cs index 959818d..dff5316 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Entry.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Entry.cs @@ -3,8 +3,6 @@ using CommandLine; using Fantasy.Assembly; using Fantasy.Async; using Fantasy.Helper; -using Fantasy.IdFactory; -using Fantasy.LowLevel; using Fantasy.Network; using Fantasy.Serialize; // ReSharper disable FunctionNeverReturns @@ -21,21 +19,33 @@ public static class Entry /// /// 框架初始化 /// + /// 日志实例 /// 注册的Assembly - public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) + /// + public static async FTask Initialize(ILog? log, params System.Reflection.Assembly[] assemblies) { + // 注册日志模块到框架 + if (log != null) + { + Log.Register(log); + } + Log.Info($"Fantasy Version:{ProgramDefine.VERSION}"); + // 加载Fantasy.config配置文件 + await ConfigLoader.InitializeFromXml(Path.Combine(AppContext.BaseDirectory, "Fantasy.config")); // 解析命令行参数 Parser.Default.ParseArguments(Environment.GetCommandLineArgs()) .WithNotParsed(error => throw new Exception("Command line format error!")) .WithParsed(option => { - ProcessDefine.Options = option; - ProcessDefine.InnerNetwork = Enum.Parse(option.InnerNetwork); + ProgramDefine.ProcessId = option.ProcessId; + ProgramDefine.ProcessType = option.ProcessType; + ProgramDefine.RuntimeMode = Enum.Parse(option.RuntimeMode); + ProgramDefine.StartupGroup = option.StartupGroup; }); // 初始化Log系统 Log.Initialize(); // 检查启动参数,后期可能有机器人等不同的启动参数 - switch (ProcessDefine.Options.ProcessType) + switch (ProgramDefine.ProcessType) { case "Game": { @@ -43,7 +53,7 @@ public static class Entry } default: { - throw new NotSupportedException($"ProcessType is {ProcessDefine.Options.ProcessType} Unrecognized!"); + throw new NotSupportedException($"ProcessType is {ProgramDefine.ProcessType} Unrecognized!"); } } // 初始化程序集管理系统 @@ -52,8 +62,15 @@ public static class Entry SerializerManager.Initialize(); // 精度处理(只针对Windows下有作用、其他系统没有这个问题、一般也不会用Windows来做服务器的) WinPeriod.Initialize(); + } - FantasyMemory.Initialize(); + /// + /// 框架初始化 + /// + /// 注册的Assembly + public static FTask Initialize(params System.Reflection.Assembly[] assemblies) + { + return Initialize(null, assemblies); } /// @@ -83,9 +100,9 @@ public static class Entry private static async FTask StartProcess() { - if (ProcessDefine.Options.StartupGroup != 0) + if (ProgramDefine.StartupGroup != 0) { - foreach (var processConfig in ProcessConfigData.Instance.ForEachByStartupGroup((uint)ProcessDefine.Options.StartupGroup)) + foreach (var processConfig in ProcessConfigData.Instance.ForEachByStartupGroup((uint)ProgramDefine.StartupGroup)) { await Process.Create(processConfig.Id); } @@ -93,9 +110,9 @@ public static class Entry return; } - switch (ProcessDefine.Options.Mode) + switch (ProgramDefine.RuntimeMode) { - case "Develop": + case ProcessMode.Develop: { foreach (var processConfig in ProcessConfigData.Instance.List) { @@ -104,9 +121,9 @@ public static class Entry return; } - case "Release": + case ProcessMode.Release: { - await Process.Create(ProcessDefine.Options.ProcessId); + await Process.Create(ProgramDefine.ProcessId); return; } } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ProcessDefine.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ProcessDefine.cs index 2bcc4e0..51732db 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ProcessDefine.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ProcessDefine.cs @@ -1,7 +1,5 @@ #if FANTASY_NET using CommandLine; -using Fantasy.Network; - #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. namespace Fantasy.Platform.Net; @@ -43,57 +41,12 @@ internal sealed class CommandLineOptions /// Develop - 开发模式(启动Process配置表中的所有Process) /// Release - 发布模式(根据ProcessId启动Process) /// - [Option('m', "Mode", Required = true, Default = "Release", HelpText = "Develop:启动Process配置表中的所有Process,\nRelease:根据ProcessId启动Process")] - public string Mode { get; set; } - /// - /// 服务器内部网络协议 - /// TCP - 服务器内部之间通讯使用TCP协议 - /// KCP - 服务器内部之间通讯使用KCP协议 - /// WebSocket - 服务器内部之间通讯使用WebSocket协议(不推荐、TCP或KCP) - /// - [Option('n', "InnerNetwork", Required = false, Default = "TCP", HelpText = "TCP、KCP、WebSocket")] - public string InnerNetwork { get; set; } - /// - /// 会话空闲检查超时时间。 - /// - [Option('t', "SessionIdleCheckerTimeout", Required = false, Default = 8000, HelpText = "Session idle check timeout")] - public int SessionIdleCheckerTimeout { get; set; } - /// - /// 会话空闲检查间隔。 - /// - [Option('i', "SessionIdleCheckerInterval", Required = false, Default = 5000, HelpText = "Session idle check interval")] - public int SessionIdleCheckerInterval { get; set; } + [Option('m', "RuntimeMode", Required = true, Default = "Release", HelpText = "Develop:启动Process配置表中的所有Process,\nRelease:根据ProcessId启动Process")] + public string RuntimeMode { get; set; } /// /// 启动组。 /// [Option('g', "StartupGroup", Required = false, Default = 0, HelpText = "Used to start a group of Process")] public int StartupGroup { get; set; } } - -/// -/// AppDefine -/// -internal static class ProcessDefine -{ - /// - /// 命令行选项 - /// - public static CommandLineOptions Options; - /// - /// App程序Id - /// - public static uint ProcessId => Options.ProcessId; - /// - /// 会话空闲检查超时时间。 - /// - public static int SessionIdleCheckerTimeout => Options.SessionIdleCheckerTimeout; - /// - /// 会话空闲检查间隔。 - /// - public static int SessionIdleCheckerInterval => Options.SessionIdleCheckerInterval; - /// - /// 内部网络通讯协议类型 - /// - public static NetworkProtocolType InnerNetwork; -} #endif \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/ProgramDefine.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/ProgramDefine.cs new file mode 100644 index 0000000..7e7299d --- /dev/null +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/ProgramDefine.cs @@ -0,0 +1,56 @@ +using System; +#if FANTASY_NET +using Fantasy.Network; +using Fantasy.Platform.Net; + +#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. +#endif + +namespace Fantasy +{ + /// + /// 程序定义 + /// + public static class ProgramDefine + { + /// + /// Fantasy版本。 + /// + public const string VERSION = "Fantasy 2.0 Beta"; + /// + /// 消息体最大长度(字节)。默认1024k。 + /// 注意:前后端设置的消息大小,一定要一样才可以,不然会不出现问题。 + /// + public static int MaxMessageSize { get; set; } = ushort.MaxValue * 16; +#if FANTASY_NET + /// + /// App程序Id。 + /// + public static uint ProcessId { get; internal set; } + /// + /// 应用程序的类型。 + /// + public static string ProcessType { get; internal set; } + /// + /// 服务器运行模式,获取或设置服务器的运行模式。 + /// + public static ProcessMode RuntimeMode { get; internal set; } + /// + /// 服务器启动组 + /// + public static int StartupGroup { get; internal set; } + /// + /// 会话空闲检查超时时间。 + /// + public static int SessionIdleCheckerTimeout { get; internal set; } + /// + /// 会话空闲检查间隔。 + /// + public static int SessionIdleCheckerInterval { get; internal set; } + /// + /// 内部网络通讯协议类型。 + /// + public static NetworkProtocolType InnerNetwork { get; internal set; } +#endif + } +} \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Entry.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Entry.cs index e5377f2..f0fa9e6 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Entry.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Entry.cs @@ -1,4 +1,5 @@ #if FANTASY_UNITY +using System; using System.Linq; using Fantasy.Assembly; using Fantasy.Async; @@ -52,6 +53,8 @@ namespace Fantasy.Platform.Unity } FantasyObject.OnRuntimeMethodLoad(); Log.Register(new UnityLog()); + ProgramDefine.MaxMessageSize = ushort.MaxValue * 16; + Log.Info($"Fantasy Version:{ProgramDefine.VERSION}"); await AssemblySystem.InnerInitialize(assemblies); // 初始化序列化 SerializerManager.Initialize(); @@ -86,6 +89,11 @@ namespace Fantasy.Platform.Unity ThreadScheduler.Update(); } + private void LateUpdate() + { + ThreadScheduler.LateUpdate(); + } + private void OnDestroy() { AssemblySystem.Dispose(); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/ISceneUpdate.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/ISceneUpdate.cs index f736edf..f83aec7 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/ISceneUpdate.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/ISceneUpdate.cs @@ -9,7 +9,23 @@ namespace Fantasy { public void Update() { + + } + } + +#if FANTASY_UNITY + internal interface ISceneLateUpdate + { + void LateUpdate(); + } + + internal sealed class EmptySceneLateUpdate : ISceneLateUpdate + { + public void LateUpdate() + { } } +#endif + } \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scene.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scene.cs index e961533..15ced7e 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scene.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scene.cs @@ -163,7 +163,11 @@ namespace Fantasy EntityPool = new EntityPool(); EntityListPool = new EntityListPool(); EntitySortedDictionaryPool = new EntitySortedDictionaryPool(); - SceneUpdate = EntityComponent = await Create(this, false, false).Initialize(); + EntityComponent = await Create(this, false, false).Initialize(); + SceneUpdate = EntityComponent; +#if FANTASY_UNITY + SceneLateUpdate = EntityComponent; +#endif MessagePoolComponent = Create(this,false,true); EventComponent = await Create(this,false,true).Initialize(); TimerComponent = Create(this, false, true).Initialize(); @@ -265,6 +269,7 @@ namespace Fantasy #elif FANTASY_UNITY Session = null; UnityNetwork = null; + SceneLateUpdate = null; #endif ThreadSynchronizationContext = null; SceneRuntimeType = SceneRuntimeType.None; @@ -273,7 +278,6 @@ namespace Fantasy #endregion internal ISceneUpdate SceneUpdate { get; set; } - internal void Update() { try @@ -285,7 +289,20 @@ namespace Fantasy Log.Error(e); } } - +#if FANTASY_UNITY + internal ISceneLateUpdate SceneLateUpdate { get; set; } + internal void LateUpdate() + { + try + { + SceneLateUpdate.LateUpdate(); + } + catch (Exception e) + { + Log.Error(e); + } + } +#endif #region Create #if FANTASY_UNITY || FANTASY_CONSOLE @@ -379,7 +396,7 @@ namespace Fantasy if (sceneConfig.InnerPort != 0) { // 创建内网网络服务器 - scene.InnerNetwork = NetworkProtocolFactory.CreateServer(scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner, machineConfig.InnerBindIP, sceneConfig.InnerPort); + scene.InnerNetwork = NetworkProtocolFactory.CreateServer(scene, ProgramDefine.InnerNetwork, NetworkTarget.Inner, machineConfig.InnerBindIP, sceneConfig.InnerPort); } if (sceneConfig.OuterPort != 0) @@ -446,6 +463,9 @@ namespace Fantasy { scene.ThreadSynchronizationContext = ThreadScheduler.MainScheduler.ThreadSynchronizationContext; scene.SceneUpdate = new EmptySceneUpdate(); +#if FANTASY_UNITY + scene.SceneLateUpdate = new EmptySceneLateUpdate(); +#endif ThreadScheduler.AddMainScheduler(scene); await scene.Initialize(); break; @@ -456,6 +476,9 @@ namespace Fantasy scene.ThreadSynchronizationContext = new ThreadSynchronizationContext(); #endif scene.SceneUpdate = new EmptySceneUpdate(); +#if FANTASY_UNITY + scene.SceneLateUpdate = new EmptySceneLateUpdate(); +#endif ThreadScheduler.AddToMultiThreadScheduler(scene); await scene.Initialize(); break; @@ -466,6 +489,9 @@ namespace Fantasy scene.ThreadSynchronizationContext = new ThreadSynchronizationContext(); #endif scene.SceneUpdate = new EmptySceneUpdate(); +#if FANTASY_UNITY + scene.SceneLateUpdate = new EmptySceneLateUpdate(); +#endif ThreadScheduler.AddToThreadPoolScheduler(scene); await scene.Initialize(); break; @@ -567,7 +593,7 @@ namespace Fantasy /// /// /// - public virtual Session GetSession(long runTimeId) + internal virtual Session GetSession(long runTimeId) { var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref runTimeId); @@ -605,7 +631,7 @@ namespace Fantasy } var remoteAddress = $"{machineConfig.InnerBindIP}:{sceneConfig.InnerPort}"; - var client = NetworkProtocolFactory.CreateClient(Scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner); + var client = NetworkProtocolFactory.CreateClient(Scene, ProgramDefine.InnerNetwork, NetworkTarget.Inner); var session = client.Connect(remoteAddress, null, () => { Log.Error($"Unable to connect to the target server sourceServerId:{Scene.Process.Id} targetServerId:{sceneConfig.ProcessConfigId}"); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MainScheduler.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MainScheduler.cs index 692def0..4db5ee9 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MainScheduler.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MainScheduler.cs @@ -15,7 +15,7 @@ namespace Fantasy public MainScheduler() { ThreadSynchronizationContext = new ThreadSynchronizationContext(); -#if !FANTASY_WEBGL +#if !FANTASY_WEBGL || !UNITY_EDITOR SynchronizationContext.SetSynchronizationContext(ThreadSynchronizationContext); #endif } @@ -79,5 +79,27 @@ namespace Fantasy _queue.Enqueue(scene); } } +#if FANTASY_UNITY + public void LateUpdate() + { + var initialCount = _queue.Count; + + while (initialCount-- > 0) + { + if(!_queue.TryDequeue(out var scene)) + { + continue; + } + + if (scene.IsDisposed) + { + continue; + } + + scene.LateUpdate(); + _queue.Enqueue(scene); + } + } +#endif } } \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs index 9f5a44c..d8353f5 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs @@ -11,7 +11,7 @@ namespace Fantasy { private bool _isDisposed; private readonly List _threads; - private readonly ConcurrentBag _queue = new ConcurrentBag(); + private readonly ConcurrentQueue _queue = new ConcurrentQueue(); private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); public ThreadPoolScheduler() @@ -63,7 +63,7 @@ namespace Fantasy return; } - _queue.Add(scene); + _queue.Enqueue(scene); } public void Remove(Scene scene) @@ -75,20 +75,18 @@ namespace Fantasy var newQueue = new Queue(); - while (!_queue.IsEmpty) + while (_queue.TryDequeue(out var currentScene)) { - if (_queue.TryTake(out var currentScene)) + if (currentScene == scene) { - if (currentScene != scene) - { - newQueue.Enqueue(currentScene); - } + continue; } + newQueue.Enqueue(currentScene); } while (newQueue.TryDequeue(out var newScene)) { - _queue.Add(newScene); + _queue.Enqueue(newScene); } } @@ -101,7 +99,7 @@ namespace Fantasy { while (!cancellationToken.IsCancellationRequested) { - if (_queue.TryTake(out var scene)) + if (_queue.TryDequeue(out var scene)) { if (scene == null || scene.IsDisposed) { @@ -124,9 +122,9 @@ namespace Fantasy { SynchronizationContext.SetSynchronizationContext(null); } - - _queue.Add(scene); + // 先停止线程后再如队列,避免同一个Scene多次重复执行 Thread.Sleep(1); + _queue.Enqueue(scene); } else { diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs index 5bd0dea..9610581 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs @@ -30,6 +30,13 @@ namespace Fantasy MainScheduler.Update(); } +#if FANTASY_UNITY + internal static void LateUpdate() + { + MainScheduler.LateUpdate(); + } +#endif + internal static void AddMainScheduler(Scene scene) { MainScheduler.Add(scene); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SubScene.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SubScene.cs index 438b8ba..a8c2e73 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SubScene.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SubScene.cs @@ -22,24 +22,27 @@ namespace Fantasy /// 存储当前Scene下管理的实体。 /// private readonly Dictionary _entities = new Dictionary(); - - internal void Initialize(Scene rootScene) + + internal void Initialize(Scene rootScene) { EntityPool = rootScene.EntityPool; EntityListPool = rootScene.EntityListPool; EntitySortedDictionaryPool = rootScene.EntitySortedDictionaryPool; SceneUpdate = rootScene.SceneUpdate; +#if FANTASY_UNITY + SceneLateUpdate = rootScene.SceneLateUpdate; +#endif TimerComponent = rootScene.TimerComponent; EventComponent = rootScene.EventComponent; EntityComponent = rootScene.EntityComponent; MessagePoolComponent = rootScene.MessagePoolComponent; CoroutineLockComponent = rootScene.CoroutineLockComponent; MessageDispatcherComponent = rootScene.MessageDispatcherComponent; - #if FANTASY_NET +#if FANTASY_NET NetworkMessagingComponent = rootScene.NetworkMessagingComponent; SingleCollectionComponent = rootScene.SingleCollectionComponent; TerminusComponent = rootScene.TerminusComponent; - #endif +#endif ThreadSynchronizationContext = rootScene.ThreadSynchronizationContext; } @@ -162,7 +165,7 @@ namespace Fantasy /// /// /// - public override Session GetSession(long runTimeId) + internal override Session GetSession(long runTimeId) { return RootScene.GetSession(runTimeId); } diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs index bb5293b..cf97a8c 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs @@ -272,7 +272,7 @@ namespace Fantasy.Serialize /// /// /// - public static byte[] Serialize(object @object) + public byte[] Serialize(object @object) { if (@object is ASerialize aSerialize) { @@ -287,7 +287,7 @@ namespace Fantasy.Serialize /// /// /// - public static byte[] Serialize(T @object) + public byte[] Serialize(T @object) { if (@object is ASerialize aSerialize) { diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs index df44fcb..bfcc95f 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs @@ -36,6 +36,16 @@ namespace Fantasy.Serialize throw new NotImplementedException(); } + public byte[] Serialize(object obj) + { + throw new NotImplementedException(); + } + + public byte[] Serialize(T @object) + { + throw new NotImplementedException(); + } + public void Serialize(T @object, IBufferWriter buffer) { throw new NotImplementedException(); diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ISerialize.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ISerialize.cs index a3a9159..3152f53 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ISerialize.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ISerialize.cs @@ -59,6 +59,19 @@ namespace Fantasy.Serialize /// /// 序列化 /// + /// + /// + byte[] Serialize(object obj); + /// + /// 序列化 + /// + /// + /// + /// + byte[] Serialize(T @object); + /// + /// 序列化 + /// /// /// /// diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs index dc3886b..5e28808 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs @@ -182,7 +182,12 @@ namespace Fantasy.Serialize RuntimeTypeModel.Default.Serialize(buffer, @object); } - internal byte[] Serialize(object @object) + /// + /// 使用ProtoBuf序列化某一个实例到byte[] + /// + /// + /// + public byte[] Serialize(object @object) { if (@object is ASerialize aSerialize) { @@ -195,7 +200,13 @@ namespace Fantasy.Serialize return buffer.ToArray(); } } - private byte[] Serialize(T @object) + /// + /// 使用ProtoBuf序列化某一个实例到byte[] + /// + /// + /// + /// + public byte[] Serialize(T @object) { if (@object is ASerialize aSerialize) { diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs index 6df5903..0e386af 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs @@ -174,7 +174,30 @@ namespace Fantasy.Serialize RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object); } - private byte[] Serialize(T @object) + /// + /// 使用ProtoBuf序列化某一个实例到byte[] + /// + /// + /// + public byte[] Serialize(object @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using (var buffer = new MemoryStream()) + { + RuntimeTypeModel.Default.Serialize(buffer, @object); + return buffer.ToArray(); + } + } + /// + /// 使用ProtoBuf序列化某一个实例到byte[] + /// + /// + /// + public byte[] Serialize(T @object) { if (@object is ASerialize aSerialize) { diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/SerializerManager.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/SerializerManager.cs index 2272074..1ff52aa 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/SerializerManager.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/SerializerManager.cs @@ -88,7 +88,9 @@ namespace Fantasy.Serialize } _isInitialized = true; +#if FANTASY_DEBUG Log.Info($"初始化序列化器成功,数量为:{_serializers.Length}"); +#endif } catch (Exception e) { @@ -118,6 +120,12 @@ namespace Fantasy.Serialize public static void Dispose() { _isInitialized = false; + + if (_serializers == null || _serializers.Length == 0) + { + return; + } + Array.Clear(_serializers, 0, _serializers.Length); } diff --git a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigContext.cs b/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigContext.cs new file mode 100644 index 0000000..c3e1836 --- /dev/null +++ b/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigContext.cs @@ -0,0 +1,85 @@ +namespace Fantasy.ConfigTable; + +public interface IConfigContext +{ + // 定义非泛型接口 +} + +public class ConfigContext : IConfigContext where T : IConfigTable +{ + private static List _cacheList = new List(); + + #region Cache + + public void Association(List list) + { + if (list != null) + { + _cacheList = list; + } + } + + #endregion + + public int Count() + { + return _cacheList.Count; + } + + public int Count(Func predicate) + { + return _cacheList.Count(predicate); + } + + public T Get(uint key) + { + return First(key); + } + + public T Fist() + { + return _cacheList.First(); + } + + public T Last() + { + return _cacheList.Last(); + } + + public T Fist(Predicate match) + { + return Get(match); + } + + public T Last(Predicate match) + { + return _cacheList.FindLast(match); + } + + public T Get(Predicate match) + { + return _cacheList.Find(match); + } + + public T GetRandom() + { + Random random = new Random(); + // 随机从列表中取一个对象 + return _cacheList[random.Next(_cacheList.Count)]; + } + + public List GetList() + { + return _cacheList; + } + + public List GetList(Predicate match) + { + return _cacheList.FindAll(match); + } + + private T First(uint key) + { + return _cacheList.Find(t => t.Key == key); + } +} \ No newline at end of file diff --git a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigTableHelper.cs b/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigTableHelper.cs index 242bd3c..e2d5ea9 100644 --- a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigTableHelper.cs +++ b/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigTableHelper.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; using System.IO; +using System.Reflection; +using Fantasy.Assembly; +using Fantasy.Helper; using Fantasy.Platform.Net; using Fantasy.Serialize; -#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +using Newtonsoft.Json.Linq; // ReSharper disable SuspiciousTypeConversion.Global @@ -14,81 +17,178 @@ namespace Fantasy.ConfigTable /// public static class ConfigTableHelper { - private static string _configTableBinaryDirectory; - private static readonly object Lock = new object(); - // 配置表数据缓存字典 - private static readonly Dictionary ConfigDic = new (); + private static readonly Dictionary _dictionary = new Dictionary(); + /// /// 初始化ConfigTableHelper /// - /// - public static void Initialize(string configTableBinaryDirectory) + public static void Initialize(string json, params System.Reflection.Assembly[] assemblies) { - _configTableBinaryDirectory = configTableBinaryDirectory; - } - /// - /// 加载配置表数据 - /// - /// 配置表类型 - /// 配置表数据 - public static T Load() where T : ASerialize - { - lock (Lock) + var jsonObj = JObject.Parse(json); + Dictionary tokens = new(); + foreach (var item in jsonObj) { try { - var dataConfig = typeof(T).Name; - - if (ConfigDic.TryGetValue(dataConfig, out var aProto)) + var name = item.Key; + var value = item.Value; + if (value is JArray jArray) { - return (T)aProto; + tokens[name] = jArray; } - - var configFile = GetConfigPath(dataConfig); - var bytes = File.ReadAllBytes(configFile); - // Log.Debug($"dataConfig:{dataConfig} {bytes.Length}"); - var data = SerializerManager.GetSerializer(FantasySerializerType.ProtoBuf).Deserialize(bytes); - ConfigDic[dataConfig] = data; - return data; } - catch (Exception ex) + catch (Exception e) { - throw new Exception($"ConfigTableManage:{typeof(T).Name} 数据表加载之后反序列化时出错:{ex}"); + Log.Error($"读表异常,请检查,name={item.Key} ex={e}"); } } + + foreach (var type in GetAllConfigTableTypes(assemblies)) + { + var name = type.Name; + if (tokens.TryGetValue(name, out var jArray)) + { + // 通过反射调用 ParseJson 方法 + var parseMethod = type.GetMethod("ParseJson", BindingFlags.Public | BindingFlags.Static); + parseMethod?.Invoke(null, [jArray]); + } + } + + var d = _dictionary; + } + + public static ConfigContext Table() where T : IConfigTable + { + var type = typeof(T); + if (_dictionary.TryGetValue(type, out var context)) + { + return context as ConfigContext; + } + + var jsonContext = new ConfigContext(); + _dictionary[type] = jsonContext; + return jsonContext; + } + + public static List ParseLine(JArray arr) where T : IConfigTable, new() + { + List list = new List(); + foreach (var jToken in arr) + { + T instance = jToken.ToObject(); + + if (instance != null) + { + list.Add(instance); + } + } + + var context = Table(); + context.Association(list); + + return list; } /// - /// 获取配置表文件路径 + /// 获取所有实现了 IConfigTable 接口的非抽象类 /// - /// 配置表名称 - /// 配置表文件路径 - private static string GetConfigPath(string name) + /// 所有非抽象的配置对象类 + private static List GetAllConfigTableTypes(params System.Reflection.Assembly[] assemblies) { - var configFile = Path.Combine(_configTableBinaryDirectory, $"{name}.bytes"); + var types = new List(); + var interfaceType = typeof(IConfigTable); - if (File.Exists(configFile)) + // 遍历当前程序集中的所有类型 + foreach (var assembly in assemblies) { - return configFile; - } - - throw new FileNotFoundException($"{name}.byte not found: {configFile}"); - } - - /// - /// 重新加载配置表数据 - /// - public static void ReLoadConfigTable() - { - lock (Lock) - { - foreach (var (_, aProto) in ConfigDic) + foreach (var type in assembly.GetTypes()) { - ((IDisposable) aProto).Dispose(); + // 检查是否实现了 IConfigTable 接口,并且不是抽象类 + if (interfaceType.IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface) + { + types.Add(type); + } } - - ConfigDic.Clear(); } + + return types; } + + // private static string _configTableBinaryDirectory; + // private static readonly object Lock = new object(); + // // 配置表数据缓存字典 + // private static readonly Dictionary ConfigDic = new (); + // /// + // /// 初始化ConfigTableHelper + // /// + // /// + // public static void Initialize(string configTableBinaryDirectory) + // { + // _configTableBinaryDirectory = configTableBinaryDirectory; + // } + // /// + // /// 加载配置表数据 + // /// + // /// 配置表类型 + // /// 配置表数据 + // public static T Load() where T : ASerialize + // { + // lock (Lock) + // { + // try + // { + // var dataConfig = typeof(T).Name; + // + // if (ConfigDic.TryGetValue(dataConfig, out var aProto)) + // { + // return (T)aProto; + // } + // + // var configFile = GetConfigPath(dataConfig); + // var bytes = File.ReadAllBytes(configFile); + // // Log.Debug($"dataConfig:{dataConfig} {bytes.Length}"); + // var data = SerializerManager.GetSerializer(FantasySerializerType.ProtoBuf).Deserialize(bytes); + // ConfigDic[dataConfig] = data; + // return data; + // } + // catch (Exception ex) + // { + // throw new Exception($"ConfigTableManage:{typeof(T).Name} 数据表加载之后反序列化时出错:{ex}"); + // } + // } + // } + // + // /// + // /// 获取配置表文件路径 + // /// + // /// 配置表名称 + // /// 配置表文件路径 + // private static string GetConfigPath(string name) + // { + // var configFile = Path.Combine(_configTableBinaryDirectory, $"{name}.bytes"); + // + // if (File.Exists(configFile)) + // { + // return configFile; + // } + // + // throw new FileNotFoundException($"{name}.byte not found: {configFile}"); + // } + // + // /// + // /// 重新加载配置表数据 + // /// + // public static void ReLoadConfigTable() + // { + // lock (Lock) + // { + // foreach (var (_, aProto) in ConfigDic) + // { + // ((IDisposable) aProto).Dispose(); + // } + // + // ConfigDic.Clear(); + // } + // } } -} +} \ No newline at end of file diff --git a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/IntDictionaryConfig.cs b/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/IntDictionaryConfig.cs deleted file mode 100644 index a9b13b3..0000000 --- a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/IntDictionaryConfig.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using ProtoBuf; -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - -// ReSharper disable CheckNamespace -#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - -namespace Fantasy.ConfigTable -{ - [ProtoContract] - public partial class IntDictionaryConfig - { - [ProtoMember(1)] - public Dictionary Dic; - public int this[int key] => GetValue(key); - public bool TryGetValue(int key, out int value) - { - value = default; - - if (!Dic.ContainsKey(key)) - { - return false; - } - - value = Dic[key]; - return true; - } - private int GetValue(int key) - { - return Dic.TryGetValue(key, out var value) ? value : 0; - } - } -} \ No newline at end of file diff --git a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/StringDictionaryConfig.cs b/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/StringDictionaryConfig.cs deleted file mode 100644 index 708ccd7..0000000 --- a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/StringDictionaryConfig.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using ProtoBuf; -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - -// ReSharper disable CheckNamespace -// ReSharper disable CollectionNeverUpdated.Global -#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. -#pragma warning disable CS8603 // Possible null reference return. -namespace Fantasy.ConfigTable -{ - [ProtoContract] - public sealed partial class StringDictionaryConfig - { - [ProtoMember(1)] - public Dictionary Dic; - public string this[int key] => GetValue(key); - public bool TryGetValue(int key, out string value) - { - value = default; - - if (!Dic.ContainsKey(key)) - { - return false; - } - - value = Dic[key]; - return true; - } - private string GetValue(int key) - { - return Dic.TryGetValue(key, out var value) ? value : null; - } - } -} \ No newline at end of file diff --git a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Interface/IConfigTable.cs b/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Interface/IConfigTable.cs index 0992677..56e3c8c 100644 --- a/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Interface/IConfigTable.cs +++ b/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Interface/IConfigTable.cs @@ -3,5 +3,8 @@ namespace Fantasy.ConfigTable /// /// 表示是一个配置文件 /// - public interface IConfigTable { } + public interface IConfigTable + { + public uint Key { get; } + } } \ No newline at end of file diff --git a/Hotfix/Game/Cache/System/PlayerBasicCacheManageComponentSystem.cs b/Hotfix/Game/Cache/System/PlayerBasicCacheManageComponentSystem.cs index eaea42a..b138f4c 100644 --- a/Hotfix/Game/Cache/System/PlayerBasicCacheManageComponentSystem.cs +++ b/Hotfix/Game/Cache/System/PlayerBasicCacheManageComponentSystem.cs @@ -122,7 +122,7 @@ public static class PlayerBasicCacheManageComponentSystem cache.Country = player.Country; cache.Head = player.Head; cache.Level = player.Level; - cache.IsVip = player.IsVip; + cache.Vip = player.Vip; cache.ExpirationTime = TimeHelper.Now + TimeHelper.OneDay; //更新则过期时间增加一天 return cache; diff --git a/Hotfix/Game/Cache/System/PlayerBasicCacheSystem.cs b/Hotfix/Game/Cache/System/PlayerBasicCacheSystem.cs index 57f3afd..c71c3a5 100644 --- a/Hotfix/Game/Cache/System/PlayerBasicCacheSystem.cs +++ b/Hotfix/Game/Cache/System/PlayerBasicCacheSystem.cs @@ -11,7 +11,7 @@ public class PlayerBasicCacheDestroySystem : DestroySystem self.NickName = string.Empty; self.Head = string.Empty; self.Level = 0; - self.IsVip = false; + self.Vip = 0; self.ExpirationTime = 0; } } @@ -26,7 +26,7 @@ public static class PlayerBasicCacheSystem ret.Country = player.Country; ret.Head = player.Head; ret.Level = player.Level; - ret.Vip = player.IsVip; + ret.Vip = player.Vip; ret.RoleId = player.Id; return ret; } diff --git a/Hotfix/Game/Item/Helper/ItemFactory.cs b/Hotfix/Game/Item/Helper/ItemFactory.cs index c6549e6..09faab1 100644 --- a/Hotfix/Game/Item/Helper/ItemFactory.cs +++ b/Hotfix/Game/Item/Helper/ItemFactory.cs @@ -13,7 +13,7 @@ public static class ItemFactory /// /// /// - public static Item Create(Scene scene, int configId, int count = 1) + public static Item Create(Scene scene, uint configId, int count = 1) { var item = Entity.Create(scene, true, true); item.ConfigId = configId; diff --git a/Hotfix/Game/Item/Helper/ItemHelper.cs b/Hotfix/Game/Item/Helper/ItemHelper.cs new file mode 100644 index 0000000..fc75258 --- /dev/null +++ b/Hotfix/Game/Item/Helper/ItemHelper.cs @@ -0,0 +1,20 @@ +namespace NB.Game; + +public static class ItemHelper +{ + public static ItemBasicType GetType(uint id) + { + var type = (int)(id / 10000); + if (type == 1) + { + return ItemBasicType.Currency; + } + + if (type == 21) + { + return ItemBasicType.Fish; + } + + return ItemBasicType.Item; + } +} \ No newline at end of file diff --git a/Hotfix/Game/Item/ItemContainerSystem.cs b/Hotfix/Game/Item/PlayerItemContainerComponentSystem.cs similarity index 76% rename from Hotfix/Game/Item/ItemContainerSystem.cs rename to Hotfix/Game/Item/PlayerItemContainerComponentSystem.cs index 1800689..91585da 100644 --- a/Hotfix/Game/Item/ItemContainerSystem.cs +++ b/Hotfix/Game/Item/PlayerItemContainerComponentSystem.cs @@ -1,11 +1,12 @@ using Fantasy; +using Fantasy.Async; using Fantasy.Entitas.Interface; namespace NB.Game; -public sealed class ItemContainerDestroySystem : DestroySystem +public sealed class ItemContainerDestroySystem : DestroySystem { - protected override void Destroy(PlayerItemContainer self) + protected override void Destroy(PlayerItemContainerComponent self) { self.CellCountMax = 0; @@ -20,8 +21,17 @@ public sealed class ItemContainerDestroySystem : DestroySystem @@ -31,7 +41,7 @@ public static class ItemContainerSystem /// /// /// - public static bool GetItemById(this PlayerItemContainer self, long id, out Item? item) + public static bool GetItemById(this PlayerItemContainerComponent self, long id, out Item? item) { return self.Items.TryGetValue(id, out item); } @@ -42,7 +52,7 @@ public static class ItemContainerSystem /// /// /// - public static bool GetFistItemByConfigId(this PlayerItemContainer self, int configId, out Item? item) + public static bool GetFistItemByConfigId(this PlayerItemContainerComponent self, int configId, out Item? item) { foreach (var (_, it) in self.Items) { @@ -100,17 +110,31 @@ public static class ItemContainerSystem #region Add - public static void Add(this PlayerItemContainer self, int configId, int count) + public static async FTask Add(this PlayerItemContainerComponent self, Dictionary items) + { + foreach (var (configId, count) in items) + { + await self.Add(configId, count, false); + } + + await self.Save(); + } + + public static async FTask Add(this PlayerItemContainerComponent self, uint configId, int count, bool needSave = true) { var item = ItemFactory.Create(self.Scene, configId, count); self.Items.Add(item.Id, item); + if (needSave) + { + await self.Save(); + } } #endregion #region 结构转换 - public static List GetItemInfos(this PlayerItemContainer self) + public static List GetItemInfos(this PlayerItemContainerComponent self) { List ret = new List(); foreach (var (_, item) in self.Items) @@ -121,7 +145,7 @@ public static class ItemContainerSystem return ret; } - public static List GetGearInfos(this PlayerItemContainer self) + public static List GetGearInfos(this PlayerItemContainerComponent self) { List ret = new List(); diff --git a/Hotfix/Game/Player/Components/PlayerManageComponentSystem.cs b/Hotfix/Game/Player/Components/PlayerManageComponentSystem.cs index ecf7644..3c5ac1d 100644 --- a/Hotfix/Game/Player/Components/PlayerManageComponentSystem.cs +++ b/Hotfix/Game/Player/Components/PlayerManageComponentSystem.cs @@ -3,6 +3,7 @@ using Fantasy.Async; using Fantasy.Entitas; using Fantasy.Entitas.Interface; using Fantasy.Helper; +using NBF; #pragma warning disable CS8603 // 可能返回 null 引用。 @@ -45,37 +46,28 @@ public static class PlayerManageComponentSystem { // 首先要先到数据库中查询是否有这个账号 account = await PlayerHelper.LoadDataBase(self.Scene, accountId); + bool needInit = false; // 如果有的话,就直接加入在缓存中就可以了 if (account == null) { Log.Debug("检查到账号没有在数据库中,需要创建一个新的账号并且保存到数据库中"); - // 如果没有,就要创建一个新的并且保存到数据库。 - // 如果不存在,表示这是一个新的账号,需要创建一下这个账号。 account = PlayerFactory.Create(self.Scene, accountId); - - account.Level = 99; - account.NickName = "王麻子"; - account.Country = "cn"; - account.Exp = 999; - account.Head = "xxx.png"; - - // for (int i = 0; i < 500; i++) - // { - // var item = Entity.Create(scene, true, true); - // account.ItemContainer.Add(item.Id, item); - // } - // - // for (int i = 0; i < 500; i++) - // { - // var item = Entity.Create(scene, true, true); - // account.Fishes.Add(item.Id, item); - // } + needInit = true; } else { Log.Debug("检查到账号在数据库中"); } + await account.TryComponent(); + await account.TryComponent(); + await account.TryComponent(); + + if (needInit) + { + await account.InitPlayer(); + } + Log.Debug("把当前账号添加到缓存中"); // 把创建完成的Account放入到缓存中 self.Add(account); @@ -152,6 +144,69 @@ public static class PlayerManageComponentSystem #endregion + #region 初始化新号数据 + + public static async Task InitPlayer(this Player player) + { + //TODO: 处理基础信息 + player.Level = 99; + player.NickName = "王麻子"; + player.Country = "cn"; + player.Exp = 999; + player.Head = "xxx.png"; + + var list = InitConfig.GetList(); + + + Dictionary> + addDic = new Dictionary>(); + foreach (var initConfig in list) + { + var itemType = ItemHelper.GetType(initConfig.ItemId); + if (!addDic.TryGetValue(itemType, out var dic)) + { + dic = new Dictionary(); + addDic.Add(itemType, dic); + } + + if (!dic.ContainsKey(initConfig.ItemId)) + { + dic.Add(initConfig.ItemId, initConfig.Amount); + } + else + { + dic[initConfig.ItemId] += initConfig.Amount; + } + } + + foreach (var (itemType, dictionary) in addDic) + { + if (itemType == ItemBasicType.Item) + { + var itemContainer = player.GetComponent(); + await itemContainer.Add(dictionary); + } + else if (itemType == ItemBasicType.Currency) + { + var playerWallet = player.GetComponent(); + foreach (var (key, value) in dictionary) + { + if (value > 0) + { + await playerWallet.Add(key, value); + } + else if (value < 0) + { + await playerWallet.Sub(key, value); + } + } + } + } + } + + #endregion + + #region 组件 /// diff --git a/Hotfix/Game/Player/Entity/PlayerSystem.cs b/Hotfix/Game/Player/Entity/PlayerSystem.cs index a5f1b36..20cfc76 100644 --- a/Hotfix/Game/Player/Entity/PlayerSystem.cs +++ b/Hotfix/Game/Player/Entity/PlayerSystem.cs @@ -1,3 +1,4 @@ +using System.Net.Http.Headers; using Fantasy; using Fantasy.Async; using Fantasy.Entitas; @@ -35,55 +36,71 @@ public sealed class PlayerDestroySystem : DestroySystem public static class PlayerSystem { + #region 物品 + + /// + /// 添加物品 + /// + /// + /// + /// + public static async FTask AddItems(this Player self, Dictionary items) + { + + var itemContainer = self.GetComponent(); + HashSet addType = new HashSet(); + foreach (var (key, value) in items) + { + var itemType = ItemHelper.GetType(key); + switch (itemType) + { + case ItemBasicType.Item: + itemContainer.Add(key, value); + addType.Add(ItemBasicType.Item); + break; + } + } + } + + #endregion + #region 测试数据 public static void SetTestData(this Player player) { - List addItemConfigs = new List() - { - 100001, 100002, 100003, - 200001, - 300001, 300002, 300003, - 400001, - 500001, 500002, - 600001, 600002, 600003, 600004, - 700001, - 800001 - }; + Dictionary> rigDic = new Dictionary>() { - { 100001, [300001, 400001, 500002, 700001, 800001] }, - { 100002, [200001, 300001, 400001, 500002, 700001, 800001] }, - { 100003, [200001, 400001, 600001] } + { 30001, [50001, 60001, 70002, 90001, 100001] }, + { 30002, [40001, 50001, 60001, 70002, 00001, 100001] }, + { 30003, [40001, 60001, 80001] } }; - //添加测试数据 - if (player.ItemContainer != null && player.ItemContainer.Items.Count < 1) - { - foreach (var configId in addItemConfigs) - { - player.ItemContainer.Add(configId, 1); - } + var itemContainer = player.GetComponent(); + + //添加测试数据 + if (itemContainer != null && itemContainer.FishingRig.Count < 1) + { foreach (var (rod, list) in rigDic) { - if (player.ItemContainer.GetFistItemByConfigId(rod, out var item) && item != null) + if (itemContainer.GetFistItemByConfigId(rod, out var item) && item != null) { var childs = new List(); foreach (var i in list) { - if (player.ItemContainer.GetFistItemByConfigId(i, out var itemChild) && itemChild != null) + if (itemContainer.GetFistItemByConfigId(i, out var itemChild) && itemChild != null) { childs.Add(itemChild.Id); } } - - player.ItemContainer.FishingRig[item.Id] = childs; + + itemContainer.FishingRig[item.Id] = childs; } } - // player.ItemContainer.FishingRig + itemContainer.Save(); } - // if(player.gr) + } #endregion diff --git a/Hotfix/Game/Player/Helper/PlayerFactory.cs b/Hotfix/Game/Player/Helper/PlayerFactory.cs index ab31c7d..bc1989f 100644 --- a/Hotfix/Game/Player/Helper/PlayerFactory.cs +++ b/Hotfix/Game/Player/Helper/PlayerFactory.cs @@ -17,6 +17,7 @@ public static class PlayerFactory public static Player Create(Scene scene, long aId) { var player = Entity.Create(scene, aId, true, true); + return player; } } \ No newline at end of file diff --git a/Hotfix/Game/Player/Helper/PlayerHelper.cs b/Hotfix/Game/Player/Helper/PlayerHelper.cs index c2e1e4c..eb296ae 100644 --- a/Hotfix/Game/Player/Helper/PlayerHelper.cs +++ b/Hotfix/Game/Player/Helper/PlayerHelper.cs @@ -8,15 +8,14 @@ namespace NB.Game; public static class PlayerHelper { - #region MyRegion - + #region 数据保存 + public static async FTask Save(this Player self) { //先立马保存,后续做缓存 await self.Scene.World.DataBase.Save(self); } - /// /// 从数据库中读取GameAccount /// @@ -32,12 +31,6 @@ public static class PlayerHelper } account.Deserialize(scene); - account.ItemContainer.Deserialize(scene); - foreach (var (_, item) in account.ItemContainer.Items) - { - item.Deserialize(scene); - } - return account; } @@ -50,6 +43,18 @@ public static class PlayerHelper { // 保存该账号信息到数据库中。 await Save(self); + var itemContainer = self.GetComponent(); + if (itemContainer != null) + { + await itemContainer.Save(); + } + + var wallet = self.GetComponent(); + if (wallet != null) + { + await wallet.Save(); + } + // 在缓存中移除自己,并且执行自己的Dispose方法。 self.Scene.GetComponent().Remove(self.Id); } @@ -119,7 +124,7 @@ public static class PlayerHelper Head = self.Head, Country = self.Country, Level = self.Level, - Vip = self.IsVip, + Vip = self.Vip, }; } @@ -127,7 +132,7 @@ public static class PlayerHelper { var info = new RoleInfo(); info.BaseInfo = GetRoleBaseInfo(self); - info.Items = self.ItemContainer.GetItemInfos(); + // info.Items = self.ItemContainer.GetItemInfos(); info.RoleId = self.RouteId; return info; } @@ -142,11 +147,12 @@ public static class PlayerHelper Level = self.Level, Exp = self.Exp, }; - if (self.IsVip) + if (self.Vip > 0) { ret.VipInfo = new VipInfo(); - // ret.VipInfo.OpenTime = self.Vip.GetTime; - // ret.VipInfo.ExpirationTime = self.Vip.ExpirationTime; + ret.VipInfo.Level = self.Vip; + ret.VipInfo.OpenTime = self.VipGetTime; + ret.VipInfo.ExpirationTime = self.VipExpirationTime; } return ret; diff --git a/Hotfix/Game/Wallet/PlayerWalletComponentSystem.cs b/Hotfix/Game/Wallet/PlayerWalletComponentSystem.cs new file mode 100644 index 0000000..de91049 --- /dev/null +++ b/Hotfix/Game/Wallet/PlayerWalletComponentSystem.cs @@ -0,0 +1,83 @@ +using Fantasy; +using Fantasy.Async; + +namespace NB.Game; + +public static class PlayerWalletComponentSystem +{ + #region Save + + public static async FTask Save(this PlayerWalletComponent self) + { + await self.Scene.World.DataBase.Save(self); + } + + #endregion + + + #region Add & Sub + + /// + /// 货币是否足够 + /// + /// + /// + /// + /// + public static bool Have(this PlayerWalletComponent self, uint configId, int count) + { + if (self.Currency.TryGetValue(configId, out var value)) + { + if (value >= Math.Abs(count)) + { + return true; + } + } + + return false; + } + + public static async FTask Add(this PlayerWalletComponent self, uint configId, int count) + { + if (count < 1) + { + Log.Error("Wallet Add Count Error "); + return; + } + + if (!self.Currency.TryAdd(configId, count)) + { + self.Currency[configId] += count; + } + + await self.Save(); + } + + public static async FTask Sub(this PlayerWalletComponent self, uint configId, int count) + { + if (count > 0) + { + Log.Error("Wallet Sub Count Error "); + return; + } + + if (self.Currency.TryGetValue(configId, out var value)) + { + if (value >= Math.Abs(count)) + { + self.Currency[configId] += count; + await self.Save(); + } + else + { + Log.Error("Wallet Sub Count Error Lower"); + } + } + else + { + Log.Error("Wallet Sub Count Error Not"); + } + } + + #endregion +} \ No newline at end of file diff --git a/Hotfix/Hotfix.csproj b/Hotfix/Hotfix.csproj index d51d67f..4be1cfc 100644 --- a/Hotfix/Hotfix.csproj +++ b/Hotfix/Hotfix.csproj @@ -14,6 +14,8 @@ + + diff --git a/Hotfix/OnCreateSceneEvent.cs b/Hotfix/OnCreateSceneEvent.cs index be79858..ff89e97 100644 --- a/Hotfix/OnCreateSceneEvent.cs +++ b/Hotfix/OnCreateSceneEvent.cs @@ -7,6 +7,7 @@ using Fantasy.Helper; using Fantasy.Serialize; using NB.Game; using NB.Map; +using NBF; using ProtoBuf; namespace NB; @@ -86,6 +87,8 @@ public sealed class OnCreateSceneEvent : AsyncEventSystem } case SceneType.Game: { + var rod = RodConfig.Get(30001); + Log.Info("rod config id="+rod.Id); // // Begins transaction // using (var session = mongoClient.StartSession()) // { diff --git a/Main/Fantasy.config b/Main/Fantasy.config new file mode 100644 index 0000000..20e6eb1 --- /dev/null +++ b/Main/Fantasy.config @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Main/Fantasy.xsd b/Main/Fantasy.xsd new file mode 100644 index 0000000..06b1ecf --- /dev/null +++ b/Main/Fantasy.xsd @@ -0,0 +1,302 @@ + + + + + + + Fantasy框架配置文件根元素 + + + + + + 配置表路径设置 + + + + + ID生成器配置 + + + + + 网络运行时配置 + + + + + 会话运行时配置 + + + + + 服务器配置 + + + + + + + + + + + 配置表文件路径 + + + + + + + + + ID生成器规则类型 + + + + + + 默认生成器,Scene最大为65535个 + + + + + ID中包含World,可解决合区ID重复问题,但Scene数量限制到255个 + + + + + + + + + + + + + 机器配置列表 + + + + + 进程配置列表 + + + + + 世界配置列表 + + + + + 场景配置列表 + + + + + + + + + + + + + + + + 机器ID + + + + + 外网IP地址 + + + + + 外网绑定IP地址 + + + + + 内网绑定IP地址 + + + + + + + + + + + + + + + 进程ID + + + + + 所属机器ID + + + + + 启动分组 + + + + + + + + + + + + + + + 世界ID + + + + + 世界名称 + + + + + 数据库连接字符串 + + + + + 数据库名称 + + + + + 数据库类型 + + + + + + + + + + + + + + + + + + + + + 场景ID + + + + + 进程配置ID + + + + + 世界配置ID + + + + + 场景运行模式 + + + + + + + + + + + + 场景类型字符串 + + + + + 网络协议类型 + + + + + + + + + + + + + + 外网端口 + + + + + 内网端口 + + + + + 场景类型数值 + + + + + + + + + 服务器内部网络协议 + + + + + + + + + + + 消息体最大长度(字节),默认1048560字节(约1.02MB) + + + + + + + + + Session idle check timeout (in milliseconds) + + + + + Session idle check interval (in milliseconds) + + + + + \ No newline at end of file diff --git a/Main/Main.csproj b/Main/Main.csproj index f088894..8bdb6b4 100644 --- a/Main/Main.csproj +++ b/Main/Main.csproj @@ -29,6 +29,9 @@ Always + + Always + diff --git a/Main/Program.cs b/Main/Program.cs index 846282c..82cfcb4 100644 --- a/Main/Program.cs +++ b/Main/Program.cs @@ -4,8 +4,8 @@ using Fantasy.Helper; using Fantasy.IdFactory; using Fantasy.Platform.Net; -// 设置配置表的路径 -ConfigTableHelper.Initialize("../../../Config/Binary"); + + // 设置ID生成规则 IdFactoryHelper.Initialize(IdFactoryType.World); // 获取配置文件 @@ -21,6 +21,10 @@ ProcessConfigData.Initialize(processConfigText); WorldConfigData.Initialize(worldConfigText); SceneConfigData.Initialize(sceneConfigText); +//解析配置文件 +var gameConfigText = await FileHelper.GetTextByRelativePath("../../../Config/Json/configs.Json"); +ConfigTableHelper.Initialize(gameConfigText,NB.AssemblyHelper.Assemblies); + // 注册日志模块到框架 // 开发者可以自己注册日志系统到框架,只要实现Fantasy.ILog接口就可以。 // 这里用的是NLog日志系统注册到框架中。 diff --git a/Main/Properties/launchSettings.json b/Main/Properties/launchSettings.json index c31a6c9..90a0233 100644 --- a/Main/Properties/launchSettings.json +++ b/Main/Properties/launchSettings.json @@ -3,7 +3,7 @@ "profiles": { "Main": { "commandName": "Project", -// "workingDirectory": "$(OutputPath)", + "workingDirectory": "$(OutputPath)", "environmentVariables": {}, "commandLineArgs": "--m Develop" } diff --git a/Server.sln.DotSettings b/Server.sln.DotSettings deleted file mode 100644 index 3d8771c..0000000 --- a/Server.sln.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - False \ No newline at end of file diff --git a/Server.sln.DotSettings.user b/Server.sln.DotSettings.user index de40ef4..077f693 100644 --- a/Server.sln.DotSettings.user +++ b/Server.sln.DotSettings.user @@ -7,6 +7,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -40,6 +41,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded diff --git a/Tools/ConfigBuilder/NBConfigBuilder/App.cs b/Tools/ConfigBuilder/NBConfigBuilder/App.cs index 2e3bb59..e824884 100644 --- a/Tools/ConfigBuilder/NBConfigBuilder/App.cs +++ b/Tools/ConfigBuilder/NBConfigBuilder/App.cs @@ -6,10 +6,8 @@ public class AppConfig public string ExcelPath { get; set; } public string ClientPath { get; set; } public string ClientJsonPath { get; set; } - public string ClientNamespace { get; set; } public string ServerPath { get; set; } public string ServerJsonPath { get; set; } - public string ServerNamespace { get; set; } public bool GenClient { get; set; } public bool GenServer { get; set; } diff --git a/Tools/ConfigBuilder/NBConfigBuilder/Exporter/ExcelExporter.cs b/Tools/ConfigBuilder/NBConfigBuilder/Exporter/ExcelExporter.cs index 9203adc..20031cb 100644 --- a/Tools/ConfigBuilder/NBConfigBuilder/Exporter/ExcelExporter.cs +++ b/Tools/ConfigBuilder/NBConfigBuilder/Exporter/ExcelExporter.cs @@ -635,12 +635,6 @@ public sealed class ExcelExporter var colInfos = isServer ? table.ServerColInfos : table.ClientColInfos; var exportPath = isServer ? App.Config.ServerPath : App.Config.ClientPath; - var csNamespace = isServer ? App.Config.ServerNamespace : App.Config.ClientNamespace; - if (string.IsNullOrEmpty(csNamespace)) - { - csNamespace = "NB"; - } - if (colInfos.Count <= 0) { return; @@ -720,7 +714,7 @@ public sealed class ExcelExporter } } - var template = ExcelTemplate.Template; + var template = GetTemplate(isServer); if (fileBuilder.Length > 0) { @@ -729,8 +723,7 @@ public sealed class ExcelExporter FileHelper.CreateDirectory(exportPath); } - var content = template.Replace("(namespace)", csNamespace) - .Replace("(ConfigName)", csName) + var content = template.Replace("(ConfigName)", csName) .Replace("(Fields)", fileBuilder.ToString()); File.WriteAllText(Path.Combine(exportPath, $"{csName}.cs"), content); } @@ -748,4 +741,10 @@ public sealed class ExcelExporter return index >= 0; } + + private string GetTemplate(bool isServer) + { + var fileName = isServer ? "TemplateServer.txt" : "TemplateClient.txt"; + return File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName)); + } } \ No newline at end of file diff --git a/Tools/ConfigBuilder/NBConfigBuilder/Exporter/ExcelTemplate.cs b/Tools/ConfigBuilder/NBConfigBuilder/Exporter/ExcelTemplate.cs deleted file mode 100644 index d12466e..0000000 --- a/Tools/ConfigBuilder/NBConfigBuilder/Exporter/ExcelTemplate.cs +++ /dev/null @@ -1,103 +0,0 @@ -namespace NBConfigBuilder; - -public static class ExcelTemplate -{ - public static readonly string Template = """ - using System; - using ProtoBuf; - using Fantasy; - using System.Linq; - using System.Reflection; - using System.Collections.Generic; - using System.Collections.Concurrent; - #if FANTASY_NET - using Fantasy.ConfigTable; - using Fantasy.Serialize; - #else - using NBC; - using NBC.Serialize; - #endif - // ReSharper disable CollectionNeverUpdated.Global - // ReSharper disable UnusedAutoPropertyAccessor.Global - #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - #pragma warning disable CS0169 - #pragma warning disable CS8618 - #pragma warning disable CS8625 - #pragma warning disable CS8603 - - namespace (namespace) - { - [ProtoContract] - public sealed partial class (ConfigName)Data : ASerialize, IConfigTable, IProto - { - [ProtoMember(1)] - public List<(ConfigName)> List { get; set; } = new List<(ConfigName)>(); - #if FANTASY_NET - [ProtoIgnore] - private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); - #else - [ProtoIgnore] - private readonly Dictionary _configs = new Dictionary(); - #endif - private static (ConfigName)Data _instance = null; - - public static (ConfigName)Data Instance - { - get { return _instance ??= ConfigTableHelper.Load<(ConfigName)Data>(); } - private set => _instance = value; - } - - public (ConfigName) Get(uint id, bool check = true) - { - if (_configs.ContainsKey(id)) - { - return _configs[id]; - } - - if (check) - { - throw new Exception($"(ConfigName) not find {id} Id"); - } - - return null; - } - public bool TryGet(uint id, out (ConfigName) config) - { - config = null; - - if (!_configs.ContainsKey(id)) - { - return false; - } - - config = _configs[id]; - return true; - } - public override void AfterDeserialization() - { - foreach (var config in List) - { - #if FANTASY_NET - _configs.TryAdd(config.Id, config); - #else - _configs.Add(config.Id, config); - #endif - config.AfterDeserialization(); - } - - EndInit(); - } - - public override void Dispose() - { - Instance = null; - } - } - - [ProtoContract] - public sealed partial class (ConfigName) : ASerialize, IProto - {(Fields) - } - } - """; -} \ No newline at end of file diff --git a/Tools/ConfigBuilder/NBConfigBuilder/Form1.Designer.cs b/Tools/ConfigBuilder/NBConfigBuilder/Form1.Designer.cs index 3723120..7fe6094 100644 --- a/Tools/ConfigBuilder/NBConfigBuilder/Form1.Designer.cs +++ b/Tools/ConfigBuilder/NBConfigBuilder/Form1.Designer.cs @@ -46,17 +46,13 @@ textBoxServerGenJsonPath = new TextBox(); label5 = new Label(); buttonSelectServerJsonPath = new Button(); - textBoxClientNamespce = new TextBox(); - textBoxServerNamespace = new TextBox(); - label6 = new Label(); - label7 = new Label(); SuspendLayout(); // // textBoxExcelPath // - textBoxExcelPath.Location = new Point(105, 13); + textBoxExcelPath.Location = new Point(81, 13); textBoxExcelPath.Name = "textBoxExcelPath"; - textBoxExcelPath.Size = new Size(301, 23); + textBoxExcelPath.Size = new Size(325, 23); textBoxExcelPath.TabIndex = 0; // // buttonSelectExcelPath @@ -80,9 +76,9 @@ // // textBoxClientGenPath // - textBoxClientGenPath.Location = new Point(105, 42); + textBoxClientGenPath.Location = new Point(81, 42); textBoxClientGenPath.Name = "textBoxClientGenPath"; - textBoxClientGenPath.Size = new Size(301, 23); + textBoxClientGenPath.Size = new Size(325, 23); textBoxClientGenPath.TabIndex = 3; // // buttonSelectClientPath @@ -100,7 +96,7 @@ checkBoxGenClient.AutoSize = true; checkBoxGenClient.Checked = true; checkBoxGenClient.CheckState = CheckState.Checked; - checkBoxGenClient.Location = new Point(412, 160); + checkBoxGenClient.Location = new Point(504, 13); checkBoxGenClient.Name = "checkBoxGenClient"; checkBoxGenClient.Size = new Size(87, 21); checkBoxGenClient.TabIndex = 5; @@ -118,9 +114,9 @@ // // textBoxServerGenPath // - textBoxServerGenPath.Location = new Point(105, 100); + textBoxServerGenPath.Location = new Point(81, 100); textBoxServerGenPath.Name = "textBoxServerGenPath"; - textBoxServerGenPath.Size = new Size(301, 23); + textBoxServerGenPath.Size = new Size(325, 23); textBoxServerGenPath.TabIndex = 7; // // label3 @@ -137,7 +133,7 @@ checkBoxGenServer.AutoSize = true; checkBoxGenServer.Checked = true; checkBoxGenServer.CheckState = CheckState.Checked; - checkBoxGenServer.Location = new Point(412, 189); + checkBoxGenServer.Location = new Point(504, 42); checkBoxGenServer.Name = "checkBoxGenServer"; checkBoxGenServer.Size = new Size(87, 21); checkBoxGenServer.TabIndex = 9; @@ -157,9 +153,9 @@ // // buttonRun // - buttonRun.Location = new Point(504, 13); + buttonRun.Location = new Point(504, 77); buttonRun.Name = "buttonRun"; - buttonRun.Size = new Size(82, 195); + buttonRun.Size = new Size(87, 77); buttonRun.TabIndex = 12; buttonRun.Text = "执行"; buttonRun.UseVisualStyleBackColor = true; @@ -167,9 +163,9 @@ // // textBoxClientGenJsonPath // - textBoxClientGenJsonPath.Location = new Point(105, 71); + textBoxClientGenJsonPath.Location = new Point(81, 71); textBoxClientGenJsonPath.Name = "textBoxClientGenJsonPath"; - textBoxClientGenJsonPath.Size = new Size(301, 23); + textBoxClientGenJsonPath.Size = new Size(325, 23); textBoxClientGenJsonPath.TabIndex = 13; // // label4 @@ -193,9 +189,9 @@ // // textBoxServerGenJsonPath // - textBoxServerGenJsonPath.Location = new Point(105, 131); + textBoxServerGenJsonPath.Location = new Point(81, 131); textBoxServerGenJsonPath.Name = "textBoxServerGenJsonPath"; - textBoxServerGenJsonPath.Size = new Size(301, 23); + textBoxServerGenJsonPath.Size = new Size(325, 23); textBoxServerGenJsonPath.TabIndex = 16; // // label5 @@ -217,47 +213,11 @@ buttonSelectServerJsonPath.UseVisualStyleBackColor = true; buttonSelectServerJsonPath.Click += buttonSelectServerJsonPath_Click; // - // textBoxClientNamespce - // - textBoxClientNamespce.Location = new Point(105, 160); - textBoxClientNamespce.Name = "textBoxClientNamespce"; - textBoxClientNamespce.Size = new Size(301, 23); - textBoxClientNamespce.TabIndex = 19; - // - // textBoxServerNamespace - // - textBoxServerNamespace.Location = new Point(105, 189); - textBoxServerNamespace.Name = "textBoxServerNamespace"; - textBoxServerNamespace.Size = new Size(301, 23); - textBoxServerNamespace.TabIndex = 20; - // - // label6 - // - label6.AutoSize = true; - label6.Location = new Point(7, 161); - label6.Name = "label6"; - label6.Size = new Size(92, 17); - label6.TabIndex = 21; - label6.Text = "客户端命名空间"; - // - // label7 - // - label7.AutoSize = true; - label7.Location = new Point(7, 192); - label7.Name = "label7"; - label7.Size = new Size(92, 17); - label7.TabIndex = 22; - label7.Text = "服务端命名空间"; - // // Form1 // AutoScaleDimensions = new SizeF(7F, 17F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(596, 216); - Controls.Add(label7); - Controls.Add(label6); - Controls.Add(textBoxServerNamespace); - Controls.Add(textBoxClientNamespce); + ClientSize = new Size(599, 165); Controls.Add(buttonSelectServerJsonPath); Controls.Add(label5); Controls.Add(textBoxServerGenJsonPath); @@ -302,9 +262,5 @@ private TextBox textBoxServerGenJsonPath; private Label label5; private Button buttonSelectServerJsonPath; - private TextBox textBoxClientNamespce; - private TextBox textBoxServerNamespace; - private Label label6; - private Label label7; } } diff --git a/Tools/ConfigBuilder/NBConfigBuilder/Form1.cs b/Tools/ConfigBuilder/NBConfigBuilder/Form1.cs index c485b96..4fd5750 100644 --- a/Tools/ConfigBuilder/NBConfigBuilder/Form1.cs +++ b/Tools/ConfigBuilder/NBConfigBuilder/Form1.cs @@ -149,9 +149,7 @@ namespace NBConfigBuilder ServerPath = textBoxServerGenPath.Text, ServerJsonPath = textBoxServerGenJsonPath.Text, GenClient = checkBoxGenClient.Checked, - GenServer = checkBoxGenServer.Checked, - ClientNamespace = textBoxClientNamespce.Text, - ServerNamespace = textBoxServerNamespace.Text + GenServer = checkBoxGenServer.Checked }; App.Config = config; try @@ -184,8 +182,6 @@ namespace NBConfigBuilder checkBoxGenServer.Checked = config.GenServer; textBoxClientGenJsonPath.Text = config.ClientJsonPath ?? ""; textBoxServerGenJsonPath.Text = config.ServerJsonPath ?? ""; - textBoxClientNamespce.Text = config.ClientNamespace ?? "NB"; - textBoxServerNamespace.Text = config.ServerNamespace ?? "NB"; } } catch (Exception ex) diff --git a/Tools/ConfigBuilder/NBConfigBuilder/Form1.resx b/Tools/ConfigBuilder/NBConfigBuilder/Form1.resx index af32865..8b2ff64 100644 --- a/Tools/ConfigBuilder/NBConfigBuilder/Form1.resx +++ b/Tools/ConfigBuilder/NBConfigBuilder/Form1.resx @@ -1,7 +1,7 @@  + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/NBConfigBuilder/NLog.dll b/Tools/NBConfigBuilder/NLog.dll new file mode 100644 index 0000000..1d15c30 Binary files /dev/null and b/Tools/NBConfigBuilder/NLog.dll differ diff --git a/Tools/NBConfigBuilder/Newtonsoft.Json.dll b/Tools/NBConfigBuilder/Newtonsoft.Json.dll new file mode 100644 index 0000000..5813d8c Binary files /dev/null and b/Tools/NBConfigBuilder/Newtonsoft.Json.dll differ diff --git a/Tools/ConfigTable/System.Collections.Immutable.dll b/Tools/NBConfigBuilder/System.Collections.Immutable.dll similarity index 100% rename from Tools/ConfigTable/System.Collections.Immutable.dll rename to Tools/NBConfigBuilder/System.Collections.Immutable.dll diff --git a/Tools/ConfigTable/System.Reflection.Metadata.dll b/Tools/NBConfigBuilder/System.Reflection.Metadata.dll similarity index 100% rename from Tools/ConfigTable/System.Reflection.Metadata.dll rename to Tools/NBConfigBuilder/System.Reflection.Metadata.dll diff --git a/Tools/NBConfigBuilder/System.Security.Cryptography.Pkcs.dll b/Tools/NBConfigBuilder/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..e521fd3 Binary files /dev/null and b/Tools/NBConfigBuilder/System.Security.Cryptography.Pkcs.dll differ diff --git a/Tools/NBConfigBuilder/System.Security.Cryptography.Xml.dll b/Tools/NBConfigBuilder/System.Security.Cryptography.Xml.dll new file mode 100644 index 0000000..1cb01ca Binary files /dev/null and b/Tools/NBConfigBuilder/System.Security.Cryptography.Xml.dll differ diff --git a/Tools/NBConfigBuilder/TemplateBack.txt b/Tools/NBConfigBuilder/TemplateBack.txt new file mode 100644 index 0000000..ebbd5d3 --- /dev/null +++ b/Tools/NBConfigBuilder/TemplateBack.txt @@ -0,0 +1,96 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +#if FANTASY_NET +using Fantasy.ConfigTable; +using Fantasy.Serialize; +#else +using NBC; +using NBC.Serialize; +#endif +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace (namespace) +{ + [ProtoContract] + public sealed partial class (ConfigName)Data : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List<(ConfigName)> List { get; set; } = new List<(ConfigName)>(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static (ConfigName)Data _instance = null; + + public static (ConfigName)Data Instance + { + get { return _instance ??= ConfigTableHelper.Load<(ConfigName)Data>(); } + private set => _instance = value; + } + + public (ConfigName) Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"(ConfigName) not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out (ConfigName) config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class (ConfigName) : ASerialize, IProto + {(Fields) + } +} \ No newline at end of file diff --git a/Tools/NBConfigBuilder/TemplateClient.txt b/Tools/NBConfigBuilder/TemplateClient.txt new file mode 100644 index 0000000..47a04cb --- /dev/null +++ b/Tools/NBConfigBuilder/TemplateClient.txt @@ -0,0 +1,79 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using NBC; +using NBC.Serialize; + +namespace NBF +{ + [ProtoContract] + public sealed partial class (ConfigName) : ASerialize, IProto, IConfigTable + { + (Fields) + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext<(ConfigName)> Context => ConfigTableHelper.Table<(ConfigName)>(); + + public static (ConfigName) Get(uint key) + { + return Context.Get(key); + } + + public static (ConfigName) Get(Predicate<(ConfigName)> match) + { + return Context.Get(match); + } + + public static (ConfigName) Fist() + { + return Context.Fist(); + } + + public static (ConfigName) Last() + { + return Context.Last(); + } + + public static (ConfigName) Fist(Predicate<(ConfigName)> match) + { + return Context.Fist(match); + } + + public static (ConfigName) Last(Predicate<(ConfigName)> match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func<(ConfigName), bool> predicate) + { + return Context.Count(predicate); + } + + public static List<(ConfigName)> GetList() + { + return Context.GetList(); + } + + public static List<(ConfigName)> GetList(Predicate<(ConfigName)> match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine<(ConfigName)>(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Tools/NBConfigBuilder/TemplateServer.txt b/Tools/NBConfigBuilder/TemplateServer.txt new file mode 100644 index 0000000..3a2823b --- /dev/null +++ b/Tools/NBConfigBuilder/TemplateServer.txt @@ -0,0 +1,79 @@ +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 (ConfigName) : ASerialize, IProto, IConfigTable + { + (Fields) + [ProtoIgnore] + public uint Key => Id; + + #region Static + + private static ConfigContext<(ConfigName)> Context => ConfigTableHelper.Table<(ConfigName)>(); + + public static (ConfigName) Get(uint key) + { + return Context.Get(key); + } + + public static (ConfigName) Get(Predicate<(ConfigName)> match) + { + return Context.Get(match); + } + + public static (ConfigName) Fist() + { + return Context.Fist(); + } + + public static (ConfigName) Last() + { + return Context.Last(); + } + + public static (ConfigName) Fist(Predicate<(ConfigName)> match) + { + return Context.Fist(match); + } + + public static (ConfigName) Last(Predicate<(ConfigName)> match) + { + return Context.Last(match); + } + + public static int Count() + { + return Context.Count(); + } + + public static int Count(Func<(ConfigName), bool> predicate) + { + return Context.Count(predicate); + } + + public static List<(ConfigName)> GetList() + { + return Context.GetList(); + } + + public static List<(ConfigName)> GetList(Predicate<(ConfigName)> match) + { + return Context.GetList(match); + } + public static void ParseJson(Newtonsoft.Json.Linq.JArray arr) + { + ConfigTableHelper.ParseLine<(ConfigName)>(arr); + } + #endregion + } +} \ No newline at end of file diff --git a/Tools/NBConfigBuilder/config.json b/Tools/NBConfigBuilder/config.json new file mode 100644 index 0000000..4891ac6 --- /dev/null +++ b/Tools/NBConfigBuilder/config.json @@ -0,0 +1,10 @@ +{ + "ExcelPath": "D:\\work\\Fishing2\\Config", + "ClientPath": "D:\\work\\Fishing2\\Assets\\Scripts\\Generate\\Config", + "ClientJsonPath": "D:\\work\\Fishing2\\Assets\\Resources\\config", + "ServerPath": "D:\\work\\Fishing2Server\\Entity\\Generate\\ConfigTable\\Entity", + "ServerJsonPath": "D:\\work\\Fishing2Server\\Config\\Json", + "GenClient": true, + "GenServer": true, + "ExcelVersionPath": "D:\\work\\Fishing2\\Config\\Version.txt" +} \ No newline at end of file diff --git a/Tools/NBConfigBuilder/cs/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/cs/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..67560d7 Binary files /dev/null and b/Tools/NBConfigBuilder/cs/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/cs/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/cs/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..155bcce Binary files /dev/null and b/Tools/NBConfigBuilder/cs/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/de/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/de/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..daca134 Binary files /dev/null and b/Tools/NBConfigBuilder/de/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/de/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/de/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..0613dde Binary files /dev/null and b/Tools/NBConfigBuilder/de/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/es/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/es/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..6528338 Binary files /dev/null and b/Tools/NBConfigBuilder/es/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/es/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/es/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..1d20ff2 Binary files /dev/null and b/Tools/NBConfigBuilder/es/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/fr/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/fr/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..d5d4b24 Binary files /dev/null and b/Tools/NBConfigBuilder/fr/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/fr/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/fr/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..e7aee2a Binary files /dev/null and b/Tools/NBConfigBuilder/fr/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/it/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/it/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..57a91a7 Binary files /dev/null and b/Tools/NBConfigBuilder/it/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/it/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/it/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..78cb09d Binary files /dev/null and b/Tools/NBConfigBuilder/it/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/ja/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/ja/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..a301df0 Binary files /dev/null and b/Tools/NBConfigBuilder/ja/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/ja/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/ja/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..77a390c Binary files /dev/null and b/Tools/NBConfigBuilder/ja/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/ko/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/ko/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..5108385 Binary files /dev/null and b/Tools/NBConfigBuilder/ko/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/ko/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/ko/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..3c56215 Binary files /dev/null and b/Tools/NBConfigBuilder/ko/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/pl/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/pl/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..965c984 Binary files /dev/null and b/Tools/NBConfigBuilder/pl/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/pl/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/pl/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..2915250 Binary files /dev/null and b/Tools/NBConfigBuilder/pl/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/protobuf-net.Core.dll b/Tools/NBConfigBuilder/protobuf-net.Core.dll new file mode 100644 index 0000000..00b3bfe Binary files /dev/null and b/Tools/NBConfigBuilder/protobuf-net.Core.dll differ diff --git a/Tools/ConfigTable/protobuf-net.dll b/Tools/NBConfigBuilder/protobuf-net.dll similarity index 74% rename from Tools/ConfigTable/protobuf-net.dll rename to Tools/NBConfigBuilder/protobuf-net.dll index cf08aaa..f29616e 100644 Binary files a/Tools/ConfigTable/protobuf-net.dll and b/Tools/NBConfigBuilder/protobuf-net.dll differ diff --git a/Tools/NBConfigBuilder/pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..5afc260 Binary files /dev/null and b/Tools/NBConfigBuilder/pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/pt-BR/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/pt-BR/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..700e2aa Binary files /dev/null and b/Tools/NBConfigBuilder/pt-BR/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/ru/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/ru/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..b4138f4 Binary files /dev/null and b/Tools/NBConfigBuilder/ru/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/ru/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/ru/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..2cf63e5 Binary files /dev/null and b/Tools/NBConfigBuilder/ru/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/ConfigTable/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll b/Tools/NBConfigBuilder/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll similarity index 100% rename from Tools/ConfigTable/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll rename to Tools/NBConfigBuilder/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll diff --git a/Tools/NBConfigBuilder/tr/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/tr/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..7ca2e8f Binary files /dev/null and b/Tools/NBConfigBuilder/tr/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/tr/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/tr/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..0f76b86 Binary files /dev/null and b/Tools/NBConfigBuilder/tr/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..8c80a88 Binary files /dev/null and b/Tools/NBConfigBuilder/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/zh-Hans/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/zh-Hans/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..52f232d Binary files /dev/null and b/Tools/NBConfigBuilder/zh-Hans/Microsoft.CodeAnalysis.resources.dll differ diff --git a/Tools/NBConfigBuilder/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll b/Tools/NBConfigBuilder/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll new file mode 100644 index 0000000..1936f8d Binary files /dev/null and b/Tools/NBConfigBuilder/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll differ diff --git a/Tools/NBConfigBuilder/zh-Hant/Microsoft.CodeAnalysis.resources.dll b/Tools/NBConfigBuilder/zh-Hant/Microsoft.CodeAnalysis.resources.dll new file mode 100644 index 0000000..fe815c6 Binary files /dev/null and b/Tools/NBConfigBuilder/zh-Hant/Microsoft.CodeAnalysis.resources.dll differ