艹
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Nullable>disable</Nullable>
|
||||
<LangVersion>default</LangVersion>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Network;
|
||||
using Fantasy.Network.Interface;
|
||||
using Fantasy.Network.Route;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public sealed class G2M_RequestAddressableIdHandler : RouteRPC<Scene, G2M_RequestAddressableId, M2G_ResponseAddressableId>
|
||||
{
|
||||
protected override async FTask Run(Scene scene, G2M_RequestAddressableId request, M2G_ResponseAddressableId response, Action reply)
|
||||
{
|
||||
// 1、因为是测试代码,所以默认每次请求这个协议我都创建一个新的Unit来做Addressable。
|
||||
var unit = Entity.Create<Unit>(scene, false, true);
|
||||
// 2、给Unit添加AddressableMessageComponent组件,并执行Register(),向AddressableScene注册自己当前的位置。
|
||||
await unit.AddComponent<AddressableMessageComponent>().Register();
|
||||
// 3、返回给Gate服务器AddressableId
|
||||
response.AddressableId = unit.Id;
|
||||
await FTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Network.Interface;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public class G2M_CreateSubSceneRequestHandler : RouteRPC<Scene, G2M_CreateSubSceneRequest, M2G_CreateSubSceneResponse>
|
||||
{
|
||||
protected override async FTask Run(Scene scene, G2M_CreateSubSceneRequest request, M2G_CreateSubSceneResponse response, Action reply)
|
||||
{
|
||||
// 下面的SceneType传的是666,其实并没有这个类型,这个是我随便写的。
|
||||
var subScene = Scene.CreateSubScene(scene, 6666);
|
||||
// 返回subScene的运行时id
|
||||
response.SubSceneRouteId = subScene.RouteId;
|
||||
await FTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Network.Interface;
|
||||
using Fantasy.Network.Route;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public sealed class G2SubScene_AddressableIdRequestHandler : RouteRPC<SubScene, G2SubScene_AddressableIdRequest, SubScene2G_AddressableIdResponse>
|
||||
{
|
||||
protected override async FTask Run(SubScene subScene, G2SubScene_AddressableIdRequest request, SubScene2G_AddressableIdResponse response, Action reply)
|
||||
{
|
||||
Log.Debug($"G2SubScene_AddressableIdRequestHandler {subScene.SceneType}");
|
||||
// 1、因为是测试代码,所以默认每次请求这个协议我都创建一个新的Unit来做Addressable。
|
||||
var unit = Entity.Create<Unit>(subScene, false, true);
|
||||
// 2、给Unit添加AddressableMessageComponent组件,并执行Register(),向AddressableScene注册自己当前的位置。
|
||||
await unit.AddComponent<AddressableMessageComponent>().Register();
|
||||
// 3、返回给Gate服务器AddressableId
|
||||
response.AddressableId = unit.Id;
|
||||
await FTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public class G2SubScene_SentMessageHandler : Route<Scene, G2SubScene_SentMessage>
|
||||
{
|
||||
protected override async FTask Run(Scene scene, G2SubScene_SentMessage message)
|
||||
{
|
||||
Log.Debug($"接受到来自Gate的消息 SceneType:{scene.SceneType} Message:{message.Tag}");
|
||||
await FTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public class OnSceneCreate_Init : AsyncEventSystem<OnCreateScene>
|
||||
// 用于验证JWT是否合法的组件
|
||||
scene.AddComponent<GateJWTComponent>();
|
||||
// 用于管理GameAccount的组件
|
||||
scene.AddComponent<GameAccountManageComponent>();
|
||||
scene.AddComponent<PlayerManageComponent>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public class C2A_LoginRequestHandler : MessageRPC<C2A_LoginRequest, A2C_LoginRes
|
||||
|
||||
session.SetTimeout(3000);
|
||||
var scene = session.Scene;
|
||||
Log.Info($"登录服场景 {scene.Id} {scene.RouteId} {scene.SceneConfigId}");
|
||||
var result = await AuthenticationHelper.Login(scene, request.Username, request.Password);
|
||||
|
||||
if (result.ErrorCode != ErrorCode.Successful && result.AccountId == -1)
|
||||
|
||||
86
Hotfix/Outer/Game/Container/ContainerSystem.cs
Normal file
86
Hotfix/Outer/Game/Container/ContainerSystem.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using Fantasy.Entitas.Interface;
|
||||
|
||||
namespace NB.Game;
|
||||
|
||||
public sealed class ContainerDestroySystem : DestroySystem<Container>
|
||||
{
|
||||
protected override void Destroy(Container self)
|
||||
{
|
||||
self.CellCount = 0;
|
||||
self.CellCountMax = 0;
|
||||
self.CurrentCellCount = 0;
|
||||
|
||||
foreach (var (_, item) in self.Items)
|
||||
{
|
||||
item.Dispose();
|
||||
}
|
||||
|
||||
self.Items.Clear();
|
||||
self.ItemsByCell.Clear();
|
||||
self.ItemsByConfigId.Clear();
|
||||
self.ItemsByType.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ContainerSystem
|
||||
{
|
||||
#region Get
|
||||
|
||||
/// <summary>
|
||||
/// 通过唯一id获取
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetItemById(this Container self, uint id, out Item item)
|
||||
{
|
||||
return self.Items.TryGetValue(id, out item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过格子位置获取物品
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <param name="cell"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetItemByCell(this Container self, uint cell, out Item item)
|
||||
{
|
||||
return self.ItemsByCell.TryGetValue(cell, out item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过配置id获取物品
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <param name="configId"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void GetItemByConfigId(this Container self, uint configId, List<Item> items)
|
||||
{
|
||||
if (!self.ItemsByConfigId.TryGetValue(configId, out var itemList))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
items.AddRange(itemList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过类型获取物品
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void GetItemByType(this Container self, ItemType type, List<Item> items)
|
||||
{
|
||||
if (!self.ItemsByType.TryGetValue((uint)type, out var itemList))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
items.AddRange(itemList);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -9,7 +9,7 @@ public sealed class C2G_GetAccountInfoRequestHandler : MessageRPC<C2G_GetAccount
|
||||
{
|
||||
protected override async FTask Run(Session session, C2G_GetAccountInfoRequest request, G2C_GetAccountInfoResponse response, Action reply)
|
||||
{
|
||||
var gameAccountFlagComponent = session.GetComponent<GameAccountFlagComponent>();
|
||||
var gameAccountFlagComponent = session.GetComponent<PlayerFlagComponent>();
|
||||
|
||||
if (gameAccountFlagComponent == null)
|
||||
{
|
||||
@@ -19,7 +19,7 @@ public sealed class C2G_GetAccountInfoRequestHandler : MessageRPC<C2G_GetAccount
|
||||
return;
|
||||
}
|
||||
|
||||
GameAccount account = gameAccountFlagComponent.Account;
|
||||
Player account = gameAccountFlagComponent.Account;
|
||||
|
||||
if (account == null)
|
||||
{
|
||||
|
||||
@@ -4,8 +4,6 @@ using Fantasy.Async;
|
||||
using Fantasy.Network;
|
||||
using Fantasy.Network.Interface;
|
||||
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
|
||||
namespace NB.Gate.Handler;
|
||||
|
||||
public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_LoginResponse>
|
||||
@@ -22,7 +20,7 @@ public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_L
|
||||
}
|
||||
|
||||
var scene = session.Scene;
|
||||
|
||||
// Log.Info($"网关服场景 {scene.Id} {scene.RouteId} {scene.SceneConfigId} {scene.RouteId} {session.RouteId}");
|
||||
if (!GateJWTHelper.ValidateToken(scene, request.ToKen, out var accountId))
|
||||
{
|
||||
// 如果失败,表示肯定是恶意攻击、所以毫不犹疑,直接断开当前会话。
|
||||
@@ -31,19 +29,19 @@ public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_L
|
||||
}
|
||||
|
||||
// 在缓存中检查该账号是否存在
|
||||
var gameAccountManageComponent = scene.GetComponent<GameAccountManageComponent>();
|
||||
var gameAccountManageComponent = scene.GetComponent<PlayerManageComponent>();
|
||||
Log.Debug("检查账号是否在缓存中");
|
||||
if (!gameAccountManageComponent.TryGet(accountId, out var account))
|
||||
{
|
||||
// 首先要先到数据库中查询是否有这个账号
|
||||
account = await GameAccountHelper.LoadDataBase(scene, accountId);
|
||||
account = await PlayerHelper.LoadDataBase(scene, accountId);
|
||||
// 如果有的话,就直接加入在缓存中就可以了
|
||||
if (account == null)
|
||||
{
|
||||
Log.Debug("检查到账号没有在数据库中,需要创建一个新的账号并且保存到数据库中");
|
||||
// 如果没有,就要创建一个新的并且保存到数据库。
|
||||
// 如果不存在,表示这是一个新的账号,需要创建一下这个账号。
|
||||
account = await GameAccountFactory.Create(scene, accountId);
|
||||
account = await PlayerFactory.Create(scene, accountId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -79,7 +77,7 @@ public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_L
|
||||
// 1、客户端断线重连,要给这个Session发送一个消息,通知它有人登录了。
|
||||
// 2、其他的客户端登录了这个账号,要给这个Session发送一个消息,通知它有人登录了。
|
||||
|
||||
var gameAccountFlagComponent = oldSession.GetComponent<GameAccountFlagComponent>();
|
||||
var gameAccountFlagComponent = oldSession.GetComponent<PlayerFlagComponent>();
|
||||
gameAccountFlagComponent.AccountID = 0;
|
||||
gameAccountFlagComponent.Account = null;
|
||||
// 给客户端发送一个重复登录的消息,如果当前客户端是自己上次登录的,发送也不会收到。
|
||||
@@ -90,7 +88,7 @@ public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_L
|
||||
}
|
||||
|
||||
// 给当前Session添加一个组件,当Session销毁的时候会销毁这个组件。
|
||||
var accountFlagComponent = session.AddComponent<GameAccountFlagComponent>();
|
||||
var accountFlagComponent = session.AddComponent<PlayerFlagComponent>();
|
||||
accountFlagComponent.AccountID = accountId;
|
||||
accountFlagComponent.Account = account;
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
using Fantasy.Entitas.Interface;
|
||||
|
||||
namespace NB.Gate.System;
|
||||
|
||||
public sealed class GameAccountManageComponentDestroySystem : DestroySystem<GameAccountManageComponent>
|
||||
{
|
||||
protected override void Destroy(GameAccountManageComponent self)
|
||||
{
|
||||
foreach (var (_, gameAccount) in self.Accounts)
|
||||
{
|
||||
gameAccount.Dispose();
|
||||
}
|
||||
|
||||
self.Accounts.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static class GameAccountManageComponentSystem
|
||||
{
|
||||
public static void Add(this GameAccountManageComponent self, GameAccount account)
|
||||
{
|
||||
self.Accounts.Add(account.Id, account);
|
||||
}
|
||||
|
||||
public static GameAccount? Get(this GameAccountManageComponent self, long accountId)
|
||||
{
|
||||
return self.Accounts.GetValueOrDefault(accountId);
|
||||
}
|
||||
|
||||
public static bool TryGet(this GameAccountManageComponent self, long accountId, out GameAccount? account)
|
||||
{
|
||||
return self.Accounts.TryGetValue(accountId, out account);
|
||||
}
|
||||
|
||||
public static void Remove(this GameAccountManageComponent self, long accountId, bool isDispose = true)
|
||||
{
|
||||
if (!self.Accounts.Remove(accountId, out var account))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isDispose)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
account.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ using Fantasy.Entitas.Interface;
|
||||
|
||||
namespace NB.Gate;
|
||||
|
||||
public sealed class GameAccountDestroySystem : DestroySystem<GameAccount>
|
||||
public sealed class PlayerDestroySystem : DestroySystem<Player>
|
||||
{
|
||||
protected override void Destroy(GameAccount self)
|
||||
protected override void Destroy(Player self)
|
||||
{
|
||||
self.CreateTime = 0;
|
||||
self.LoginTime = 0;
|
||||
@@ -5,20 +5,20 @@ using Fantasy.Helper;
|
||||
|
||||
namespace NB.Gate;
|
||||
|
||||
public static class GameAccountFactory
|
||||
public static class PlayerFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个新的GameAccount
|
||||
/// 创建一个新的Player
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="aId">ToKen令牌传递过来的aId</param>
|
||||
/// <param name="isSaveDataBase">是否在创建的过程中保存到数据库</param>
|
||||
/// <returns></returns>
|
||||
public static async FTask<GameAccount> Create(Scene scene, long aId, bool isSaveDataBase = true)
|
||||
public static async FTask<Player> Create(Scene scene, long aId, bool isSaveDataBase = true)
|
||||
{
|
||||
var gameAccount = Entity.Create<GameAccount>(scene, aId, false, false);
|
||||
var gameAccount = Entity.Create<Player>(scene, aId, false, false);
|
||||
gameAccount.LoginTime = gameAccount.CreateTime = TimeHelper.Now;
|
||||
|
||||
|
||||
if (isSaveDataBase)
|
||||
{
|
||||
await gameAccount.SaveDataBase();
|
||||
@@ -2,15 +2,15 @@ using Fantasy.Entitas.Interface;
|
||||
|
||||
namespace NB.Gate;
|
||||
|
||||
public sealed class GameAccountFlagComponentDestroySystem : DestroySystem<GameAccountFlagComponent>
|
||||
public sealed class PlayerFlagComponentDestroySystem : DestroySystem<PlayerFlagComponent>
|
||||
{
|
||||
protected override void Destroy(GameAccountFlagComponent self)
|
||||
protected override void Destroy(PlayerFlagComponent self)
|
||||
{
|
||||
if (self.AccountID != 0)
|
||||
{
|
||||
// 执行下线过程、并且要求在5分钟后完成缓存清理。也就是5分钟后会保存数据到数据库。
|
||||
// 由于5分钟太长了、咱们测试的时候,不方便测试,也可以把这个时间改短一些,比如10秒。
|
||||
GameAccountHelper.Disconnect(self.Scene, self.AccountID, 1000 * 60 * 5).Coroutine();
|
||||
PlayerHelper.Disconnect(self.Scene, self.AccountID, 1000 * 60 * 5).Coroutine();
|
||||
self.AccountID = 0;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Fantasy.Network;
|
||||
|
||||
namespace NB.Gate;
|
||||
|
||||
public static class GameAccountHelper
|
||||
public static class PlayerHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 从数据库中读取GameAccount
|
||||
@@ -13,9 +13,9 @@ public static class GameAccountHelper
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="accountId">账号Id</param>
|
||||
/// <returns></returns>
|
||||
public static async FTask<GameAccount?> LoadDataBase(Scene scene, long accountId)
|
||||
public static async FTask<Player?> LoadDataBase(Scene scene, long accountId)
|
||||
{
|
||||
var account = await scene.World.DataBase.First<GameAccount>(d => d.Id == accountId);
|
||||
var account = await scene.World.DataBase.First<Player>(d => d.Id == accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return null;
|
||||
@@ -29,7 +29,7 @@ public static class GameAccountHelper
|
||||
/// 保存账号到数据库中
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
public static async FTask SaveDataBase(this GameAccount self)
|
||||
public static async FTask SaveDataBase(this Player self)
|
||||
{
|
||||
await self.Scene.World.DataBase.Save(self);
|
||||
}
|
||||
@@ -38,12 +38,12 @@ public static class GameAccountHelper
|
||||
/// 执行该账号的断开逻辑,不要非必要不要使用这个接口,这个接口是内部使用。
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
public static async FTask Disconnect(this GameAccount self)
|
||||
public static async FTask Disconnect(this Player self)
|
||||
{
|
||||
// 保存该账号信息到数据库中。
|
||||
await SaveDataBase(self);
|
||||
// 在缓存中移除自己,并且执行自己的Dispose方法。
|
||||
self.Scene.GetComponent<GameAccountManageComponent>().Remove(self.Id);
|
||||
self.Scene.GetComponent<PlayerManageComponent>().Remove(self.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,7 +62,7 @@ public static class GameAccountHelper
|
||||
// 这样的话,是不是可以在登录的时候,给这个组件把AccountId存到这个组件呢?
|
||||
|
||||
// 要检查当前缓存中是否存在该账号的数据
|
||||
var gameAccountManageComponent = scene.GetComponent<GameAccountManageComponent>();
|
||||
var gameAccountManageComponent = scene.GetComponent<PlayerManageComponent>();
|
||||
if (!gameAccountManageComponent.TryGet(accountId, out var account))
|
||||
{
|
||||
// 如果缓存中没有、那表示已经下线或者根本不存在该账号,应该在打印一个警告,因为正常的情况下是不会出现的。
|
||||
@@ -98,7 +98,7 @@ public static class GameAccountHelper
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <returns></returns>
|
||||
public static GameAccountInfo GetGameAccountInfo(this GameAccount self)
|
||||
public static GameAccountInfo GetGameAccountInfo(this Player self)
|
||||
{
|
||||
// 其实可以不用每次都NEW一个新的GameAccountInfo
|
||||
// 可以在当前账号下创建一个GameAccountInfo,每次变动会提前通知这个GameAccountInfo
|
||||
49
Hotfix/Outer/Gate/System/PlayerManageComponentSystem.cs
Normal file
49
Hotfix/Outer/Gate/System/PlayerManageComponentSystem.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Fantasy.Entitas.Interface;
|
||||
|
||||
namespace NB.Gate.System;
|
||||
|
||||
public sealed class PlayerManageComponentDestroySystem : DestroySystem<PlayerManageComponent>
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user