using Fantasy; using Fantasy.Async; using Fantasy.Entitas; using Fantasy.Helper; using Fantasy.Network; namespace NB.Game; public static class PlayerHelper { #region 数据保存 public static async FTask Save(this Player self) { //先立马保存,后续做缓存 await self.Scene.World.Database.Save(self); } /// /// 从数据库中读取GameAccount /// /// /// 账号Id /// public static async FTask LoadDataBase(Scene scene, long accountId) { var account = await scene.World.Database.First(d => d.Id == accountId); if (account == null) { return null; } account.Deserialize(scene); return account; } /// /// 执行该账号的断开逻辑,不要非必要不要使用这个接口,这个接口是内部使用。 /// /// public static async FTask Disconnect(this Player self) { // 保存该账号信息到数据库中。 await Save(self); var itemContainer = self.GetComponent(); if (itemContainer != null) { await itemContainer.Save(); } var wallet = self.GetComponent(); if (wallet != null) { await wallet.Save(); } // 在缓存中移除自己,并且执行自己的Dispose方法。 self.Scene.GetComponent().Remove(self.Id); } /// /// 账号完整的断开逻辑,执行了这个接口后,该账号会完全下线。 /// /// /// /// public static async FTask Disconnect(Scene scene, long accountId, int timeOut = 1000 * 60 * 3) { // 调用该方法有如下几种情况: // 1、客户端主动断开,如:退出游戏、切换账号、等。 客户端会主动发送一个协议给服务器通知服务器断开。 // 2、客户端断断线 客户端不会主动发送一个协议给服务器,是由服务器的心跳来检测是否断开了。 // 如果是心跳检测断开的Session,我怎么能拿到当前的这个账号来进行下线处理呢? // 通过给当前的Session挂载一个组件,当销毁这个Session时候呢,也会销毁这个组件。 // 这样的话,是不是可以在登录的时候,给这个组件把AccountId存到这个组件呢? // 要检查当前缓存中是否存在该账号的数据 var gameAccountManageComponent = scene.GetComponent(); if (!gameAccountManageComponent.TryGet(accountId, out var account)) { // 如果缓存中没有、那表示已经下线或者根本不存在该账号,应该在打印一个警告,因为正常的情况下是不会出现的。 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"); return; } // 如果不存在定时任务的组件,那就添加并设置定时任务 if (account.IsTimeOutComponent()) { // 如果已经存在了,那就表示当然已经有一个延时断开的任务了,那就不需要重复添加了 return; } // 立即下线处理 if (timeOut <= 0) { // 如果timeOut销毁或等会0的情况下,执行立即下线。 await account.Disconnect(); return; } // 设置延迟下线 account.SetTimeout(timeOut, account.Disconnect); } #endregion #region 结构转换 public static RoleSimpleInfo GetRoleSimpleInfo(this Player self) { return new RoleSimpleInfo() { RoleId = self.Id, NickName = self.NickName, Head = self.Head, Country = self.Country, Level = self.Level, Vip = self.Vip, }; } public static RoleInfo GetRoleInfo(this Player self) { var info = new RoleInfo(); info.BaseInfo = GetRoleBaseInfo(self); // info.Items = self.ItemContainer.GetItemInfos(); info.RoleId = self.Address; return info; } public static RoleBaseInfo GetRoleBaseInfo(this Player self) { var ret = new RoleBaseInfo() { NickName = self.NickName, Head = self.Head, Country = self.Country, Level = self.Level, Exp = self.Exp, }; if (self.Vip > 0) { ret.VipInfo = new VipInfo(); ret.VipInfo.Level = self.Vip; ret.VipInfo.OpenTime = self.VipGetTime; ret.VipInfo.ExpirationTime = self.VipExpirationTime; } return ret; } #endregion }