配置表接入和升级服务器框架到最新版

This commit is contained in:
2025-10-10 17:57:01 +08:00
parent 520d4f37bd
commit 8a302754d6
250 changed files with 6356 additions and 4135 deletions

Binary file not shown.

Binary file not shown.

433
Config/Json/configs.json Normal file
View File

@@ -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"
]
}
]
}

View File

@@ -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; //变化钓组信息
}
////////////// ******** 鱼护 *******/////////////

View File

@@ -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; //到期时间
}

View File

@@ -29,6 +29,9 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Game\Shop\" />
<Folder Include="Generate\ConfigTable\Entity\" />
<Folder Include="Generate\ConfigTable\Partial\" />
<Folder Include="Social\Entity\" />
<Folder Include="Social\Mail\" />
</ItemGroup>

View File

@@ -29,7 +29,7 @@ public class PlayerBasicCache : Entity
/// <summary>
/// 是否是vip
/// </summary>
public bool IsVip;
public int Vip;
/// <summary>
/// 缓存失效时间

View File

@@ -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
/// <summary>
/// 配置id
/// </summary>
[BsonElement("cid")] public int ConfigId;
[BsonElement("cid")] public uint ConfigId;
/// <summary>
/// 是否绑定
@@ -46,5 +46,5 @@ public class Item : Entity
/// <summary>
/// 物品所属的容器
/// </summary>
[BsonIgnore] PlayerItemContainer Container;
[BsonIgnore] PlayerItemContainerComponent Container;
}

View File

@@ -6,7 +6,7 @@ using NB.Game;
namespace NB;
public sealed class PlayerItemContainer : Entity
public sealed class PlayerItemContainerComponent : Entity
{
/// <summary>
/// 最大格子数量
@@ -24,14 +24,4 @@ public sealed class PlayerItemContainer : Entity
/// </summary>
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<long, List<long>> FishingRig = new Dictionary<long, List<long>>();
// /// <summary>
// /// 按物品id分组
// /// </summary>
// [BsonIgnore] public readonly OneToManyList<int, Item> ItemsByConfigId = new OneToManyListPool<int, Item>();
//
// /// <summary>
// /// 容器内按物品类型分组
// /// </summary>
// [BsonIgnore] public readonly OneToManyList<uint, Item> ItemsByType = new OneToManyListPool<uint, Item>();
}

View File

@@ -34,7 +34,7 @@ public sealed class Player : Entity
/// 当前经验
/// </summary>
[BsonElement("exp")] public int Exp;
/// <summary>
/// 星数
@@ -47,41 +47,20 @@ public sealed class Player : Entity
[BsonElement("high")] public int Highlight;
/// <summary>
/// 角色vip信息
/// vip状态
/// </summary>
[BsonElement("vInfo")] public PlayerVip Vip;
[BsonElement("vip")] public int Vip;
/// <summary>
/// 钱包
/// 获取时间
/// </summary>
[BsonElement("wallet")] public PlayerWallet Wallet;
[BsonElement("vTime")] public long VipGetTime;
/// <summary>
/// 背包
/// 失效时间
/// </summary>
[BsonElement("bag")] public PlayerItemContainer ItemContainer;
[BsonElement("vExTime")] public long VipExpirationTime;
/// <summary>
/// 鱼护
/// </summary>
[BsonElement("fish")] public FishContainer FishContainer;
/// <summary>
/// 技能
/// </summary>
[BsonElement("skill")] public SkillContainer SkillContainer;
/// <summary>
/// 成就
/// </summary>
[BsonElement("achievement")] public AchievementContainer AchievementContainer;
/// <summary>
/// 是否是vip
/// </summary>
[BsonIgnore]
public bool IsVip => Vip != null && Vip.ExpirationTime > TimeHelper.Now;
[BsonIgnore] public long SessionRunTimeId;
}

View File

@@ -7,21 +7,11 @@ namespace NB.Game;
/// <summary>
/// 用户钱包
/// </summary>
public class PlayerWallet : Entity
public class PlayerWalletComponent : Entity
{
/// <summary>
/// 余额
/// </summary>
public int Money;
/// <summary>
/// 金币
/// </summary>
public int Gold;
/// <summary>
/// 其他货币
/// 所有货币
/// </summary>
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<int, int> Other = new();
public Dictionary<uint, int> Currency = new();
}

View File

@@ -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<BaitConfig> List { get; set; } = new List<BaitConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, BaitConfig> _configs = new ConcurrentDictionary<uint, BaitConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, BaitConfig> _configs = new Dictionary<uint, BaitConfig>();
#endif
private static BaitConfigData _instance = null;
public static BaitConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<BaitConfigData>(); }
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; } // 重量(克)
}
}
public uint Weight { get; set; } // 重量(克)
[ProtoMember(6)]
public uint[] Arr { get; set; } = Array.Empty<uint>(); // 重量(克)
[ProtoMember(7)]
public string[] ArrStr { get; set; } = Array.Empty<string>(); // 重量(克)
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<BaitConfig> Context => ConfigTableHelper.Table<BaitConfig>();
public static BaitConfig Get(uint key)
{
return Context.Get(key);
}
public static BaitConfig Get(Predicate<BaitConfig> match)
{
return Context.Get(match);
}
public static BaitConfig Fist()
{
return Context.Fist();
}
public static BaitConfig Last()
{
return Context.Last();
}
public static BaitConfig Fist(Predicate<BaitConfig> match)
{
return Context.Fist(match);
}
public static BaitConfig Last(Predicate<BaitConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<BaitConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<BaitConfig> GetList()
{
return Context.GetList();
}
public static List<BaitConfig> GetList(Predicate<BaitConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<BaitConfig>(arr);
}
#endregion
}
}

View File

@@ -0,0 +1,85 @@
using System;
using ProtoBuf;
using Fantasy;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Fantasy.Serialize;
using Fantasy.ConfigTable;
namespace NBF
{
[ProtoContract]
public sealed partial class 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<string>(); // 参数值
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<BasicConfig> Context => ConfigTableHelper.Table<BasicConfig>();
public static BasicConfig Get(uint key)
{
return Context.Get(key);
}
public static BasicConfig Get(Predicate<BasicConfig> match)
{
return Context.Get(match);
}
public static BasicConfig Fist()
{
return Context.Fist();
}
public static BasicConfig Last()
{
return Context.Last();
}
public static BasicConfig Fist(Predicate<BasicConfig> match)
{
return Context.Fist(match);
}
public static BasicConfig Last(Predicate<BasicConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<BasicConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<BasicConfig> GetList()
{
return Context.GetList();
}
public static List<BasicConfig> GetList(Predicate<BasicConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<BasicConfig>(arr);
}
#endregion
}
}

View File

@@ -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<BobberConfig> List { get; set; } = new List<BobberConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, BobberConfig> _configs = new ConcurrentDictionary<uint, BobberConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, BobberConfig> _configs = new Dictionary<uint, BobberConfig>();
#endif
private static BobberConfigData _instance = null;
public static BobberConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<BobberConfigData>(); }
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; } // 是否夜光
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<BobberConfig> Context => ConfigTableHelper.Table<BobberConfig>();
public static BobberConfig Get(uint key)
{
return Context.Get(key);
}
public static BobberConfig Get(Predicate<BobberConfig> match)
{
return Context.Get(match);
}
public static BobberConfig Fist()
{
return Context.Fist();
}
public static BobberConfig Last()
{
return Context.Last();
}
public static BobberConfig Fist(Predicate<BobberConfig> match)
{
return Context.Fist(match);
}
public static BobberConfig Last(Predicate<BobberConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<BobberConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<BobberConfig> GetList()
{
return Context.GetList();
}
public static List<BobberConfig> GetList(Predicate<BobberConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<BobberConfig>(arr);
}
#endregion
}
}

View File

@@ -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<FeederConfig> List { get; set; } = new List<FeederConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, FeederConfig> _configs = new ConcurrentDictionary<uint, FeederConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, FeederConfig> _configs = new Dictionary<uint, FeederConfig>();
#endif
private static FeederConfigData _instance = null;
public static FeederConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<FeederConfigData>(); }
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; } // 重量(克)
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<FeederConfig> Context => ConfigTableHelper.Table<FeederConfig>();
public static FeederConfig Get(uint key)
{
return Context.Get(key);
}
public static FeederConfig Get(Predicate<FeederConfig> match)
{
return Context.Get(match);
}
public static FeederConfig Fist()
{
return Context.Fist();
}
public static FeederConfig Last()
{
return Context.Last();
}
public static FeederConfig Fist(Predicate<FeederConfig> match)
{
return Context.Fist(match);
}
public static FeederConfig Last(Predicate<FeederConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<FeederConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<FeederConfig> GetList()
{
return Context.GetList();
}
public static List<FeederConfig> GetList(Predicate<FeederConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<FeederConfig>(arr);
}
#endregion
}
}

View File

@@ -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<FishConfig> List { get; set; } = new List<FishConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, FishConfig> _configs = new ConcurrentDictionary<uint, FishConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, FishConfig> _configs = new Dictionary<uint, FishConfig>();
#endif
private static FishConfigData _instance = null;
public static FishConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<FishConfigData>(); }
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; } // 接受饵
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<FishConfig> Context => ConfigTableHelper.Table<FishConfig>();
public static FishConfig Get(uint key)
{
return Context.Get(key);
}
public static FishConfig Get(Predicate<FishConfig> match)
{
return Context.Get(match);
}
public static FishConfig Fist()
{
return Context.Fist();
}
public static FishConfig Last()
{
return Context.Last();
}
public static FishConfig Fist(Predicate<FishConfig> match)
{
return Context.Fist(match);
}
public static FishConfig Last(Predicate<FishConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<FishConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<FishConfig> GetList()
{
return Context.GetList();
}
public static List<FishConfig> GetList(Predicate<FishConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<FishConfig>(arr);
}
#endregion
}
}

View File

@@ -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<HookConfig> List { get; set; } = new List<HookConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, HookConfig> _configs = new ConcurrentDictionary<uint, HookConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, HookConfig> _configs = new Dictionary<uint, HookConfig>();
#endif
private static HookConfigData _instance = null;
public static HookConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<HookConfigData>(); }
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; } // 重量(克)
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<HookConfig> Context => ConfigTableHelper.Table<HookConfig>();
public static HookConfig Get(uint key)
{
return Context.Get(key);
}
public static HookConfig Get(Predicate<HookConfig> match)
{
return Context.Get(match);
}
public static HookConfig Fist()
{
return Context.Fist();
}
public static HookConfig Last()
{
return Context.Last();
}
public static HookConfig Fist(Predicate<HookConfig> match)
{
return Context.Fist(match);
}
public static HookConfig Last(Predicate<HookConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<HookConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<HookConfig> GetList()
{
return Context.GetList();
}
public static List<HookConfig> GetList(Predicate<HookConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<HookConfig>(arr);
}
#endregion
}
}

View File

@@ -0,0 +1,85 @@
using System;
using ProtoBuf;
using Fantasy;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Fantasy.Serialize;
using Fantasy.ConfigTable;
namespace NBF
{
[ProtoContract]
public sealed partial class 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<InitConfig> Context => ConfigTableHelper.Table<InitConfig>();
public static InitConfig Get(uint key)
{
return Context.Get(key);
}
public static InitConfig Get(Predicate<InitConfig> match)
{
return Context.Get(match);
}
public static InitConfig Fist()
{
return Context.Fist();
}
public static InitConfig Last()
{
return Context.Last();
}
public static InitConfig Fist(Predicate<InitConfig> match)
{
return Context.Fist(match);
}
public static InitConfig Last(Predicate<InitConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<InitConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<InitConfig> GetList()
{
return Context.GetList();
}
public static List<InitConfig> GetList(Predicate<InitConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<InitConfig>(arr);
}
#endregion
}
}

View File

@@ -0,0 +1,89 @@
using System;
using ProtoBuf;
using Fantasy;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Fantasy.Serialize;
using Fantasy.ConfigTable;
namespace NBF
{
[ProtoContract]
public sealed partial class 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<ItemConfig> Context => ConfigTableHelper.Table<ItemConfig>();
public static ItemConfig Get(uint key)
{
return Context.Get(key);
}
public static ItemConfig Get(Predicate<ItemConfig> match)
{
return Context.Get(match);
}
public static ItemConfig Fist()
{
return Context.Fist();
}
public static ItemConfig Last()
{
return Context.Last();
}
public static ItemConfig Fist(Predicate<ItemConfig> match)
{
return Context.Fist(match);
}
public static ItemConfig Last(Predicate<ItemConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<ItemConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<ItemConfig> GetList()
{
return Context.GetList();
}
public static List<ItemConfig> GetList(Predicate<ItemConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<ItemConfig>(arr);
}
#endregion
}
}

View File

@@ -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<LineConfig> List { get; set; } = new List<LineConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, LineConfig> _configs = new ConcurrentDictionary<uint, LineConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, LineConfig> _configs = new Dictionary<uint, LineConfig>();
#endif
private static LineConfigData _instance = null;
public static LineConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<LineConfigData>(); }
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; } // 尺寸
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<LineConfig> Context => ConfigTableHelper.Table<LineConfig>();
public static LineConfig Get(uint key)
{
return Context.Get(key);
}
public static LineConfig Get(Predicate<LineConfig> match)
{
return Context.Get(match);
}
public static LineConfig Fist()
{
return Context.Fist();
}
public static LineConfig Last()
{
return Context.Last();
}
public static LineConfig Fist(Predicate<LineConfig> match)
{
return Context.Fist(match);
}
public static LineConfig Last(Predicate<LineConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<LineConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<LineConfig> GetList()
{
return Context.GetList();
}
public static List<LineConfig> GetList(Predicate<LineConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<LineConfig>(arr);
}
#endregion
}
}

View File

@@ -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<LureConfig> List { get; set; } = new List<LureConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, LureConfig> _configs = new ConcurrentDictionary<uint, LureConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, LureConfig> _configs = new Dictionary<uint, LureConfig>();
#endif
private static LureConfigData _instance = null;
public static LureConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<LureConfigData>(); }
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; } // 重量(克)
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<LureConfig> Context => ConfigTableHelper.Table<LureConfig>();
public static LureConfig Get(uint key)
{
return Context.Get(key);
}
public static LureConfig Get(Predicate<LureConfig> match)
{
return Context.Get(match);
}
public static LureConfig Fist()
{
return Context.Fist();
}
public static LureConfig Last()
{
return Context.Last();
}
public static LureConfig Fist(Predicate<LureConfig> match)
{
return Context.Fist(match);
}
public static LureConfig Last(Predicate<LureConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<LureConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<LureConfig> GetList()
{
return Context.GetList();
}
public static List<LureConfig> GetList(Predicate<LureConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<LureConfig>(arr);
}
#endregion
}
}

View File

@@ -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<ReelConfig> List { get; set; } = new List<ReelConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, ReelConfig> _configs = new ConcurrentDictionary<uint, ReelConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, ReelConfig> _configs = new Dictionary<uint, ReelConfig>();
#endif
private static ReelConfigData _instance = null;
public static ReelConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<ReelConfigData>(); }
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; } // 强度
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<ReelConfig> Context => ConfigTableHelper.Table<ReelConfig>();
public static ReelConfig Get(uint key)
{
return Context.Get(key);
}
public static ReelConfig Get(Predicate<ReelConfig> match)
{
return Context.Get(match);
}
public static ReelConfig Fist()
{
return Context.Fist();
}
public static ReelConfig Last()
{
return Context.Last();
}
public static ReelConfig Fist(Predicate<ReelConfig> match)
{
return Context.Fist(match);
}
public static ReelConfig Last(Predicate<ReelConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<ReelConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<ReelConfig> GetList()
{
return Context.GetList();
}
public static List<ReelConfig> GetList(Predicate<ReelConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<ReelConfig>(arr);
}
#endregion
}
}

View File

@@ -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<RingConfig> List { get; set; } = new List<RingConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, RingConfig> _configs = new ConcurrentDictionary<uint, RingConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, RingConfig> _configs = new Dictionary<uint, RingConfig>();
#endif
private static RingConfigData _instance = null;
public static RingConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<RingConfigData>(); }
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; } // 模型
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<RingConfig> Context => ConfigTableHelper.Table<RingConfig>();
public static RingConfig Get(uint key)
{
return Context.Get(key);
}
public static RingConfig Get(Predicate<RingConfig> match)
{
return Context.Get(match);
}
public static RingConfig Fist()
{
return Context.Fist();
}
public static RingConfig Last()
{
return Context.Last();
}
public static RingConfig Fist(Predicate<RingConfig> match)
{
return Context.Fist(match);
}
public static RingConfig Last(Predicate<RingConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<RingConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<RingConfig> GetList()
{
return Context.GetList();
}
public static List<RingConfig> GetList(Predicate<RingConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<RingConfig>(arr);
}
#endregion
}
}

View File

@@ -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<RodConfig> List { get; set; } = new List<RodConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, RodConfig> _configs = new ConcurrentDictionary<uint, RodConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, RodConfig> _configs = new Dictionary<uint, RodConfig>();
#endif
private static RodConfigData _instance = null;
public static RodConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<RodConfigData>(); }
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; } // 结构类型
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<RodConfig> Context => ConfigTableHelper.Table<RodConfig>();
public static RodConfig Get(uint key)
{
return Context.Get(key);
}
public static RodConfig Get(Predicate<RodConfig> match)
{
return Context.Get(match);
}
public static RodConfig Fist()
{
return Context.Fist();
}
public static RodConfig Last()
{
return Context.Last();
}
public static RodConfig Fist(Predicate<RodConfig> match)
{
return Context.Fist(match);
}
public static RodConfig Last(Predicate<RodConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<RodConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<RodConfig> GetList()
{
return Context.GetList();
}
public static List<RodConfig> GetList(Predicate<RodConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<RodConfig>(arr);
}
#endregion
}
}

View File

@@ -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<UnitConfig> List { get; set; } = new List<UnitConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, UnitConfig> _configs = new ConcurrentDictionary<uint, UnitConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, UnitConfig> _configs = new Dictionary<uint, UnitConfig>();
#endif
private static UnitConfigData _instance = null;
public static UnitConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<UnitConfigData>(); }
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; } // 字典类型
}
}

View File

@@ -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<WeightConfig> List { get; set; } = new List<WeightConfig>();
#if FANTASY_NET
[ProtoIgnore]
private readonly ConcurrentDictionary<uint, WeightConfig> _configs = new ConcurrentDictionary<uint, WeightConfig>();
#else
[ProtoIgnore]
private readonly Dictionary<uint, WeightConfig> _configs = new Dictionary<uint, WeightConfig>();
#endif
private static WeightConfigData _instance = null;
public static WeightConfigData Instance
{
get { return _instance ??= ConfigTableHelper.Load<WeightConfigData>(); }
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; } // 重量(克)
}
}
[ProtoIgnore]
public uint Key => Id;
#region Static
private static ConfigContext<WeightConfig> Context => ConfigTableHelper.Table<WeightConfig>();
public static WeightConfig Get(uint key)
{
return Context.Get(key);
}
public static WeightConfig Get(Predicate<WeightConfig> match)
{
return Context.Get(match);
}
public static WeightConfig Fist()
{
return Context.Fist();
}
public static WeightConfig Last()
{
return Context.Last();
}
public static WeightConfig Fist(Predicate<WeightConfig> match)
{
return Context.Fist(match);
}
public static WeightConfig Last(Predicate<WeightConfig> match)
{
return Context.Last(match);
}
public static int Count()
{
return Context.Count();
}
public static int Count(Func<WeightConfig, bool> predicate)
{
return Context.Count(predicate);
}
public static List<WeightConfig> GetList()
{
return Context.GetList();
}
public static List<WeightConfig> GetList(Predicate<WeightConfig> match)
{
return Context.GetList(match);
}
public static void ParseJson(Newtonsoft.Json.Linq.JArray arr)
{
ConfigTableHelper.ParseLine<WeightConfig>(arr);
}
#endregion
}
}

View File

@@ -1,10 +0,0 @@
namespace Fantasy;
public sealed partial class UnitConfigData
{
public override void EndInit()
{
Log.Debug("UnitConfigData EndInit");
base.EndInit();
}
}

View File

@@ -34,7 +34,6 @@ namespace Fantasy
Country = default;
Level = default;
Exp = default;
Vip = default;
VipInfo = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<RoleBaseInfo>(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; }
}
/// <summary>

View File

@@ -40,15 +40,10 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
<PackageReference Include="mimalloc-csharp" Version="1.0.7" />
<PackageReference Include="MongoDB.Bson" Version="3.1.0" />
<PackageReference Include="MongoDB.Driver" Version="3.1.0" />
<PackageReference Include="MongoDB.Bson" Version="3.4.3" />
<PackageReference Include="MongoDB.Driver" Version="3.4.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="protobuf-net" Version="3.2.45" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="System.IO.Pipelines" Version="9.0.0" />
<PackageReference Include="protobuf-net" Version="3.2.56" />
</ItemGroup>
<ItemGroup>
@@ -58,4 +53,8 @@
<None Include="README.md" Pack="true" PackagePath="\"/>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="System.IO.Pipelines" Version="9.0.8" />
</ItemGroup>
</Project>

View File

@@ -92,11 +92,6 @@ namespace Fantasy.DataBase
return data == null ? 0 : Convert.ToInt64(data["Result"]);
}
/// <summary>
/// Mongo 注释
/// </summary>
public MongoClient Client => _mongoClient;
#endregion
#region GetCollection

View File

@@ -82,7 +82,7 @@ namespace Fantasy.Async
/// </summary>
/// <param name="coroutineLockType"></param>
/// <param name="coroutineLockQueueKey"></param>
public void Release(int coroutineLockType, long coroutineLockQueueKey)
public void Release(long coroutineLockType, long coroutineLockQueueKey)
{
if (IsDisposed)
{

View File

@@ -67,11 +67,15 @@ namespace Fantasy.Entitas
return HashCode.Combine(CustomEventType, EntitiesType);
}
}
/// <summary>
/// Entity管理组件
/// </summary>
#if FANTASY_UNITY
public sealed class EntityComponent : Entity, ISceneUpdate, ISceneLateUpdate, IAssembly
#else
public sealed class EntityComponent : Entity, ISceneUpdate, IAssembly
#endif
{
private readonly OneToManyList<long, Type> _assemblyList = new();
private readonly OneToManyList<long, Type> _assemblyHashCodes = new();
@@ -80,15 +84,19 @@ namespace Fantasy.Entitas
private readonly Dictionary<Type, IUpdateSystem> _updateSystems = new();
private readonly Dictionary<Type, IDestroySystem> _destroySystems = new();
private readonly Dictionary<Type, IDeserializeSystem> _deserializeSystems = new();
private readonly Dictionary<Type, IFrameUpdateSystem> _frameUpdateSystem = new();
private readonly OneToManyList<long, CustomEntitiesSystemKey> _assemblyCustomSystemList = new();
private readonly Dictionary<CustomEntitiesSystemKey, ICustomEntitiesSystem> _customEntitiesSystems = new Dictionary<CustomEntitiesSystemKey, ICustomEntitiesSystem>();
private readonly Dictionary<Type, long> _hashCodes = new Dictionary<Type, long>();
private readonly Queue<UpdateQueueInfo> _updateQueue = new Queue<UpdateQueueInfo>();
private readonly Queue<FrameUpdateQueueInfo> _frameUpdateQueue = new Queue<FrameUpdateQueueInfo>();
private readonly Dictionary<long, UpdateQueueInfo> _updateQueueDic = new Dictionary<long, UpdateQueueInfo>();
#if FANTASY_UNITY
private readonly Dictionary<Type, ILateUpdateSystem> _lateUpdateSystems = new();
private readonly Queue<UpdateQueueInfo> _lateUpdateQueue = new Queue<UpdateQueueInfo>();
private readonly Dictionary<long, UpdateQueueInfo> _lateUpdateQueueDic = new Dictionary<long, UpdateQueueInfo>();
#endif
internal async FTask<EntityComponent> Initialize()
{
@@ -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
/// <summary>
/// 将实体加入更新队列,准备进行更新
/// 将实体加入Update队列,准备进行Update
/// </summary>
/// <param name="entity">实体对象</param>
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);
}
/// <summary>
/// 停止实体进行更新
/// 停止实体Update
/// </summary>
/// <param name="entity">实体对象</param>
public void StopUpdate(Entity entity)
@@ -369,7 +374,7 @@ namespace Fantasy.Entitas
}
/// <summary>
/// 执行实体系统的更新逻辑
/// 执行实体系统的Update
/// </summary>
public void Update()
{
@@ -410,44 +415,84 @@ namespace Fantasy.Entitas
}
}
/// <summary>
/// 执行实体系统的帧更新逻辑
/// </summary>
public void FrameUpdate()
{
var count = _frameUpdateQueue.Count;
#endregion
while (count-- > 0)
#if FANTASY_UNITY
#region LateUpdate
/// <summary>
/// 将实体加入LateUpdate队列准备进行LateUpdate
/// </summary>
/// <param name="entity">实体对象</param>
public void StartLateUpdate(Entity entity)
{
var type = entity.Type;
var entityRuntimeId = entity.RuntimeId;
if (!_lateUpdateSystems.ContainsKey(type))
{
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);
}
/// <summary>
/// 停止实体进行LateUpdate
/// </summary>
/// <param name="entity">实体对象</param>
public void StopLateUpdate(Entity entity)
{
if (!_lateUpdateQueueDic.Remove(entity.RuntimeId, out var updateQueueInfo))
{
return;
}
updateQueueInfo.IsStop = true;
}
public void LateUpdate()
{
var lateUpdateQueue = _lateUpdateQueue.Count;
while (lateUpdateQueue-- > 0)
{
var lateUpdateQueueStruct = _lateUpdateQueue.Dequeue();
if (lateUpdateQueueStruct.IsStop)
{
continue;
}
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();

View File

@@ -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;
}

View File

@@ -1,31 +1,36 @@
#if FANTASY_UNITY
using System;
namespace Fantasy.Entitas.Interface
{
internal interface IFrameUpdateSystem : IEntitiesSystem { }
internal interface ILateUpdateSystem : IEntitiesSystem { }
/// <summary>
/// 帧更新时间的抽象接口
/// 实体的LateUpdate事件的抽象接口
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class FrameUpdateSystem<T> : IFrameUpdateSystem where T : Entity
/// <typeparam name="T">实体的泛型类型</typeparam>
public abstract class LateUpdateSystem<T> : ILateUpdateSystem where T : Entity
{
/// <summary>
/// 实体的类型
/// </summary>
/// <returns></returns>
public Type EntitiesType() => typeof(T);
/// <summary>
/// 事件的抽象方法,需要自己实现这个方法
/// </summary>
/// <param name="self">触发事件的实体实例</param>
protected abstract void FrameUpdate(T self);
protected abstract void LateUpdate(T self);
/// <summary>
/// 框架内部调用的触发FrameUpdate的方法
/// 框架内部调用的触发Awake的方法
/// </summary>
/// <param name="self"></param>
/// <param name="self">触发事件的实体实例</param>
public void Invoke(Entity self)
{
FrameUpdate((T) self);
LateUpdate((T)self);
}
}
}
}
#endif

View File

@@ -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);
}
/// <summary>
@@ -57,7 +57,7 @@ namespace Fantasy.Helper
{
var md5 = MD5.Create();
bytes = md5.ComputeHash(bytes);
return bytes.ToHex("x2");
return bytes.ToHex(false);
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
@@ -17,7 +18,7 @@ namespace Fantasy.Helper
/// <returns>完整路径。</returns>
public static string GetFullPath(string relativePath)
{
return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath));
return Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, relativePath));
}
/// <summary>

View File

@@ -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
/// </summary>
public static partial class HashCodeHelper
{
private static readonly SHA256 Sha256Hash = SHA256.Create();
/// <summary>
/// 计算两个字符串的HashCode
/// </summary>
@@ -24,112 +23,7 @@ namespace Fantasy.Helper
hash = hash * 31 + b.GetHashCode();
return hash;
}
#if FANTASY_NET || !FANTASY_WEBGL
/// <summary>
/// 使用bkdr算法生成一个long的值
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 使用MurmurHash3算法生成一个uint的值
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 使用MurmurHash3算法生成一个long的值
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
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
/// <summary>
/// 使用bkdr算法生成一个long的值
/// </summary>
@@ -137,18 +31,23 @@ namespace Fantasy.Helper
/// <returns></returns>
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;
}
/// <summary>
/// 使用MurmurHash3算法生成一个uint的值
/// </summary>
@@ -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;
}
/// <summary>
/// 使用MurmurHash3算法生成一个long的值
/// </summary>
@@ -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
/// <summary>
/// 根据字符串计算一个Hash值
/// </summary>
/// <param name="rawData"></param>
/// <param name="obj"></param>
/// <param name="seed"></param>
/// <returns></returns>
public static int ComputeSha256HashAsInt(string rawData)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Hash32(string obj, uint seed = 0) => Hash32(obj.AsSpan(), seed);
/// <summary>
/// 根据字符串计算一个Hash值
/// </summary>
/// <param name="obj"></param>
/// <param name="seed"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Hash32<T>(in T obj, uint seed = 0) where T : unmanaged => Hash32(
MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf<T>()),
seed);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Hash32<T>(ReadOnlySpan<T> buffer, uint seed = 0) where T : unmanaged =>
Hash32(MemoryMarshal.Cast<T, byte>(buffer), seed);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Hash32(ReadOnlySpan<byte> 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<uint>(ref local2) * 2246822519U;
num2 = (uint)((((int)num6 << 13) | (int)(num6 >> 19)) * -1640531535);
uint num7 = num3 +
Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset1)) *
2246822519U;
num3 = (uint)((((int)num7 << 13) | (int)(num7 >> 19)) * -1640531535);
uint num8 = num4 +
Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset2)) *
2246822519U;
num4 = (uint)((((int)num8 << 13) | (int)(num8 >> 19)) * -1640531535);
uint num9 = num5 +
Unsafe.ReadUnaligned<uint>(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<uint>(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
}
/// <summary>
/// 根据字符串计算一个Hash值
/// </summary>
/// <param name="obj"></param>
/// <param name="seed"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long Hash64(string obj, ulong seed = 0) => Hash64(obj.AsSpan(), seed);
/// <summary>
/// 根据字符串计算一个Hash值
/// </summary>
/// <param name="obj"></param>
/// <param name="seed"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long Hash64<T>(in T obj, ulong seed = 0) where T : unmanaged => Hash64(
MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf<T>()),
seed);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long Hash64<T>(ReadOnlySpan<T> buffer, ulong seed = 0) where T : unmanaged =>
Hash64(MemoryMarshal.Cast<T, byte>(buffer), seed);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long Hash64(ReadOnlySpan<byte> 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<ulong>(ref local2) * 14029467366897019727UL;
num2 = (ulong)((((long)num6 << 31) | (long)(num6 >> 33)) * -7046029288634856825L);
var num7 = num3 +
Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(8U))) *
14029467366897019727UL;
num3 = (ulong)((((long)num7 << 31) | (long)(num7 >> 33)) * -7046029288634856825L);
var num8 = num4 +
Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(16U))) *
14029467366897019727UL;
num4 = (ulong)((((long)num8 << 31) | (long)(num8 >> 33)) * -7046029288634856825L);
var num9 = num5 +
Unsafe.ReadUnaligned<ulong>(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<ulong>(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<uint>(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
}
}
}

View File

@@ -54,7 +54,7 @@ namespace Fantasy.Helper
return null;
}
}
/// <summary>
/// 克隆一个IPEndPoint
/// </summary>
@@ -66,7 +66,7 @@ namespace Fantasy.Helper
var ip = (IPEndPoint)endPoint;
return new IPEndPoint(ip.Address, ip.Port);
}
/// <summary>
/// 比较两个IPEndPoint是否相等
/// </summary>
@@ -79,7 +79,7 @@ namespace Fantasy.Helper
var ip = (IPEndPoint)endPoint;
return ip.Address.Equals(ipEndPoint.Address) && ip.Port == ipEndPoint.Port;
}
/// <summary>
/// 比较两个IPEndPoint是否相等
/// </summary>
@@ -91,7 +91,6 @@ namespace Fantasy.Helper
{
return endPoint.Address.Equals(ipEndPoint.Address) && endPoint.Port == ipEndPoint.Port;
}
#if !FANTASY_WEBGL
/// <summary>
/// 将SocketAddress写入到Byte[]中
@@ -100,13 +99,13 @@ namespace Fantasy.Helper
/// <param name="buffer"></param>
/// <param name="offset"></param>
[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
/// <exception cref="ArgumentException"></exception>
/// <exception cref="InvalidOperationException"></exception>
[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<int>(ref spanRef);
var socketAddressSize = Unsafe.ReadUnaligned<int>(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
/// <exception cref="ArgumentException"></exception>
/// <exception cref="InvalidOperationException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe int ByteToSocketAddress(ReadOnlyMemory<byte> buffer, int offset, out SocketAddress socketAddress)
public static int ByteToSocketAddress(ReadOnlyMemory<byte> 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<int>(ref spanRef);
var socketAddressSize = Unsafe.ReadUnaligned<int>(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
/// <param name="socketAddress"></param>
/// <returns></returns>
/// <exception cref="NotSupportedException"></exception>
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<byte> 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<long>(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);
}
/// <summary>
/// 将 Socket 缓冲区大小设置为操作系统限制。
/// </summary>
@@ -440,4 +442,4 @@ namespace Fantasy.Helper
}
}
}
#endif
#endif

View File

@@ -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<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes1, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes1>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes2
{
private FixedBytes1 _e0;
private FixedBytes1 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes2, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes2>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes4
{
private FixedBytes2 _e0;
private FixedBytes2 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes4, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes4>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes8
{
private FixedBytes4 _e0;
private FixedBytes4 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes8, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes8>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes16
{
private FixedBytes8 _e0;
private FixedBytes8 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes16, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes16>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes32
{
private FixedBytes16 _e0;
private FixedBytes16 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes32, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes32>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes64
{
private FixedBytes32 _e0;
private FixedBytes32 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes64, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes64>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes128
{
private FixedBytes64 _e0;
private FixedBytes64 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes128, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes128>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes256
{
private FixedBytes128 _e0;
private FixedBytes128 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes256, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes256>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes512
{
private FixedBytes256 _e0;
private FixedBytes256 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes512, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes512>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes1024
{
private FixedBytes512 _e0;
private FixedBytes512 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes1024, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes1024>());
}
#endregion
}
#endif

View File

@@ -47,6 +47,15 @@ namespace Fantasy.IdFactory
}
}
/// <summary>
/// 获得当前的IdFactoryType
/// </summary>
/// <returns></returns>
public static IdFactoryType GetIdFactoryType()
{
return _idFactoryType;
}
internal static IEntityIdFactory EntityIdFactory(uint sceneId, byte worldId)
{
switch (_idFactoryType)

View File

@@ -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
/// <summary>

View File

@@ -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<nuint, void*> _alloc;
private static delegate* managed<nuint, void*> _allocZeroed;
private static delegate* managed<void*, void> _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*<nuint, void*> alloc, delegate*<nuint, void*> allocZeroed, delegate*<void*, void> 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<byte>.Count)
{
nuint offset = 0;
var lengthToExamine = byteCount - (nuint)Vector512<byte>.Count;
if (lengthToExamine != 0)
{
do
{
if (Vector512.LoadUnsafe(ref first, offset) != Vector512.LoadUnsafe(ref second, offset))
return false;
offset += (nuint)Vector512<byte>.Count;
} while (lengthToExamine > offset);
}
return Vector512.LoadUnsafe(ref first, lengthToExamine) == Vector512.LoadUnsafe(ref second, lengthToExamine);
}
#endif
if (Vector256.IsHardwareAccelerated && byteCount >= (nuint)Vector256<byte>.Count)
{
nuint offset = 0;
var lengthToExamine = byteCount - (nuint)Vector256<byte>.Count;
if (lengthToExamine != 0)
{
do
{
if (Vector256.LoadUnsafe(ref first, offset) != Vector256.LoadUnsafe(ref second, offset))
return false;
offset += (nuint)Vector256<byte>.Count;
} while (lengthToExamine > offset);
}
return Vector256.LoadUnsafe(ref first, lengthToExamine) == Vector256.LoadUnsafe(ref second, lengthToExamine);
}
if (byteCount >= (nuint)Vector128<byte>.Count)
{
nuint offset = 0;
var lengthToExamine = byteCount - (nuint)Vector128<byte>.Count;
if (lengthToExamine != 0)
{
do
{
if (Vector128.LoadUnsafe(ref first, offset) != Vector128.LoadUnsafe(ref second, offset))
return false;
offset += (nuint)Vector128<byte>.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<nuint>(ref first) - Unsafe.ReadUnaligned<nuint>(ref second);
differentBits |= Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned<nuint>(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<nuint>(ref Unsafe.AddByteOffset(ref first, offset)) != Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref second, offset)))
#else
if (Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref first, (nint)offset)) != Unsafe.ReadUnaligned<nuint>(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<nuint>(ref Unsafe.AddByteOffset(ref first, lengthToExamine)) == Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref second, lengthToExamine));
#else
return Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref first, (nint)lengthToExamine)) == Unsafe.ReadUnaligned<nuint>(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<ushort>(ref first);
differentBits -= Unsafe.ReadUnaligned<ushort>(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<uint>(ref first) - Unsafe.ReadUnaligned<uint>(ref second);
#if NET7_0_OR_GREATER
differentBits |= Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref second, offset));
#else
differentBits |= Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref first, (nint)offset)) - Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref second, (nint)offset));
#endif
return differentBits == 0;
}
}
}
}
#endif

View File

@@ -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<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes1, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes1>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes2
{
private FixedBytes1 _e0;
private FixedBytes1 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes2, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes2>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes4
{
private FixedBytes2 _e0;
private FixedBytes2 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes4, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes4>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes8
{
private FixedBytes4 _e0;
private FixedBytes4 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes8, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes8>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes16
{
private FixedBytes8 _e0;
private FixedBytes8 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes16, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes16>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes32
{
private FixedBytes16 _e0;
private FixedBytes16 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes32, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes32>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes64
{
private FixedBytes32 _e0;
private FixedBytes32 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes64, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes64>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes128
{
private FixedBytes64 _e0;
private FixedBytes64 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes128, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes128>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes256
{
private FixedBytes128 _e0;
private FixedBytes128 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes256, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes256>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes512
{
private FixedBytes256 _e0;
private FixedBytes256 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes512, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes512>());
}
[StructLayout(LayoutKind.Sequential)]
public struct FixedBytes1024
{
private FixedBytes512 _e0;
private FixedBytes512 _e1;
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref Unsafe.As<FixedBytes1024, byte>(ref Unsafe.AsRef(in this)), Unsafe.SizeOf<FixedBytes1024>());
}
}
#endif

View File

@@ -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<T>(in T obj, uint seed = 0) where T : unmanaged => Hash32(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf<T>()), seed);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Hash32<T>(ReadOnlySpan<T> buffer, uint seed = 0) where T : unmanaged => Hash32(MemoryMarshal.Cast<T, byte>(buffer), seed);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Hash32(ReadOnlySpan<byte> 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<uint>(ref local2) * 2246822519U;
num2 = (uint)((((int)num6 << 13) | (int)(num6 >> 19)) * -1640531535);
uint num7 = num3 + Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset1)) * 2246822519U;
num3 = (uint)((((int)num7 << 13) | (int)(num7 >> 19)) * -1640531535);
uint num8 = num4 + Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref local2, elementOffset2)) * 2246822519U;
num4 = (uint)((((int)num8 << 13) | (int)(num8 >> 19)) * -1640531535);
uint num9 = num5 + Unsafe.ReadUnaligned<uint>(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<uint>(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<T>(in T obj, ulong seed = 0) where T : unmanaged => Hash64(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf<T>()), seed);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long Hash64<T>(ReadOnlySpan<T> buffer, ulong seed = 0) where T : unmanaged => Hash64(MemoryMarshal.Cast<T, byte>(buffer), seed);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long Hash64(ReadOnlySpan<byte> 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<ulong>(ref local2) * 14029467366897019727UL;
num2 = (ulong)((((long)num6 << 31) | (long)(num6 >> 33)) * -7046029288634856825L);
var num7 = num3 + Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(8U))) * 14029467366897019727UL;
num3 = (ulong)((((long)num7 << 31) | (long)(num7 >> 33)) * -7046029288634856825L);
var num8 = num4 + Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref local2, new UIntPtr(16U))) * 14029467366897019727UL;
num4 = (ulong)((((long)num8 << 31) | (long)(num8 >> 33)) * -7046029288634856825L);
var num9 = num5 + Unsafe.ReadUnaligned<ulong>(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<ulong>(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<uint>(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
}
}
}

View File

@@ -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;
}

View File

@@ -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; }
}
/// <summary>
/// 漫游传送终端的请求
/// </summary>
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; }
}
/// <summary>
/// 用于服务器之间获取漫游的TerminusId。
/// </summary>
[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
}

View File

@@ -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<int>(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<uint>(ref Unsafe.Add(ref bufferRef, Packet.PacketLength));
RpcId = Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref bufferRef, Packet.InnerPacketRpcIdLocation));
RouteId = Unsafe.ReadUnaligned<long>(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
/// <param name="packInfo"></param>
/// <returns></returns>
/// <exception cref="ScanException"></exception>
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<int>(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<uint>(ref Unsafe.Add(ref bufferRef, Packet.PacketLength));
RpcId = Unsafe.ReadUnaligned<uint>(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<int>(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<uint>(ref Unsafe.Add(ref bufferRef, Packet.PacketLength));
RpcId = Unsafe.ReadUnaligned<uint>(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;
}
}

View File

@@ -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
/// <returns>打包完成会返回一个MemoryStreamBuffer</returns>
/// <exception cref="Exception"></exception>
[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;
}

View File

@@ -47,56 +47,61 @@ namespace Fantasy.PacketParser
#if FANTASY_NET
internal sealed class InnerReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser
{
public override unsafe bool UnPack(ref ReadOnlyMemory<byte> buffer, out APackInfo packInfo)
public override bool UnPack(ref ReadOnlyMemory<byte> 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<int>(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<uint>(ref Unsafe.Add(ref messageRef, Packet.InnerPacketRpcIdLocation));
PackInfo.ProtocolCode =
Unsafe.ReadUnaligned<uint>(ref Unsafe.Add(ref messageRef, Packet.PacketLength));
PackInfo.RouteId =
Unsafe.ReadUnaligned<long>(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<byte> buffer, out APackInfo packInfo)
public override bool UnPack(ref ReadOnlyMemory<byte> 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<int>(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<uint>(ref Unsafe.Add(ref messageRef, Packet.PacketLength));
PackInfo.RpcId =
Unsafe.ReadUnaligned<uint>(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;
}

View File

@@ -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();

View File

@@ -5,10 +5,6 @@ namespace Fantasy.PacketParser
/// </summary>
public struct Packet
{
/// <summary>
/// 消息体最大长度
/// </summary>
public const int PacketBodyMaxLength = ushort.MaxValue * 16;
/// <summary>
/// 消息体长度在消息头占用的长度
/// </summary>

View File

@@ -53,6 +53,7 @@ namespace Fantasy.Scheduler
case OpCodeType.OuterPingRequest:
{
// 注意心跳目前只有外网才才会有、内网之间不需要心跳。
session.LastReceiveTime = TimeHelper.Now;
_pingResponse.Now = session.LastReceiveTime;

View File

@@ -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();
// 开启监听

View File

@@ -17,12 +17,12 @@ namespace KCP
/// </summary>
/// <param name="buffer">KCP output destination</param>
/// <param name="length">KCP output size (excluding reserved)</param>
public delegate void KcpCallback(byte[] buffer, int length);
internal delegate void KcpCallback(byte[] buffer, int length);
/// <summary>
/// Kcp
/// </summary>
public sealed unsafe class Kcp : IDisposable
internal sealed unsafe class Kcp : IDisposable
{
/// <summary>
/// Kcp

View File

@@ -16,7 +16,7 @@ namespace kcp
/// <summary>
/// https://github.com/skywind3000/kcp
/// </summary>
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<nuint, void*> ikcp_malloc_hook = null;
public static delegate* managed<void*, void> ikcp_free_hook = null;
// //---------------------------------------------------------------------
// // manage segment
// //---------------------------------------------------------------------
// public static delegate* managed<nuint, void*> ikcp_malloc_hook = null;
// public static delegate* managed<void*, void> 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<nuint, void*> new_malloc, delegate* managed<void*, void> new_free)
{
ikcp_malloc_hook = new_malloc;
ikcp_free_hook = new_free;
}
// // redefine allocator
// public static void ikcp_allocator(delegate* managed<nuint, void*> new_malloc, delegate* managed<void*, void> 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;

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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<KCPClientNetwork>
internal sealed class KCPClientNetworkUpdateSystem : UpdateSystem<KCPClientNetwork>
{
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<uint> _updateTimeOutTime = new List<uint>();
private readonly SortedSet<uint> _updateTimer = new SortedSet<uint>();
private readonly SocketAsyncEventArgs _connectEventArgs = new SocketAsyncEventArgs();

View File

@@ -62,7 +62,7 @@ namespace Fantasy.Network.KCP
}
}
public static class KCPFactory
internal static class KCPFactory
{
public const int FANTASY_KCP_RESERVED_HEAD = 5;

View File

@@ -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,

View File

@@ -23,7 +23,7 @@ using Fantasy.Network.Interface;
namespace Fantasy.Network.KCP
{
public sealed class KCPServerNetworkUpdateSystem : UpdateSystem<KCPServerNetwork>
internal sealed class KCPServerNetworkUpdateSystem : UpdateSystem<KCPServerNetwork>
{
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);

View File

@@ -17,13 +17,13 @@ namespace Fantasy.Network.KCP
/// <summary>
/// KCP 服务器网络通道,用于处理服务器与客户端之间的数据通信。
/// </summary>
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; }

View File

@@ -40,7 +40,7 @@ namespace Fantasy.Network
case NetworkProtocolType.WebSocket:
{
var network = Entity.Create<WebSocketServerNetwork>(scene, false, true);
network.Initialize(networkTarget, bindIp, port);
network.Initialize(networkTarget, port);
return network;
}
case NetworkProtocolType.HTTP:

View File

@@ -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;

View File

@@ -17,7 +17,7 @@ public class WebSocketServerNetwork : ANetwork
private HttpListener _httpListener;
private readonly Dictionary<uint, INetworkChannel> _connectionChannel = new Dictionary<uint, INetworkChannel>();
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)
{

View File

@@ -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)

View File

@@ -184,7 +184,118 @@ public sealed class SessionRoamingComponent : Entity
#endregion
#region Message
#region OuterMessage
/// <summary>
/// 发送一个消息给漫游终
/// </summary>
/// <param name="message"></param>
public void Send(IRoamingMessage message)
{
Call(message.RouteType, message).Coroutine();
}
/// <summary>
/// 发送一个消息给漫游终端
/// </summary>
/// <param name="roamingType"></param>
/// <param name="message"></param>
public void Send(int roamingType, IRouteMessage message)
{
Call(roamingType, message).Coroutine();
}
/// <summary>
/// 发送一个RPC消息给漫游终端
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public async FTask<IResponse> Call(IRoamingMessage message)
{
return await Call(message.RouteType, message);
}
/// <summary>
/// 发送一个RPC消息给漫游终端
/// </summary>
/// <param name="roamingType"></param>
/// <param name="message"></param>
/// <returns></returns>
public async FTask<IResponse> 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)
{

View File

@@ -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<SessionIdleCheckerComponent>
@@ -57,7 +58,7 @@ public class SessionIdleCheckerComponent : Entity
/// </summary>
/// <param name="interval">以毫秒为单位的检查间隔。</param>
/// <param name="timeOut">以毫秒为单位的空闲超时时间。</param>
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);
}
/// <summary>
/// 重新开始心跳检查
/// </summary>
/// <param name="interval">以毫秒为单位的检查间隔。</param>
/// <param name="timeOut">以毫秒为单位的空闲超时时间。</param>
public void Restart(int interval, int timeOut)
{
Stop();
Start(interval, timeOut);
}
/// <summary>
/// 停止空闲检查功能。
/// </summary>
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();
}
}

View File

@@ -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> 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<int> _pingSamples = new Queue<int>();
/// <summary>
/// 当前Ping延迟毫秒滑动均值
/// </summary>
public int PingMilliseconds { get; private set; }
/// <summary>
/// 当前Ping延迟浮点数通常用于调试
/// </summary>
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
/// <param name="interval">以毫秒为单位的心跳请求发送间隔。</param>
/// <param name="timeOut">设置与服务器的通信超时时间,如果超过这个时间限制,将自动断开会话(Session)。</param>
/// <param name="timeOutInterval">用于检测与服务器连接超时频率。</param>
public void Start(int interval, int timeOut = 5000, int timeOutInterval = 3000)
/// <param name="maxPingSamples">Ping包的采样数量</param>
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();
}
/// <summary>
@@ -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)
{

View File

@@ -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;
/// <summary>
/// 关联的网络连接通道
/// </summary>
internal INetworkChannel Channel { get; private set; }
/// <summary>
/// 当前Session的终结点信息
/// </summary>
public IPEndPoint RemoteEndPoint { get; private set; }
private ANetworkMessageScheduler NetworkMessageScheduler { get; set; }
private ANetworkMessageScheduler NetworkMessageScheduler { get; set;}
internal readonly Dictionary<long, FTask<IResponse>> RequestCallback = new();
/// <summary>
/// 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<Session>(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<SessionIdleCheckerComponent>().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();
}
/// <summary>
/// 发送一个消息
/// </summary>
@@ -194,10 +187,10 @@ namespace Fantasy.Network
{
return;
}
Channel.Send(rpcId, routeId, null, message);
}
/// <summary>
/// 发送一个消息
/// </summary>
@@ -213,7 +206,7 @@ namespace Fantasy.Network
Channel.Send(rpcId, routeId, null, routeMessage);
}
/// <summary>
/// 发送一个RPC消息
/// </summary>
@@ -226,14 +219,14 @@ namespace Fantasy.Network
{
return null;
}
var requestCallback = FTask<IResponse>.Create();
var rpcId = ++_rpcId;
var rpcId = ++_rpcId;
RequestCallback.Add(rpcId, requestCallback);
Send(request, rpcId, routeId);
return requestCallback;
}
/// <summary>
/// 发送一个RPC消息
/// </summary>
@@ -246,9 +239,9 @@ namespace Fantasy.Network
{
return null;
}
var requestCallback = FTask<IResponse>.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
/// <summary>
/// 重新开始心跳检查
/// </summary>
/// <param name="interval"></param>
/// <param name="timeOut"></param>
public void RestartIdleChecker(int interval, int timeOut)
{
var sessionIdleCheckerComponent = GetComponent<SessionIdleCheckerComponent>();
if (sessionIdleCheckerComponent == null)
{
Log.Error("SessionIdleCheckerComponent is null");
return;
}
sessionIdleCheckerComponent.Restart(interval, timeOut);
}
/// <summary>
/// 重新开始心跳检查(使用框架配置的参数)
/// </summary>
public void RestartIdleChecker()
{
RestartIdleChecker(ProgramDefine.SessionIdleCheckerInterval, ProgramDefine.SessionIdleCheckerTimeout);
}
#endif
}
}
}

View File

@@ -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);
// 初始化序列化

View File

@@ -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;
/// <summary>
/// Fantasy框架XML配置文件加载器
/// </summary>
public static class ConfigLoader
{
/// <summary>
/// 从XML配置文件初始化所有配置
/// </summary>
/// <param name="configPath"></param>
/// <exception cref="InvalidOperationException"></exception>
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<MachineConfig>();
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<ProcessConfig>();
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<WorldConfig>();
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<SceneConfig>();
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<uint>();
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<uint>();
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<uint>();
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<uint>();
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<uint, Dictionary<int, uint>>(); // 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<int, uint>();
}
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>(idFactoryType));
// 加载网络配置
XmlNode? networkNode = root.SelectSingleNode("f:network", nsManager);
ProgramDefine.InnerNetwork = Enum.Parse<NetworkProtocolType>(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

View File

@@ -30,7 +30,29 @@ namespace Fantasy.Platform.Net
/// <param name="machineConfigJson"></param>
public static void Initialize(string machineConfigJson)
{
Instance = machineConfigJson.Deserialize<MachineConfigData>();
try
{
Instance = machineConfigJson.Deserialize<MachineConfigData>();
foreach (var config in Instance.List)
{
Instance._configs.TryAdd(config.Id, config);
}
}
catch (Exception e)
{
throw new InvalidOperationException($"MachineConfigData.Json format error {e.Message}");
}
}
/// <summary>
/// 初始化MachineConfig
/// </summary>
/// <param name="list"></param>
public static void Initialize(List<MachineConfig> list)
{
Instance = new MachineConfigData
{
List = list
};
foreach (var config in Instance.List)
{
Instance._configs.TryAdd(config.Id, config);

View File

@@ -26,12 +26,34 @@ namespace Fantasy.Platform.Net
/// </summary>
public static ProcessConfigData Instance { get; private set; }
/// <summary>
/// 初始化MachineConfig
/// 初始化ProcessConfig
/// </summary>
/// <param name="processConfigJson"></param>
public static void Initialize(string processConfigJson)
{
Instance = processConfigJson.Deserialize<ProcessConfigData>();
try
{
Instance = processConfigJson.Deserialize<ProcessConfigData>();
foreach (var config in Instance.List)
{
Instance._configs.TryAdd(config.Id, config);
}
}
catch (Exception e)
{
throw new InvalidOperationException($"ProcessConfigData.Json format error {e.Message}");
}
}
/// <summary>
/// 初始化ProcessConfig
/// </summary>
/// <param name="list"></param>
public static void Initialize(List<ProcessConfig> list)
{
Instance = new ProcessConfigData
{
List = list
};
foreach (var config in Instance.List)
{
Instance._configs.TryAdd(config.Id, config);

View File

@@ -42,7 +42,27 @@ namespace Fantasy.Platform.Net
/// <param name="sceneConfigJson"></param>
public static void Initialize(string sceneConfigJson)
{
Instance = sceneConfigJson.Deserialize<SceneConfigData>();
try
{
Instance = sceneConfigJson.Deserialize<SceneConfigData>();
Initialize();
}
catch (Exception e)
{
throw new InvalidOperationException($"SceneConfigData.Json format error {e.Message}");
}
}
/// <summary>
/// 初始化SceneConfig
/// </summary>
public static void Initialize(List<SceneConfig> sceneConfigs)
{
Instance = new SceneConfigData() { List = sceneConfigs };
Initialize();
}
private static void Initialize()
{
foreach (var config in Instance.List)
{
config.Initialize();

View File

@@ -30,7 +30,29 @@ namespace Fantasy.Platform.Net
/// <param name="worldConfigJson"></param>
public static void Initialize(string worldConfigJson)
{
Instance = worldConfigJson.Deserialize<WorldConfigData>();
try
{
Instance = worldConfigJson.Deserialize<WorldConfigData>();
foreach (var config in Instance.List)
{
Instance._configs.TryAdd(config.Id, config);
}
}
catch (Exception e)
{
throw new InvalidOperationException($"WorldConfigData.Json format error {e.Message}");
}
}
/// <summary>
/// 初始化WorldConfig
/// </summary>
/// <param name="list"></param>
public static void Initialize(List<WorldConfig> list)
{
Instance = new WorldConfigData
{
List = list
};
foreach (var config in Instance.List)
{
Instance._configs.TryAdd(config.Id, config);

View File

@@ -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
/// <summary>
/// 框架初始化
/// </summary>
/// <param name="log">日志实例</param>
/// <param name="assemblies">注册的Assembly</param>
public static async FTask Initialize(params System.Reflection.Assembly[] assemblies)
/// <returns></returns>
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<CommandLineOptions>(Environment.GetCommandLineArgs())
.WithNotParsed(error => throw new Exception("Command line format error!"))
.WithParsed(option =>
{
ProcessDefine.Options = option;
ProcessDefine.InnerNetwork = Enum.Parse<NetworkProtocolType>(option.InnerNetwork);
ProgramDefine.ProcessId = option.ProcessId;
ProgramDefine.ProcessType = option.ProcessType;
ProgramDefine.RuntimeMode = Enum.Parse<ProcessMode>(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();
/// <summary>
/// 框架初始化
/// </summary>
/// <param name="assemblies">注册的Assembly</param>
public static FTask Initialize(params System.Reflection.Assembly[] assemblies)
{
return Initialize(null, assemblies);
}
/// <summary>
@@ -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;
}
}

View File

@@ -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
/// </summary>
[Option('m', "Mode", Required = true, Default = "Release", HelpText = "Develop:启动Process配置表中的所有Process,\nRelease:根据ProcessId启动Process")]
public string Mode { get; set; }
/// <summary>
/// 服务器内部网络协议
/// TCP - 服务器内部之间通讯使用TCP协议
/// KCP - 服务器内部之间通讯使用KCP协议
/// WebSocket - 服务器内部之间通讯使用WebSocket协议(不推荐、TCP或KCP)
/// </summary>
[Option('n', "InnerNetwork", Required = false, Default = "TCP", HelpText = "TCP、KCP、WebSocket")]
public string InnerNetwork { get; set; }
/// <summary>
/// 会话空闲检查超时时间。
/// </summary>
[Option('t', "SessionIdleCheckerTimeout", Required = false, Default = 8000, HelpText = "Session idle check timeout")]
public int SessionIdleCheckerTimeout { get; set; }
/// <summary>
/// 会话空闲检查间隔。
/// </summary>
[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; }
/// <summary>
/// 启动组。
/// </summary>
[Option('g', "StartupGroup", Required = false, Default = 0, HelpText = "Used to start a group of Process")]
public int StartupGroup { get; set; }
}
/// <summary>
/// AppDefine
/// </summary>
internal static class ProcessDefine
{
/// <summary>
/// 命令行选项
/// </summary>
public static CommandLineOptions Options;
/// <summary>
/// App程序Id
/// </summary>
public static uint ProcessId => Options.ProcessId;
/// <summary>
/// 会话空闲检查超时时间。
/// </summary>
public static int SessionIdleCheckerTimeout => Options.SessionIdleCheckerTimeout;
/// <summary>
/// 会话空闲检查间隔。
/// </summary>
public static int SessionIdleCheckerInterval => Options.SessionIdleCheckerInterval;
/// <summary>
/// 内部网络通讯协议类型
/// </summary>
public static NetworkProtocolType InnerNetwork;
}
#endif

View File

@@ -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
{
/// <summary>
/// 程序定义
/// </summary>
public static class ProgramDefine
{
/// <summary>
/// Fantasy版本。
/// </summary>
public const string VERSION = "Fantasy 2.0 Beta";
/// <summary>
/// 消息体最大长度(字节)。默认1024k。
/// 注意:前后端设置的消息大小,一定要一样才可以,不然会不出现问题。
/// </summary>
public static int MaxMessageSize { get; set; } = ushort.MaxValue * 16;
#if FANTASY_NET
/// <summary>
/// App程序Id。
/// </summary>
public static uint ProcessId { get; internal set; }
/// <summary>
/// 应用程序的类型。
/// </summary>
public static string ProcessType { get; internal set; }
/// <summary>
/// 服务器运行模式,获取或设置服务器的运行模式。
/// </summary>
public static ProcessMode RuntimeMode { get; internal set; }
/// <summary>
/// 服务器启动组
/// </summary>
public static int StartupGroup { get; internal set; }
/// <summary>
/// 会话空闲检查超时时间。
/// </summary>
public static int SessionIdleCheckerTimeout { get; internal set; }
/// <summary>
/// 会话空闲检查间隔。
/// </summary>
public static int SessionIdleCheckerInterval { get; internal set; }
/// <summary>
/// 内部网络通讯协议类型。
/// </summary>
public static NetworkProtocolType InnerNetwork { get; internal set; }
#endif
}
}

View File

@@ -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();

View File

@@ -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
}

View File

@@ -163,7 +163,11 @@ namespace Fantasy
EntityPool = new EntityPool();
EntityListPool = new EntityListPool<Entity>();
EntitySortedDictionaryPool = new EntitySortedDictionaryPool<long, Entity>();
SceneUpdate = EntityComponent = await Create<EntityComponent>(this, false, false).Initialize();
EntityComponent = await Create<EntityComponent>(this, false, false).Initialize();
SceneUpdate = EntityComponent;
#if FANTASY_UNITY
SceneLateUpdate = EntityComponent;
#endif
MessagePoolComponent = Create<MessagePoolComponent>(this,false,true);
EventComponent = await Create<EventComponent>(this,false,true).Initialize();
TimerComponent = Create<TimerComponent>(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
/// <param name="runTimeId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
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}");

View File

@@ -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
}
}

View File

@@ -11,7 +11,7 @@ namespace Fantasy
{
private bool _isDisposed;
private readonly List<Thread> _threads;
private readonly ConcurrentBag<Scene> _queue = new ConcurrentBag<Scene>();
private readonly ConcurrentQueue<Scene> _queue = new ConcurrentQueue<Scene>();
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<Scene>();
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
{

View File

@@ -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);

View File

@@ -22,24 +22,27 @@ namespace Fantasy
/// 存储当前Scene下管理的实体。
/// </summary>
private readonly Dictionary<long, Entity> _entities = new Dictionary<long, Entity>();
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
/// <param name="runTimeId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public override Session GetSession(long runTimeId)
internal override Session GetSession(long runTimeId)
{
return RootScene.GetSession(runTimeId);
}

View File

@@ -272,7 +272,7 @@ namespace Fantasy.Serialize
/// </summary>
/// <param name="object"></param>
/// <returns></returns>
public static byte[] Serialize(object @object)
public byte[] Serialize(object @object)
{
if (@object is ASerialize aSerialize)
{
@@ -287,7 +287,7 @@ namespace Fantasy.Serialize
/// <param name="object"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static byte[] Serialize<T>(T @object)
public byte[] Serialize<T>(T @object)
{
if (@object is ASerialize aSerialize)
{

View File

@@ -36,6 +36,16 @@ namespace Fantasy.Serialize
throw new NotImplementedException();
}
public byte[] Serialize(object obj)
{
throw new NotImplementedException();
}
public byte[] Serialize<T>(T @object)
{
throw new NotImplementedException();
}
public void Serialize<T>(T @object, IBufferWriter<byte> buffer)
{
throw new NotImplementedException();

View File

@@ -59,6 +59,19 @@ namespace Fantasy.Serialize
/// <summary>
/// 序列化
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
byte[] Serialize(object obj);
/// <summary>
/// 序列化
/// </summary>
/// <param name="object"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
byte[] Serialize<T>(T @object);
/// <summary>
/// 序列化
/// </summary>
/// <param name="object"></param>
/// <param name="buffer"></param>
/// <typeparam name="T"></typeparam>

View File

@@ -182,7 +182,12 @@ namespace Fantasy.Serialize
RuntimeTypeModel.Default.Serialize(buffer, @object);
}
internal byte[] Serialize(object @object)
/// <summary>
/// 使用ProtoBuf序列化某一个实例到byte[]
/// </summary>
/// <param name="object"></param>
/// <returns></returns>
public byte[] Serialize(object @object)
{
if (@object is ASerialize aSerialize)
{
@@ -195,7 +200,13 @@ namespace Fantasy.Serialize
return buffer.ToArray();
}
}
private byte[] Serialize<T>(T @object)
/// <summary>
/// 使用ProtoBuf序列化某一个实例到byte[]
/// </summary>
/// <param name="object"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public byte[] Serialize<T>(T @object)
{
if (@object is ASerialize aSerialize)
{

View File

@@ -174,7 +174,30 @@ namespace Fantasy.Serialize
RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object);
}
private byte[] Serialize<T>(T @object)
/// <summary>
/// 使用ProtoBuf序列化某一个实例到byte[]
/// </summary>
/// <param name="object"></param>
/// <returns></returns>
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();
}
}
/// <summary>
/// 使用ProtoBuf序列化某一个实例到byte[]
/// </summary>
/// <param name="object"></param>
/// <returns></returns>
public byte[] Serialize<T>(T @object)
{
if (@object is ASerialize aSerialize)
{

View File

@@ -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);
}

View File

@@ -0,0 +1,85 @@
namespace Fantasy.ConfigTable;
public interface IConfigContext
{
// 定义非泛型接口
}
public class ConfigContext<T> : IConfigContext where T : IConfigTable
{
private static List<T> _cacheList = new List<T>();
#region Cache
public void Association(List<T> list)
{
if (list != null)
{
_cacheList = list;
}
}
#endregion
public int Count()
{
return _cacheList.Count;
}
public int Count(Func<T, bool> 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<T> match)
{
return Get(match);
}
public T Last(Predicate<T> match)
{
return _cacheList.FindLast(match);
}
public T Get(Predicate<T> match)
{
return _cacheList.Find(match);
}
public T GetRandom()
{
Random random = new Random();
// 随机从列表中取一个对象
return _cacheList[random.Next(_cacheList.Count)];
}
public List<T> GetList()
{
return _cacheList;
}
public List<T> GetList(Predicate<T> match)
{
return _cacheList.FindAll(match);
}
private T First(uint key)
{
return _cacheList.Find(t => t.Key == key);
}
}

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