From c97bd0ab55ce156c5ba7f8a9302734a2876c0b44 Mon Sep 17 00:00:00 2001 From: bob <605277374@qq.com> Date: Fri, 1 Aug 2025 18:05:25 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=AE=9A=E6=97=B6=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=90=BD=E5=9C=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Entity/Entity.csproj | 1 - Entity/Game/Container/ContainerComponent.cs | 23 --- Entity/Game/Fish/Fish.cs | 10 + Entity/Game/Fish/FishContainer.cs | 19 ++ Entity/Game/Item/Item.cs | 9 +- .../Container.cs => Item/ItemContainer.cs} | 22 +-- Entity/Game/Mission/Mission.cs | 10 + Entity/Game/Player/Child/PlayerBasic.cs | 32 ++++ Entity/Game/Player/Child/PlayerSlot.cs | 34 ++++ Entity/Game/Player/Child/PlayerStatistics.cs | 1 + .../{PlayerDayFlags.cs => PlayerTackle.cs} | 5 +- Entity/Game/Player/Child/PlayerVip.cs | 7 +- Entity/Game/Player/Child/PlayerWallet.cs | 27 +++ Entity/Game/Player/Player.cs | 67 ++----- Entity/Game/Player/PlayerAutoSaveComponent.cs | 8 - Entity/Game/Player/PlayerManageComponent.cs | 12 ++ Entity/Game/Skill/Skill.cs | 11 ++ .../Handler/G2Game_EnterRequestHandler.cs | 78 +------- .../{Handler => Item/Helper}/ItemFactory.cs | 0 .../ItemContainerSystem.cs} | 27 +-- .../Components/PlayerManageComponentSystem.cs | 178 ++++++++++++++++++ Hotfix/Game/Player/Entity/PlayerSystem.cs | 35 ++++ .../Player => Player/Helper}/PlayerFactory.cs | 15 +- .../Player => Player/Helper}/PlayerHelper.cs | 77 ++++++-- .../Game/System/ItemManagerComponentSystem.cs | 6 - .../Player/PlayerAutoSaveComponentSystem.cs | 6 - .../Game/System/Player/PlayerDestroySystem.cs | 13 -- .../System/PlayerManageComponentSystem.cs | 49 ----- Hotfix/Hotfix.csproj | 4 - Server.sln.DotSettings.user | 1 + 30 files changed, 477 insertions(+), 310 deletions(-) delete mode 100644 Entity/Game/Container/ContainerComponent.cs create mode 100644 Entity/Game/Fish/FishContainer.cs rename Entity/Game/{Container/Container.cs => Item/ItemContainer.cs} (66%) create mode 100644 Entity/Game/Mission/Mission.cs create mode 100644 Entity/Game/Player/Child/PlayerBasic.cs create mode 100644 Entity/Game/Player/Child/PlayerSlot.cs rename Entity/Game/Player/Child/{PlayerDayFlags.cs => PlayerTackle.cs} (56%) create mode 100644 Entity/Game/Player/Child/PlayerWallet.cs delete mode 100644 Entity/Game/Player/PlayerAutoSaveComponent.cs create mode 100644 Entity/Game/Skill/Skill.cs rename Hotfix/Game/{Handler => Item/Helper}/ItemFactory.cs (100%) rename Hotfix/Game/{Container/ContainerSystem.cs => Item/ItemContainerSystem.cs} (59%) create mode 100644 Hotfix/Game/Player/Components/PlayerManageComponentSystem.cs create mode 100644 Hotfix/Game/Player/Entity/PlayerSystem.cs rename Hotfix/Game/{System/Player => Player/Helper}/PlayerFactory.cs (54%) rename Hotfix/Game/{System/Player => Player/Helper}/PlayerHelper.cs (70%) delete mode 100644 Hotfix/Game/System/ItemManagerComponentSystem.cs delete mode 100644 Hotfix/Game/System/Player/PlayerAutoSaveComponentSystem.cs delete mode 100644 Hotfix/Game/System/Player/PlayerDestroySystem.cs delete mode 100644 Hotfix/Game/System/PlayerManageComponentSystem.cs diff --git a/Entity/Entity.csproj b/Entity/Entity.csproj index be2ab6d..a23094a 100644 --- a/Entity/Entity.csproj +++ b/Entity/Entity.csproj @@ -29,7 +29,6 @@ - diff --git a/Entity/Game/Container/ContainerComponent.cs b/Entity/Game/Container/ContainerComponent.cs deleted file mode 100644 index 92b7ea9..0000000 --- a/Entity/Game/Container/ContainerComponent.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Fantasy.Entitas; - -namespace NB; - -public enum ContainerType : uint -{ - /// - /// 背包 - /// - Bag, - - /// - /// 鱼护 - /// - FishBag, -} - -/// -/// 物品容器组件 -/// -public class ContainerComponent : Entity -{ -} \ No newline at end of file diff --git a/Entity/Game/Fish/Fish.cs b/Entity/Game/Fish/Fish.cs index a15edfe..08c7746 100644 --- a/Entity/Game/Fish/Fish.cs +++ b/Entity/Game/Fish/Fish.cs @@ -24,4 +24,14 @@ public class Fish : Entity /// 失效时间 /// [BsonElement("et")] public long ExpirationTime; + + /// + /// 获取地图 + /// + [BsonElement("map")] public int Map; + + /// + /// 物品所属的容器 + /// + [BsonIgnore] FishContainer Container; } \ No newline at end of file diff --git a/Entity/Game/Fish/FishContainer.cs b/Entity/Game/Fish/FishContainer.cs new file mode 100644 index 0000000..1dd3112 --- /dev/null +++ b/Entity/Game/Fish/FishContainer.cs @@ -0,0 +1,19 @@ +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace NB.Game; + +public class FishContainer : Entity +{ + /// + /// 最大格子数量 + /// + public int CellCountMax; + + /// + /// 容器内的物品 + /// + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary Fishes = new Dictionary(); +} \ No newline at end of file diff --git a/Entity/Game/Item/Item.cs b/Entity/Game/Item/Item.cs index b6e0be6..e394885 100644 --- a/Entity/Game/Item/Item.cs +++ b/Entity/Game/Item/Item.cs @@ -11,8 +11,6 @@ public enum ItemType Fish, } - - public class Item : Entity { /// @@ -43,5 +41,10 @@ public class Item : Entity /// /// 耐久度 /// - [BsonElement("a")] public int Abrasion; + [BsonElement("abr")] public int Abrasion; + + /// + /// 物品所属的容器 + /// + [BsonIgnore] ItemContainer Container; } \ No newline at end of file diff --git a/Entity/Game/Container/Container.cs b/Entity/Game/Item/ItemContainer.cs similarity index 66% rename from Entity/Game/Container/Container.cs rename to Entity/Game/Item/ItemContainer.cs index 7ec1262..b0713e7 100644 --- a/Entity/Game/Container/Container.cs +++ b/Entity/Game/Item/ItemContainer.cs @@ -6,34 +6,20 @@ using NB.Game; namespace NB; -public sealed class Container : Entity +public sealed class ItemContainer : Entity { - /// - /// 可用格子数量 - /// - public int CellCount; - /// /// 最大格子数量 /// public int CellCountMax; - - /// - /// 当前已经使用格子数量 - /// - public int CurrentCellCount; - + /// /// 容器内的物品 /// [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] public Dictionary Items = new Dictionary(); - - /// - /// 容器内物品,按格子进行分组 - /// - [BsonIgnore] public Dictionary ItemsByCell = new Dictionary(); - + + /// /// 按物品id分组 /// diff --git a/Entity/Game/Mission/Mission.cs b/Entity/Game/Mission/Mission.cs new file mode 100644 index 0000000..76c1a23 --- /dev/null +++ b/Entity/Game/Mission/Mission.cs @@ -0,0 +1,10 @@ +using Fantasy.Entitas; + +namespace NB.Game; + +/// +/// 角色任务 +/// +public class Mission : Entity +{ +} \ No newline at end of file diff --git a/Entity/Game/Player/Child/PlayerBasic.cs b/Entity/Game/Player/Child/PlayerBasic.cs new file mode 100644 index 0000000..71017db --- /dev/null +++ b/Entity/Game/Player/Child/PlayerBasic.cs @@ -0,0 +1,32 @@ +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; + +namespace NB.Game; + +public class PlayerBasic : Entity +{ + /// + /// 昵称 + /// + public string NickName; + + /// + /// 头像 + /// + public string Head; + + /// + /// 国家 + /// + public string Country; + + /// + /// 等级 + /// + public int Level; + + /// + /// 当前经验 + /// + public int Exp; +} \ No newline at end of file diff --git a/Entity/Game/Player/Child/PlayerSlot.cs b/Entity/Game/Player/Child/PlayerSlot.cs new file mode 100644 index 0000000..525dda0 --- /dev/null +++ b/Entity/Game/Player/Child/PlayerSlot.cs @@ -0,0 +1,34 @@ +using Fantasy.Entitas; + +namespace NB.Game; + +public enum SlotType +{ + None, + + /// + /// 物品 + /// + Item, + + /// + /// 钓组 + /// + Tackle +} + +/// +/// 快速使用插槽 +/// +public class PlayerSlot : Entity +{ + /// + /// 插槽类型 + /// + public SlotType SlotType; + + /// + /// 绑定快速使用的id + /// + public long BindId; +} \ No newline at end of file diff --git a/Entity/Game/Player/Child/PlayerStatistics.cs b/Entity/Game/Player/Child/PlayerStatistics.cs index c1aad96..08057f6 100644 --- a/Entity/Game/Player/Child/PlayerStatistics.cs +++ b/Entity/Game/Player/Child/PlayerStatistics.cs @@ -1,4 +1,5 @@ using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; namespace NB; diff --git a/Entity/Game/Player/Child/PlayerDayFlags.cs b/Entity/Game/Player/Child/PlayerTackle.cs similarity index 56% rename from Entity/Game/Player/Child/PlayerDayFlags.cs rename to Entity/Game/Player/Child/PlayerTackle.cs index 22b612a..4b2d85b 100644 --- a/Entity/Game/Player/Child/PlayerDayFlags.cs +++ b/Entity/Game/Player/Child/PlayerTackle.cs @@ -3,8 +3,9 @@ namespace NB; /// -/// 角色状态标志量 +/// 玩家钓组 /// -public class PlayerDayFlags +public class PlayerTackle : Entity { + } \ No newline at end of file diff --git a/Entity/Game/Player/Child/PlayerVip.cs b/Entity/Game/Player/Child/PlayerVip.cs index 7deddfe..3124a60 100644 --- a/Entity/Game/Player/Child/PlayerVip.cs +++ b/Entity/Game/Player/Child/PlayerVip.cs @@ -1,6 +1,9 @@ -namespace NB; +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; -public class PlayerVip +namespace NB; + +public class PlayerVip : Entity { /// /// 是否是vip diff --git a/Entity/Game/Player/Child/PlayerWallet.cs b/Entity/Game/Player/Child/PlayerWallet.cs new file mode 100644 index 0000000..c4ee134 --- /dev/null +++ b/Entity/Game/Player/Child/PlayerWallet.cs @@ -0,0 +1,27 @@ +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace NB.Game; + +/// +/// 用户钱包 +/// +public class PlayerWallet : Entity +{ + /// + /// 余额 + /// + public int Money; + + /// + /// 金币 + /// + public int Gold; + + /// + /// 其他货币 + /// + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary Other = new(); +} \ No newline at end of file diff --git a/Entity/Game/Player/Player.cs b/Entity/Game/Player/Player.cs index a3bac85..9244c58 100644 --- a/Entity/Game/Player/Player.cs +++ b/Entity/Game/Player/Player.cs @@ -6,72 +6,35 @@ namespace NB.Game; public sealed class Player : Entity { - [BsonElement("ct")] public long CreateTime; - [BsonElement("lt")] public long LoginTime; + /// + /// 基础信息 + /// + public PlayerBasic Basic; /// - /// 昵称 + /// 统计信息 /// - [BsonElement("name")] public string NickName; + public PlayerStatistics Statistics; /// - /// 头像 + /// 角色vip信息 /// - public string Head; + public PlayerVip Vip; /// - /// 国家 + /// 钱包 /// - public string Country; + public PlayerWallet Wallet; /// - /// 等级 + /// 背包 /// - [BsonElement("lv")] public int Level; - - /// - /// 当前经验 - /// - public int Exp; - - /// - /// 余额 - /// - public int Money; - - /// - /// 金币 - /// - public int Gold; - - // public PlayerStatistics Statistics = new PlayerStatistics(); - // public PlayerDayFlags DayFlags = new PlayerDayFlags(); - // public PlayerVip Vip = new PlayerVip(); - - - /// - /// 其他货币 - /// - [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] - public Dictionary Currency = new(); - - /// - /// 插槽 - /// - [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] - public Dictionary Slots = new Dictionary(); - - /// - /// 背包物品 - /// - [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] - public Dictionary Items = new Dictionary(); + public ItemContainer ItemContainer; /// /// 鱼护 /// - [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] - public Dictionary Fishes = new Dictionary(); + public FishContainer FishContainer; [BsonIgnore] public long SessionRunTimeId; @@ -82,7 +45,7 @@ public sealed class Player : Entity [BsonIgnore] public bool NeedSave; /// - /// 最后保存时间 + /// 需要保存数据库时间 /// - [BsonIgnore] public long LastSaveTime; + [BsonIgnore] public long NeedSaveTime; } \ No newline at end of file diff --git a/Entity/Game/Player/PlayerAutoSaveComponent.cs b/Entity/Game/Player/PlayerAutoSaveComponent.cs deleted file mode 100644 index 86b02e5..0000000 --- a/Entity/Game/Player/PlayerAutoSaveComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Fantasy.Entitas; - -namespace NB.Game; - -public class PlayerAutoSaveComponent : Entity -{ - -} \ No newline at end of file diff --git a/Entity/Game/Player/PlayerManageComponent.cs b/Entity/Game/Player/PlayerManageComponent.cs index 1965dca..99bbac4 100644 --- a/Entity/Game/Player/PlayerManageComponent.cs +++ b/Entity/Game/Player/PlayerManageComponent.cs @@ -4,5 +4,17 @@ namespace NB.Game; public sealed class PlayerManageComponent : Entity { + /// + /// 10分钟 + /// + public const long AutoSaveTime = 60000; // 600000; + + public long AutoSaveTimerId; + public readonly Dictionary Players = new(); + + /// + /// 需要保存到数据库的玩家 + /// + public readonly HashSet NeedSavePlayer = new(); } \ No newline at end of file diff --git a/Entity/Game/Skill/Skill.cs b/Entity/Game/Skill/Skill.cs new file mode 100644 index 0000000..09d0b5d --- /dev/null +++ b/Entity/Game/Skill/Skill.cs @@ -0,0 +1,11 @@ +using Fantasy.Entitas; + +namespace NB.Game; + +/// +/// 角色技能 +/// +public class Skill : Entity +{ + +} \ No newline at end of file diff --git a/Hotfix/Game/Handler/G2Game_EnterRequestHandler.cs b/Hotfix/Game/Handler/G2Game_EnterRequestHandler.cs index fd66e40..5aa93d1 100644 --- a/Hotfix/Game/Handler/G2Game_EnterRequestHandler.cs +++ b/Hotfix/Game/Handler/G2Game_EnterRequestHandler.cs @@ -16,89 +16,13 @@ public class G2Game_EnterRequestHandler : RouteRPC(); - Log.Debug("检查账号是否在缓存中"); - if (!gameAccountManageComponent.TryGet(accountId, out var account)) - { - // 首先要先到数据库中查询是否有这个账号 - account = await PlayerHelper.LoadDataBase(scene, accountId); - // 如果有的话,就直接加入在缓存中就可以了 - if (account == null) - { - Log.Debug("检查到账号没有在数据库中,需要创建一个新的账号并且保存到数据库中"); - // 如果没有,就要创建一个新的并且保存到数据库。 - // 如果不存在,表示这是一个新的账号,需要创建一下这个账号。 - account = await PlayerFactory.Create(scene, accountId); - account.Level = 99; - account.NickName = "王麻子"; - account.Country = "cn"; - account.Exp = 999; - account.Head = "xxx.png"; - - for (int i = 0; i < 500; i++) - { - var item = Entity.Create(scene, true, true); - account.Items.Add(item.Id, item); - } - - for (int i = 0; i < 500; i++) - { - var item = Entity.Create(scene, true, true); - account.Fishes.Add(item.Id, item); - } - // account.Items - - account.NeedSave = true; - - await account.SaveDataBase(); - } - else - { - Log.Debug("检查到账号在数据库中"); - } - - Log.Debug("把当前账号添加到缓存中"); - // 把创建完成的Account放入到缓存中 - gameAccountManageComponent.Add(account); - } - else - { - Log.Debug("检测到当前账号已经在缓存中了"); - // 如果有延迟下线的计划任务,那就先取消一下。 - account.CancelTimeout(); - // 如果在Gate的缓存中已经存在了该账号那只能以下几种可能: - // 1、同一客户端发送了重复登录的请求数据。 - // 2、客户端经历的断线然后又重新连接到这个服务器上了(断线重连)。 - // 3、多个客户端同时登录了这个账号(顶号)。 - - if (request.GateRouteId == account.SessionRunTimeId) - { - // 如果执行到这里,说明是客户端发送了多次登录的请求,这样的情况下,直接返回就可以了,不需要做任何操作。 - return; - } - } - - account.LoginTime = TimeHelper.Now; + var account = await gameAccountManageComponent.Online(scene, request.AccountId, request.GateRouteId); response.RoleRouteId = account.RuntimeId; - if (account.GetComponent() == null) - { - var mailComponent = await scene.World.DataBase.Query(account.Id, true); - if (mailComponent == null) - { - //如果没有邮件组件 - account.AddComponent(); - } - else - { - account.AddComponent(mailComponent); - } - } - await FTask.CompletedTask; } } \ No newline at end of file diff --git a/Hotfix/Game/Handler/ItemFactory.cs b/Hotfix/Game/Item/Helper/ItemFactory.cs similarity index 100% rename from Hotfix/Game/Handler/ItemFactory.cs rename to Hotfix/Game/Item/Helper/ItemFactory.cs diff --git a/Hotfix/Game/Container/ContainerSystem.cs b/Hotfix/Game/Item/ItemContainerSystem.cs similarity index 59% rename from Hotfix/Game/Container/ContainerSystem.cs rename to Hotfix/Game/Item/ItemContainerSystem.cs index 1c546a7..97ea7e4 100644 --- a/Hotfix/Game/Container/ContainerSystem.cs +++ b/Hotfix/Game/Item/ItemContainerSystem.cs @@ -2,13 +2,11 @@ namespace NB.Game; -public sealed class ContainerDestroySystem : DestroySystem +public sealed class ItemContainerDestroySystem : DestroySystem { - protected override void Destroy(Container self) + protected override void Destroy(ItemContainer self) { - self.CellCount = 0; self.CellCountMax = 0; - self.CurrentCellCount = 0; foreach (var (_, item) in self.Items) { @@ -16,13 +14,12 @@ public sealed class ContainerDestroySystem : DestroySystem } self.Items.Clear(); - self.ItemsByCell.Clear(); self.ItemsByConfigId.Clear(); self.ItemsByType.Clear(); } } -public static class ContainerSystem +public static class ItemContainerSystem { #region Get @@ -33,30 +30,18 @@ public static class ContainerSystem /// /// /// - public static bool GetItemById(this Container self, uint id, out Item item) + public static bool GetItemById(this ItemContainer self, uint id, out Item item) { return self.Items.TryGetValue(id, out item); } - /// - /// 通过格子位置获取物品 - /// - /// - /// - /// - /// - public static bool GetItemByCell(this Container self, uint cell, out Item item) - { - return self.ItemsByCell.TryGetValue(cell, out item); - } - /// /// 通过配置id获取物品 /// /// /// /// - public static void GetItemByConfigId(this Container self, uint configId, List items) + public static void GetItemByConfigId(this ItemContainer self, uint configId, List items) { if (!self.ItemsByConfigId.TryGetValue(configId, out var itemList)) { @@ -72,7 +57,7 @@ public static class ContainerSystem /// /// /// - public static void GetItemByType(this Container self, ItemType type, List items) + public static void GetItemByType(this ItemContainer self, ItemType type, List items) { if (!self.ItemsByType.TryGetValue((uint)type, out var itemList)) { diff --git a/Hotfix/Game/Player/Components/PlayerManageComponentSystem.cs b/Hotfix/Game/Player/Components/PlayerManageComponentSystem.cs new file mode 100644 index 0000000..5b99bee --- /dev/null +++ b/Hotfix/Game/Player/Components/PlayerManageComponentSystem.cs @@ -0,0 +1,178 @@ +using Fantasy; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; + +#pragma warning disable CS8603 // 可能返回 null 引用。 + +namespace NB.Game; + +public sealed class PlayerManageComponentAwakeSystem : AwakeSystem +{ + protected override void Awake(PlayerManageComponent self) + { + self.AutoSaveTimerId = + self.Scene.TimerComponent.Net.RepeatedTimer(1000 * 60, () => { _ = self.CheckAutoSave(); }); + } +} + +public sealed class PlayerManageComponentDestroySystem : DestroySystem +{ + protected override void Destroy(PlayerManageComponent self) + { + foreach (var (_, gameAccount) in self.Players) + { + gameAccount.Dispose(); + } + + self.Players.Clear(); + self.Scene.TimerComponent.Net.Remove(self.AutoSaveTimerId); + self.AutoSaveTimerId = 0; + } +} + +public static class PlayerManageComponentSystem +{ + #region 上线下线 + + /// + /// 玩家上线 + /// + /// + /// + /// + public static async FTask Online(this PlayerManageComponent self, Scene scene, long accountId, + long gateRouteId) + { + Log.Debug("检查账号是否在缓存中"); + if (!self.TryGet(accountId, out var account)) + { + // 首先要先到数据库中查询是否有这个账号 + account = await PlayerHelper.LoadDataBase(scene, accountId); + // 如果有的话,就直接加入在缓存中就可以了 + if (account == null) + { + Log.Debug("检查到账号没有在数据库中,需要创建一个新的账号并且保存到数据库中"); + // 如果没有,就要创建一个新的并且保存到数据库。 + // 如果不存在,表示这是一个新的账号,需要创建一下这个账号。 + account = PlayerFactory.Create(scene, accountId); + + + account.Basic.Level = 99; + account.Basic.NickName = "王麻子"; + account.Basic.Country = "cn"; + account.Basic.Exp = 999; + account.Basic.Head = "xxx.png"; + + // for (int i = 0; i < 500; i++) + // { + // var item = Entity.Create(scene, true, true); + // account.ItemContainer.Add(item.Id, item); + // } + // + // for (int i = 0; i < 500; i++) + // { + // var item = Entity.Create(scene, true, true); + // account.Fishes.Add(item.Id, item); + // } + } + else + { + Log.Debug("检查到账号在数据库中"); + } + + Log.Debug("把当前账号添加到缓存中"); + // 把创建完成的Account放入到缓存中 + self.Add(account); + } + else + { + Log.Debug("检测到当前账号已经在缓存中了"); + // 如果有延迟下线的计划任务,那就先取消一下。 + account.CancelTimeout(); + // 如果在Gate的缓存中已经存在了该账号那只能以下几种可能: + // 1、同一客户端发送了重复登录的请求数据。 + // 2、客户端经历的断线然后又重新连接到这个服务器上了(断线重连)。 + // 3、多个客户端同时登录了这个账号(顶号)。 + + if (gateRouteId == account.SessionRunTimeId) + { + // 如果执行到这里,说明是客户端发送了多次登录的请求,这样的情况下,直接返回就可以了,不需要做任何操作。 + return null; + } + } + + account.Statistics.LoginTime = TimeHelper.Now; + + + if (account.GetComponent() == null) + { + var mailComponent = await scene.World.DataBase.Query(account.Id, true); + if (mailComponent == null) + { + //如果没有邮件组件 + account.AddComponent(); + } + else + { + account.AddComponent(mailComponent); + } + } + + await account.Save(); + + return account; + } + + #endregion + + #region 获取&移除 + + public static void Add(this PlayerManageComponent self, Player account) + { + self.Players.Add(account.Id, account); + } + + public static Player Get(this PlayerManageComponent self, long accountId) + { + return self.Players.GetValueOrDefault(accountId); + } + + public static bool TryGet(this PlayerManageComponent self, long accountId, out Player account) + { + return self.Players.TryGetValue(accountId, out account); + } + + public static void Remove(this PlayerManageComponent self, long accountId, bool isDispose = true) + { + if (!self.Players.Remove(accountId, out var account)) + { + return; + } + + if (!isDispose) + { + return; + } + + account.Dispose(); + } + + #endregion + + #region 自动保存 + + public static async FTask CheckAutoSave(this PlayerManageComponent self) + { + foreach (var (_, player) in self.Players) + { + if (player.NeedSave) + { + await player.SaveImmediately(); + } + } + } + + #endregion +} \ No newline at end of file diff --git a/Hotfix/Game/Player/Entity/PlayerSystem.cs b/Hotfix/Game/Player/Entity/PlayerSystem.cs new file mode 100644 index 0000000..e3dbff5 --- /dev/null +++ b/Hotfix/Game/Player/Entity/PlayerSystem.cs @@ -0,0 +1,35 @@ +using Fantasy; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; + +#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。 + +namespace NB.Game; + +public sealed class PlayerDestroySystem : DestroySystem +{ + protected override void Destroy(Player self) + { + self.Basic.Dispose(); + self.Basic = null; + self.ItemContainer.Dispose(); + self.ItemContainer = null; + self.FishContainer.Dispose(); + self.FishContainer = null; + self.Wallet.Dispose(); + self.Wallet = null; + self.Vip.Dispose(); + self.Vip = null; + self.Statistics.Dispose(); + self.Statistics = null; + + self.SessionRunTimeId = 0; + } +} + +public static class PlayerSystem +{ + +} \ No newline at end of file diff --git a/Hotfix/Game/System/Player/PlayerFactory.cs b/Hotfix/Game/Player/Helper/PlayerFactory.cs similarity index 54% rename from Hotfix/Game/System/Player/PlayerFactory.cs rename to Hotfix/Game/Player/Helper/PlayerFactory.cs index 019f7d4..3d2a611 100644 --- a/Hotfix/Game/System/Player/PlayerFactory.cs +++ b/Hotfix/Game/Player/Helper/PlayerFactory.cs @@ -15,17 +15,10 @@ public static class PlayerFactory /// ToKen令牌传递过来的aId /// 是否在创建的过程中保存到数据库 /// - public static async FTask Create(Scene scene, long aId, bool isSaveDataBase = true) + public static Player Create(Scene scene, long aId) { - var gameAccount = Entity.Create(scene, aId, false, false); - gameAccount.LoginTime = gameAccount.CreateTime = TimeHelper.Now; - - - if (isSaveDataBase) - { - await gameAccount.SaveDataBase(); - } - - return gameAccount; + var player = Entity.Create(scene, aId, true, true); + player.InitializeChildEntity(); + return player; } } \ No newline at end of file diff --git a/Hotfix/Game/System/Player/PlayerHelper.cs b/Hotfix/Game/Player/Helper/PlayerHelper.cs similarity index 70% rename from Hotfix/Game/System/Player/PlayerHelper.cs rename to Hotfix/Game/Player/Helper/PlayerHelper.cs index 8d64f06..fd5aade 100644 --- a/Hotfix/Game/System/Player/PlayerHelper.cs +++ b/Hotfix/Game/Player/Helper/PlayerHelper.cs @@ -1,11 +1,63 @@ using Fantasy; using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Helper; using Fantasy.Network; namespace NB.Game; public static class PlayerHelper { + public static void InitializeChildEntity(this Player self) + { + if (self.Basic == null) + { + self.Basic = Entity.Create(self.Scene, true, true); + } + + if (self.ItemContainer == null) + { + self.ItemContainer = Entity.Create(self.Scene, true, true); + } + + if (self.FishContainer == null) + { + self.FishContainer = Entity.Create(self.Scene, true, true); + } + + if (self.Wallet == null) + { + self.Wallet = Entity.Create(self.Scene, true, true); + } + + if (self.Vip == null) + { + self.Vip = Entity.Create(self.Scene, true, true); + } + + if (self.Statistics == null) + { + self.Statistics = Entity.Create(self.Scene, true, true); + self.Statistics.LoginTime = self.Statistics.CreateTime = TimeHelper.Now; + } + } + + public static async FTask SaveImmediately(this Player self) + { + await self.Scene.World.DataBase.Save(self); + self.NeedSave = false; + Log.Info($"player id:{self.Id} save data to dataBase"); + } + + public static async FTask Save(this Player self) + { + self.NeedSave = true; + self.NeedSaveTime = TimeHelper.Now + PlayerManageComponent.AutoSaveTime; + //先立马保存,后续做缓存 + await self.Scene.World.DataBase.Save(self); + } + + /// /// 从数据库中读取GameAccount /// @@ -24,14 +76,6 @@ public static class PlayerHelper return account; } - /// - /// 保存账号到数据库中 - /// - /// - public static async FTask SaveDataBase(this Player self) - { - await self.Scene.World.DataBase.Save(self); - } /// /// 执行该账号的断开逻辑,不要非必要不要使用这个接口,这个接口是内部使用。 @@ -40,7 +84,7 @@ public static class PlayerHelper public static async FTask Disconnect(this Player self) { // 保存该账号信息到数据库中。 - await SaveDataBase(self); + await SaveImmediately(self); // 在缓存中移除自己,并且执行自己的Dispose方法。 self.Scene.GetComponent().Remove(self.Id); } @@ -59,7 +103,7 @@ public static class PlayerHelper // 如果是心跳检测断开的Session,我怎么能拿到当前的这个账号来进行下线处理呢? // 通过给当前的Session挂载一个组件,当销毁这个Session时候呢,也会销毁这个组件。 // 这样的话,是不是可以在登录的时候,给这个组件把AccountId存到这个组件呢? - + // 要检查当前缓存中是否存在该账号的数据 var gameAccountManageComponent = scene.GetComponent(); if (!gameAccountManageComponent.TryGet(accountId, out var account)) @@ -68,19 +112,23 @@ public static class PlayerHelper Log.Warning($"GameAccountHelper Disconnect accountId : {accountId} not found"); return; } + // 为了防止逻辑的错误,加一个警告来排除下 if (!scene.TryGetEntity(account.SessionRunTimeId, out var session)) { // 如果没有找到对应的Session,那只有一种可能就是当前的链接会话已经断开了,一般的情况下也不会出现的,所以咱们也要打印一个警告。 - Log.Warning($"GameAccountHelper Disconnect accountId : {accountId} SessionRunTimeId : {account.SessionRunTimeId} not found"); + Log.Warning( + $"GameAccountHelper Disconnect accountId : {accountId} SessionRunTimeId : {account.SessionRunTimeId} not found"); return; } + // 如果不存在定时任务的组件,那就添加并设置定时任务 if (account.IsTimeOutComponent()) { // 如果已经存在了,那就表示当然已经有一个延时断开的任务了,那就不需要重复添加了 return; } + // 立即下线处理 if (timeOut <= 0) { @@ -88,6 +136,7 @@ public static class PlayerHelper await account.Disconnect(); return; } + // 设置延迟下线 account.SetTimeout(timeOut, account.Disconnect); } @@ -102,11 +151,11 @@ public static class PlayerHelper // 其实可以不用每次都NEW一个新的GameAccountInfo // 可以在当前账号下创建一个GameAccountInfo,每次变动会提前通知这个GameAccountInfo // 又或者每次调用该方法的时候,把值重新赋值一下。 - + return new GameAccountInfo() { - CreateTime = self.CreateTime, - LoginTime = self.LoginTime + CreateTime = self.Statistics.CreateTime, + LoginTime = self.Statistics.LoginTime }; } } \ No newline at end of file diff --git a/Hotfix/Game/System/ItemManagerComponentSystem.cs b/Hotfix/Game/System/ItemManagerComponentSystem.cs deleted file mode 100644 index feb7270..0000000 --- a/Hotfix/Game/System/ItemManagerComponentSystem.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace NB.Game.System; - -public class ItemManagerComponentSystem -{ - -} \ No newline at end of file diff --git a/Hotfix/Game/System/Player/PlayerAutoSaveComponentSystem.cs b/Hotfix/Game/System/Player/PlayerAutoSaveComponentSystem.cs deleted file mode 100644 index 49410e4..0000000 --- a/Hotfix/Game/System/Player/PlayerAutoSaveComponentSystem.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace NB.Game; - -public class PlayerAutoSaveComponentSystem -{ - -} \ No newline at end of file diff --git a/Hotfix/Game/System/Player/PlayerDestroySystem.cs b/Hotfix/Game/System/Player/PlayerDestroySystem.cs deleted file mode 100644 index 90aa06a..0000000 --- a/Hotfix/Game/System/Player/PlayerDestroySystem.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Fantasy.Entitas.Interface; - -namespace NB.Game; - -public sealed class PlayerDestroySystem : DestroySystem -{ - protected override void Destroy(Player self) - { - self.CreateTime = 0; - self.LoginTime = 0; - self.SessionRunTimeId = 0; - } -} \ No newline at end of file diff --git a/Hotfix/Game/System/PlayerManageComponentSystem.cs b/Hotfix/Game/System/PlayerManageComponentSystem.cs deleted file mode 100644 index c626983..0000000 --- a/Hotfix/Game/System/PlayerManageComponentSystem.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Fantasy.Entitas.Interface; - -namespace NB.Game; - -public sealed class PlayerManageComponentDestroySystem : DestroySystem -{ - protected override void Destroy(PlayerManageComponent self) - { - foreach (var (_, gameAccount) in self.Players) - { - gameAccount.Dispose(); - } - - self.Players.Clear(); - } -} - -public static class PlayerManageComponentSystem -{ - public static void Add(this PlayerManageComponent self, Player account) - { - self.Players.Add(account.Id, account); - } - - public static Player Get(this PlayerManageComponent self, long accountId) - { - return self.Players.GetValueOrDefault(accountId); - } - - public static bool TryGet(this PlayerManageComponent self, long accountId, out Player account) - { - return self.Players.TryGetValue(accountId, out account); - } - - public static void Remove(this PlayerManageComponent self, long accountId, bool isDispose = true) - { - if (!self.Players.Remove(accountId, out var account)) - { - return; - } - - if (!isDispose) - { - return; - } - - account.Dispose(); - } -} \ No newline at end of file diff --git a/Hotfix/Hotfix.csproj b/Hotfix/Hotfix.csproj index 99d72ad..2707d36 100644 --- a/Hotfix/Hotfix.csproj +++ b/Hotfix/Hotfix.csproj @@ -12,8 +12,4 @@ - - - - diff --git a/Server.sln.DotSettings.user b/Server.sln.DotSettings.user index 6c23b67..3bbff5d 100644 --- a/Server.sln.DotSettings.user +++ b/Server.sln.DotSettings.user @@ -8,6 +8,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded