175 lines
5.4 KiB
C#
175 lines
5.4 KiB
C#
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<PlayerManageComponent>
|
||
{
|
||
protected override void Awake(PlayerManageComponent self)
|
||
{
|
||
self.AutoSaveTimerId =
|
||
self.Scene.TimerComponent.Net.RepeatedTimer(1000 * 60, () => { _ = self.CheckAutoSave(); });
|
||
}
|
||
}
|
||
|
||
public sealed class PlayerManageComponentDestroySystem : DestroySystem<PlayerManageComponent>
|
||
{
|
||
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 上线下线
|
||
|
||
/// <summary>
|
||
/// 玩家上线
|
||
/// </summary>
|
||
/// <param name="self"></param>
|
||
/// <param name="accountId"></param>
|
||
/// <param name="gateRouteId"></param>
|
||
public static async FTask<Player?> Online(this PlayerManageComponent self, long accountId, long gateRouteId)
|
||
{
|
||
Log.Debug("检查账号是否在缓存中");
|
||
if (!self.TryGet(accountId, out var account))
|
||
{
|
||
// 首先要先到数据库中查询是否有这个账号
|
||
account = await PlayerHelper.LoadDataBase(self.Scene, accountId);
|
||
// 如果有的话,就直接加入在缓存中就可以了
|
||
if (account == null)
|
||
{
|
||
Log.Debug("检查到账号没有在数据库中,需要创建一个新的账号并且保存到数据库中");
|
||
// 如果没有,就要创建一个新的并且保存到数据库。
|
||
// 如果不存在,表示这是一个新的账号,需要创建一下这个账号。
|
||
account = PlayerFactory.Create(self.Scene, accountId);
|
||
|
||
|
||
account.Level = 99;
|
||
account.NickName = "王麻子";
|
||
account.Country = "cn";
|
||
account.Exp = 999;
|
||
account.Head = "xxx.png";
|
||
|
||
// for (int i = 0; i < 500; i++)
|
||
// {
|
||
// var item = Entity.Create<Item>(scene, true, true);
|
||
// account.ItemContainer.Add(item.Id, item);
|
||
// }
|
||
//
|
||
// for (int i = 0; i < 500; i++)
|
||
// {
|
||
// var item = Entity.Create<Fish>(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;
|
||
|
||
await account.Save();
|
||
|
||
return account;
|
||
}
|
||
|
||
public static async FTask Offline(this PlayerManageComponent self, long accountId, long sessionId)
|
||
{
|
||
if (self.TryGet(accountId, out var account))
|
||
{
|
||
if (account.SessionRunTimeId == sessionId)
|
||
{
|
||
//退出的是当前的
|
||
await account.Save();
|
||
self.Remove(accountId);
|
||
}
|
||
}
|
||
}
|
||
|
||
#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
|
||
} |