新增角色相关信息

This commit is contained in:
2025-07-28 23:45:46 +08:00
parent be33e12b35
commit 09bbae66d2
68 changed files with 452 additions and 662 deletions

View File

@@ -2,6 +2,6 @@
/é" MultiThread* Addressable2KCP8ˇś@ůUH
&ę" MultiThread* Addressable@<40>VH
(ë" MultiThread*Gate2KCP8 ś@ŤVH
ě" MultiThread*Map@—VH
í" MultiThread*Map@ˇVH
ě" MultiThread*Game@—VH
í" MultiThread*Game@ˇVH
î" MultiThread*Chat@«VH

View File

@@ -1,2 +1,2 @@
$ 测试服" fantasy_main*MongoDB
9 测试服mongodb://127.0.0.1" fantasy_main*MongoDB

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
{"WorksheetNames":[-8419147776733210060,-3495952183970875596,1720330851179383898,3730651590607244245],"Tables":{"-3495952183970875596":1753598025078,"-1088042625810372120":1753532052628,"1720330851179383898":1753532052630,"3730651590607244245":1753532052629,"5812538452563588342":1753532052630}}
{"WorksheetNames":[-8419147776733210060,-3495952183970875596,1720330851179383898,3730651590607244245],"Tables":{"-3495952183970875596":1753712105933,"-1088042625810372120":1753532052628,"1720330851179383898":1753711757684,"3730651590607244245":1753532052629,"5812538452563588342":1753532052630}}

View File

@@ -2,7 +2,7 @@
{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":"KCP","OuterPort":20001,"InnerPort":11001,"SceneType":1},
{"Id":1002,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":null,"OuterPort":0,"InnerPort":11011,"SceneType":2},
{"Id":1003,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Gate","NetworkProtocol":"KCP","OuterPort":20000,"InnerPort":11021,"SceneType":3},
{"Id":1004,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Map","NetworkProtocol":null,"OuterPort":0,"InnerPort":11031,"SceneType":5},
{"Id":1005,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Map","NetworkProtocol":null,"OuterPort":0,"InnerPort":11041,"SceneType":5},
{"Id":1004,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Game","NetworkProtocol":null,"OuterPort":0,"InnerPort":11031,"SceneType":4},
{"Id":1005,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Game","NetworkProtocol":null,"OuterPort":0,"InnerPort":11041,"SceneType":4},
{"Id":1006,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Chat","NetworkProtocol":null,"OuterPort":0,"InnerPort":11051,"SceneType":8}
]}

View File

@@ -1,3 +1,3 @@
{"List":[
{"Id":1,"WorldName":"测试服","DbConnection":null,"DbName":"fantasy_main","DbType":"MongoDB"}
{"Id":1,"WorldName":"测试服","DbConnection":"mongodb://127.0.0.1","DbName":"fantasy_main","DbType":"MongoDB"}
]}

View File

@@ -1,2 +1,13 @@
syntax = "proto3";
package Sining.Message;
///通知游戏服角色进入该游戏服
message G2Game_EnterRequest // IRouteRequest,Game2G_EnterResponse
{
int64 AccountId = 1; //账号id
int64 GateRouteId = 2;//网关路由地址
}
message Game2G_EnterResponse // IRouteResponse
{
int64 RoleRouteId = 1; //角色实体的路由id
}

View File

@@ -0,0 +1,19 @@
syntax = "proto3";
package Fantasy.Network.Message;
/// GameAccount实体类
message RoleBaseInfo
{
string NickName = 1;//昵称
string Head = 2;//头像
string Country = 3;//国家
int32 Level = 4;//等级
int32 Exp = 5;//当前等级
}
///角色信息
message RoleInfo
{
RoleBaseInfo BaseInfo = 1;
int64 RoleId = 2; //账号id
}

View File

@@ -37,12 +37,15 @@ message GameAccountInfo
int64 CreateTime = 1;
int64 LoginTime = 2;
}
/// 拿到当前账号的信息
message C2G_GetAccountInfoRequest // IRequest,G2C_GetAccountInfoResponse
message C2Game_GetRoleInfoRequest // ICustomRouteRequest,Game2C_GetRoleInfoResponse,GameRoute
{
}
message G2C_GetAccountInfoResponse // IResponse
message Game2C_GetRoleInfoResponse // ICustomRouteResponse
{
GameAccountInfo GameAccountInfo = 1;
string Name;
string RoleId;
}

View File

@@ -1,3 +1,4 @@
// Route协议定义(需要定义1000以上、因为1000以内的框架预留)
GateRoute = 1001 // Gate
ChatRoute = 1002 // Chat
ChatRoute = 1002 // Chat
GameRoute = 1003 // Game

View File

@@ -28,7 +28,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Gate\" />
<Folder Include="Map\" />
</ItemGroup>

View File

@@ -5,8 +5,7 @@ namespace NB;
/// <summary>
/// 角色基础数据
/// </summary>
[RoleCom]
public class RoleBasic : Entity
public class PlayerBasic
{
/// <summary>
/// 昵称

View File

@@ -5,7 +5,6 @@ namespace NB;
/// <summary>
/// 角色状态标志量
/// </summary>
[RoleCom]
public class RoleDayFlags : Entity
public class PlayerDayFlags
{
}

View File

@@ -5,8 +5,7 @@ namespace NB;
/// <summary>
/// 角色统计数据
/// </summary>
[RoleCom]
public class RoleStatistics : Entity
public class PlayerStatistics
{
/// <summary>
/// 登录次数

View File

@@ -0,0 +1,30 @@
using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Options;
namespace NB.Game;
public sealed class Player : Entity
{
public long CreateTime;
public long LoginTime;
public PlayerBasic Basic = new PlayerBasic();
public PlayerStatistics Statistics = new PlayerStatistics();
public PlayerDayFlags DayFlags = new PlayerDayFlags();
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<int, int> Currency = new();
[BsonIgnore] public long SessionRunTimeId;
/// <summary>
/// 需要保存数据库
/// </summary>
[BsonIgnore] public bool NeedSave;
/// <summary>
/// 最后保存时间
/// </summary>
[BsonIgnore] public long LastSaveTime;
}

View File

@@ -0,0 +1,8 @@
using Fantasy.Entitas;
namespace NB.Game;
public class PlayerAutoSaveComponent : Entity
{
}

View File

@@ -1,6 +1,6 @@
using Fantasy.Entitas;
namespace NB.Gate;
namespace NB.Game;
public sealed class PlayerManageComponent : Entity
{

View File

@@ -1,15 +0,0 @@
using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Options;
namespace NB;
/// <summary>
/// 角色货币数据
/// </summary>
[RoleCom]
public class RoleCurrency : Entity
{
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<int, int> dic = new();
}

View File

@@ -1,8 +0,0 @@
using Fantasy.Entitas;
namespace NB;
public sealed class Role : Entity
{
}

View File

@@ -1,10 +0,0 @@
using CommandLine;
namespace NB;
/// <summary>
/// 挂这个 玩家Unit创建时会自动添加此组件
/// </summary>
public class RoleComAttribute : BaseAttribute
{
}

View File

@@ -1,11 +0,0 @@
using Fantasy.Entitas;
namespace NB;
public class RoleManagerComponent : Entity
{
/// <summary>
/// 游戏列表
/// </summary>
public readonly Dictionary<long, Role> Roles = new();
}

View File

@@ -1,13 +0,0 @@
using Fantasy.Entitas;
using MongoDB.Bson.Serialization.Attributes;
namespace NB.Gate;
public sealed class Player : Entity
{
public long CreateTime;
public long LoginTime;
[BsonIgnore]
public long SessionRunTimeId;
}

View File

@@ -1,15 +0,0 @@
using Fantasy.Entitas;
namespace NB.Gate;
public sealed class PlayerFlagComponent : Entity
{
public bool Kick { get; set; }
public long AccountID;
// 有一种可能当在Account在其他地方被销毁
// 这时候因为这个Account是会回收到池子中所以这个引用还是有效的
// 那这时候就会出现这个引用的Account可能是其他用户的了。
public EntityReference<Player> Player;
}

View File

@@ -0,0 +1,10 @@
using Fantasy.Entitas;
namespace NB.Gate;
public sealed class SessionPlayerComponent : Entity
{
public bool Kick { get; set; }
public long AccountID;
}

View File

@@ -15,6 +15,53 @@ using Fantasy.Serialize;
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8618
namespace NBC
namespace Fantasy
{
/// <summary>
/// 通知游戏服角色进入该游戏服
/// </summary>
[ProtoContract]
public partial class G2Game_EnterRequest : AMessage, IRouteRequest, IProto
{
public static G2Game_EnterRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<G2Game_EnterRequest>();
}
public override void Dispose()
{
AccountId = default;
GateRouteId = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<G2Game_EnterRequest>(this);
#endif
}
[ProtoIgnore]
public Game2G_EnterResponse ResponseType { get; set; }
public uint OpCode() { return InnerOpcode.G2Game_EnterRequest; }
[ProtoMember(1)]
public long AccountId { get; set; }
[ProtoMember(2)]
public long GateRouteId { get; set; }
}
[ProtoContract]
public partial class Game2G_EnterResponse : AMessage, IRouteResponse, IProto
{
public static Game2G_EnterResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<Game2G_EnterResponse>();
}
public override void Dispose()
{
ErrorCode = default;
RoleRouteId = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<Game2G_EnterResponse>(this);
#endif
}
public uint OpCode() { return InnerOpcode.Game2G_EnterResponse; }
[ProtoMember(1)]
public long RoleRouteId { get; set; }
[ProtoMember(2)]
public uint ErrorCode { get; set; }
}
}

View File

@@ -2,5 +2,7 @@ namespace Fantasy
{
public static partial class InnerOpcode
{
public const uint G2Game_EnterRequest = 1073751825;
public const uint Game2G_EnterResponse = 1207969553;
}
}

View File

@@ -0,0 +1,75 @@
using ProtoBuf;
using System.Collections.Generic;
using MongoDB.Bson.Serialization.Attributes;
using Fantasy;
using Fantasy.Network.Interface;
using Fantasy.Serialize;
// ReSharper disable InconsistentNaming
// ReSharper disable RedundantUsingDirective
// ReSharper disable RedundantOverriddenMember
// ReSharper disable PartialTypeWithSinglePart
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable CheckNamespace
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8618
namespace Fantasy
{
/// <summary>
/// GameAccount实体类
/// </summary>
[ProtoContract]
public partial class RoleBaseInfo : AMessage, IProto
{
public static RoleBaseInfo Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<RoleBaseInfo>();
}
public override void Dispose()
{
NickName = default;
Head = default;
Country = default;
Level = default;
Exp = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<RoleBaseInfo>(this);
#endif
}
[ProtoMember(1)]
public string NickName { get; set; }
[ProtoMember(2)]
public string Head { get; set; }
[ProtoMember(3)]
public string Country { get; set; }
[ProtoMember(4)]
public int Level { get; set; }
[ProtoMember(5)]
public int Exp { get; set; }
}
/// <summary>
/// 角色信息
/// </summary>
[ProtoContract]
public partial class RoleInfo : AMessage, IProto
{
public static RoleInfo Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<RoleInfo>();
}
public override void Dispose()
{
BaseInfo = default;
RoleId = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<RoleInfo>(this);
#endif
}
[ProtoMember(1)]
public RoleBaseInfo BaseInfo { get; set; }
[ProtoMember(2)]
public long RoleId { get; set; }
}
}

View File

@@ -15,7 +15,7 @@ using Fantasy.Serialize;
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8618
namespace NBC
namespace Fantasy
{
[ProtoContract]
public partial class C2A_LoginRequest : AMessage, IRequest, IProto
@@ -149,45 +149,47 @@ namespace NBC
[ProtoMember(2)]
public long LoginTime { get; set; }
}
/// <summary>
/// 拿到当前账号的信息
/// </summary>
[ProtoContract]
public partial class C2G_GetAccountInfoRequest : AMessage, IRequest, IProto
public partial class C2Game_GetRoleInfoRequest : AMessage, ICustomRouteRequest, IProto
{
public static C2G_GetAccountInfoRequest Create(Scene scene)
public static C2Game_GetRoleInfoRequest Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<C2G_GetAccountInfoRequest>();
return scene.MessagePoolComponent.Rent<C2Game_GetRoleInfoRequest>();
}
public override void Dispose()
{
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<C2G_GetAccountInfoRequest>(this);
GetScene().MessagePoolComponent.Return<C2Game_GetRoleInfoRequest>(this);
#endif
}
[ProtoIgnore]
public G2C_GetAccountInfoResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2G_GetAccountInfoRequest; }
public Game2C_GetRoleInfoResponse ResponseType { get; set; }
public uint OpCode() { return OuterOpcode.C2Game_GetRoleInfoRequest; }
[ProtoIgnore]
public int RouteType => Fantasy.RouteType.GameRoute;
}
[ProtoContract]
public partial class G2C_GetAccountInfoResponse : AMessage, IResponse, IProto
public partial class Game2C_GetRoleInfoResponse : AMessage, ICustomRouteResponse, IProto
{
public static G2C_GetAccountInfoResponse Create(Scene scene)
public static Game2C_GetRoleInfoResponse Create(Scene scene)
{
return scene.MessagePoolComponent.Rent<G2C_GetAccountInfoResponse>();
return scene.MessagePoolComponent.Rent<Game2C_GetRoleInfoResponse>();
}
public override void Dispose()
{
ErrorCode = default;
GameAccountInfo = default;
Name = default;
RoleId = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return<G2C_GetAccountInfoResponse>(this);
GetScene().MessagePoolComponent.Return<Game2C_GetRoleInfoResponse>(this);
#endif
}
public uint OpCode() { return OuterOpcode.G2C_GetAccountInfoResponse; }
public uint OpCode() { return OuterOpcode.Game2C_GetRoleInfoResponse; }
[ProtoMember(1)]
public GameAccountInfo GameAccountInfo { get; set; }
public string Name { get; set; }
[ProtoMember(2)]
public string RoleId { get; set; }
[ProtoMember(3)]
public uint ErrorCode { get; set; }
}
}

View File

@@ -7,7 +7,7 @@ namespace Fantasy
public const uint C2G_LoginRequest = 268445458;
public const uint G2C_LoginResponse = 402663186;
public const uint G2C_RepeatLogin = 134227729;
public const uint C2G_GetAccountInfoRequest = 268445459;
public const uint G2C_GetAccountInfoResponse = 402663187;
public const uint C2Game_GetRoleInfoRequest = 2281711377;
public const uint Game2C_GetRoleInfoResponse = 2415929105;
}
}

View File

@@ -5,5 +5,6 @@ namespace Fantasy
{
public const int GateRoute = 1001; // Gate
public const int ChatRoute = 1002; // Chat
public const int GameRoute = 1003; // Game
}
}

View File

@@ -0,0 +1,75 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas;
using Fantasy.Helper;
using Fantasy.Network;
using Fantasy.Network.Interface;
using NB;
using NB.Gate;
namespace NB.Game;
public class G2Game_EnterRequestHandler : RouteRPC<Scene, G2Game_EnterRequest, Game2G_EnterResponse>
{
protected override async FTask Run(Scene scene, G2Game_EnterRequest request, Game2G_EnterResponse response,
Action reply)
{
Log.Debug("收到 G2Game_EnterRequestHandler");
var accountId = request.AccountId;
// 在缓存中检查该账号是否存在
var gameAccountManageComponent = scene.GetComponent<PlayerManageComponent>();
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.Basic.Level = 99;
account.Basic.NickName = "王麻子";
account.Basic.Country = "cn";
account.Basic.Exp = 999;
account.Basic.Head = "xxx.png";
account.NeedSave = true;
}
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;
response.RoleRouteId = account.RuntimeId;
await FTask.CompletedTask;
}
}

View File

@@ -1,49 +0,0 @@
using Fantasy.Entitas.Interface;
namespace NB;
public sealed class RoleManagerComponentDestroySystem : DestroySystem<RoleManagerComponent>
{
protected override void Destroy(RoleManagerComponent self)
{
foreach (var (_, role) in self.Roles)
{
role.Dispose();
}
self.Roles.Clear();
}
}
public static class RoleManagerComponentSystem
{
public static void Add(this RoleManagerComponent self, Role account)
{
self.Roles.Add(account.Id, account);
}
public static Role Get(this RoleManagerComponent self, long accountId)
{
return self.Roles.GetValueOrDefault(accountId);
}
public static bool TryGet(this RoleManagerComponent self, long accountId, out Role account)
{
return self.Roles.TryGetValue(accountId, out account);
}
public static void Remove(this RoleManagerComponent self, long accountId, bool isDispose = true)
{
if (!self.Roles.Remove(accountId, out var account))
{
return;
}
if (!isDispose)
{
return;
}
account.Dispose();
}
}

View File

@@ -0,0 +1,6 @@
namespace NB.Game;
public class PlayerAutoSaveComponentSystem
{
}

View File

@@ -1,6 +1,6 @@
using Fantasy.Entitas.Interface;
namespace NB.Gate;
namespace NB.Game;
public sealed class PlayerDestroySystem : DestroySystem<Player>
{

View File

@@ -2,8 +2,9 @@ using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas;
using Fantasy.Helper;
using NB.Game;
namespace NB.Gate;
namespace NB.Game;
public static class PlayerFactory
{

View File

@@ -1,9 +1,8 @@
using NB.Gate.System;
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
namespace NB.Gate;
namespace NB.Game;
public static class PlayerHelper
{

View File

@@ -1,6 +1,6 @@
using Fantasy.Entitas.Interface;
namespace NB.Gate.System;
namespace NB.Game;
public sealed class PlayerManageComponentDestroySystem : DestroySystem<PlayerManageComponent>
{
@@ -27,7 +27,7 @@ public static class PlayerManageComponentSystem
return self.Players.GetValueOrDefault(accountId);
}
public static bool TryGet(this PlayerManageComponent self, long accountId, out Player? account)
public static bool TryGet(this PlayerManageComponent self, long accountId, out Player account)
{
return self.Players.TryGetValue(accountId, out account);
}

View File

@@ -0,0 +1,32 @@
// using Fantasy;
// using Fantasy.Async;
// using Fantasy.Network;
// using Fantasy.Network.Interface;
//
// namespace NB.Gate;
//
// public sealed class C2G_GetAccountInfoRequestHandler : MessageRPC<C2G_GetAccountInfoRequest, G2C_GetAccountInfoResponse>
// {
// protected override async FTask Run(Session session, C2G_GetAccountInfoRequest request, G2C_GetAccountInfoResponse response, Action reply)
// {
// var gameAccountFlagComponent = session.GetComponent<PlayerFlagComponent>();
//
// if (gameAccountFlagComponent == null)
// {
// // 表示不应该访问这个接口,要先访问登录的接口。
// // response.ErrorCode = 1;
// session.Dispose();
// return;
// }
//
// Player account = gameAccountFlagComponent.Player;
//
// if (account == null)
// {
// // 表示这个Account已经被销毁过了。不是咱们想要的了
// }
//
// response.GameAccountInfo = account.GetGameAccountInfo();
// await FTask.CompletedTask;
// }
// }

View File

@@ -0,0 +1,78 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
using Fantasy.Platform.Net;
namespace NB.Gate.Handler;
public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_LoginResponse>
{
protected override async FTask Run(Session session, C2G_LoginRequest request, G2C_LoginResponse response,
Action reply)
{
if (string.IsNullOrEmpty(request.ToKen))
{
// 1、客户端漏传了 response.ErrorCode = 1;
// 2、恶意攻击导致的 session.Dispose();
session.Dispose();
return;
}
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))
{
// 如果失败,表示肯定是恶意攻击、所以毫不犹疑,直接断开当前会话。
session.Dispose();
return;
}
// 首先需要找到一个需要建立Route的Scene的SceneConfig。
// 例子演示的连接的ChatScene,所以这里我通过SceneConfigData拿到这个SceneConfig。
// 如果是其他Scene用法跟这个没有任何区别。
var gameSceneConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Game)[0];
// 通过chatSceneConfig拿到这个Scene的RouteId
var gameRouteId = gameSceneConfig.RouteId;
//连接到游戏中心服
var gameResponse = (Game2G_EnterResponse)await session.Scene.NetworkMessagingComponent.CallInnerRoute(
gameRouteId, new G2Game_EnterRequest()
{
AccountId = accountId,
GateRouteId = session.RuntimeId
});
if (gameResponse.ErrorCode != 0)
{
// 如果ErrorCode不是0表示请求的协议发生错误应该提示给客户端。
// 这里就不做这个了。
response.ErrorCode = gameResponse.ErrorCode;
return;
}
// 要实现Route协议的转发需要给Session添加一个RouteComponent这个非常重要。
var routeComponent = session.AddComponent<RouteComponent>();
// 需要再Examples/Config/NetworkProtocol/RouteType.Config里添加一个ChatRoute
// 然后点击导表工具会自动生成一个RouteType.cs文件。
// 使用你定义的ChatRoute当routeType的参数传递进去。
// routeResponse会返回一个ChatRouteId这个就是Chat的RouteId。
routeComponent.AddAddress(RouteType.GameRoute, gameResponse.RoleRouteId);
// 这些操作完成后就完成了Route消息的建立。
// 后面可以直接发送Route消息通过Gate自动中转给Chat了。
// 给当前Session添加一个组件当Session销毁的时候会销毁这个组件。
var accountFlagComponent = session.AddComponent<SessionPlayerComponent>();
accountFlagComponent.AccountID = accountId;
// account.SessionRunTimeId = session.RuntimeId;
// response.GameAccountInfo = account.GetGameAccountInfo();
Log.Debug($"当前的Gate服务器:{session.Scene.SceneConfigId} accountId:{accountId}");
Log.Debug($"网关内网连接到游戏服成功 routerId={gameResponse.RoleRouteId}");
}
}

View File

@@ -1,32 +0,0 @@
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
namespace NB.Gate;
public sealed class C2G_GetAccountInfoRequestHandler : MessageRPC<C2G_GetAccountInfoRequest, G2C_GetAccountInfoResponse>
{
protected override async FTask Run(Session session, C2G_GetAccountInfoRequest request, G2C_GetAccountInfoResponse response, Action reply)
{
var gameAccountFlagComponent = session.GetComponent<PlayerFlagComponent>();
if (gameAccountFlagComponent == null)
{
// 表示不应该访问这个接口,要先访问登录的接口。
// response.ErrorCode = 1;
session.Dispose();
return;
}
Player account = gameAccountFlagComponent.Player;
if (account == null)
{
// 表示这个Account已经被销毁过了。不是咱们想要的了
}
response.GameAccountInfo = account.GetGameAccountInfo();
await FTask.CompletedTask;
}
}

View File

@@ -1,101 +0,0 @@
using NB.Gate.System;
using Fantasy;
using Fantasy.Async;
using Fantasy.Network;
using Fantasy.Network.Interface;
namespace NB.Gate.Handler;
public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_LoginResponse>
{
protected override async FTask Run(Session session, C2G_LoginRequest request, G2C_LoginResponse response,
Action reply)
{
if (string.IsNullOrEmpty(request.ToKen))
{
// 1、客户端漏传了 response.ErrorCode = 1;
// 2、恶意攻击导致的 session.Dispose();
session.Dispose();
return;
}
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))
{
// 如果失败,表示肯定是恶意攻击、所以毫不犹疑,直接断开当前会话。
session.Dispose();
return;
}
// 在缓存中检查该账号是否存在
var gameAccountManageComponent = scene.GetComponent<PlayerManageComponent>();
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);
}
else
{
Log.Debug("检查到账号在数据库中");
}
Log.Debug("把当前账号添加到缓存中");
// 把创建完成的Account放入到缓存中
gameAccountManageComponent.Add(account);
}
else
{
Log.Debug("检测到当前账号已经在缓存中了");
// 如果有延迟下线的计划任务,那就先取消一下。
account.CancelTimeout();
// 如果在Gate的缓存中已经存在了该账号那只能以下几种可能:
// 1、同一客户端发送了重复登录的请求数据。
// 2、客户端经历的断线然后又重新连接到这个服务器上了断线重连
// 3、多个客户端同时登录了这个账号顶号
if (session.RuntimeId == account.SessionRunTimeId)
{
// 如果执行到这里,说明是客户端发送了多次登录的请求,这样的情况下,直接返回就可以了,不需要做任何操作。
return;
}
Log.Debug("检测到当前账号的Session不是同一个");
if (scene.TryGetEntity<Session>(account.SessionRunTimeId, out var oldSession))
{
Log.Debug("当前账号的Session在当前的系统中所以需要发送一个重复登录的命令并且要断开这个Session");
// 如果这个Session在当前框架中可以查询到。
// 那表示就是当前的会话还是在存在的,有如下几个可能:
// 1、客户端断线重连要给这个Session发送一个消息通知它有人登录了。
// 2、其他的客户端登录了这个账号要给这个Session发送一个消息通知它有人登录了。
var gameAccountFlagComponent = oldSession.GetComponent<PlayerFlagComponent>();
gameAccountFlagComponent.AccountID = 0;
gameAccountFlagComponent.Player = null;
// 给客户端发送一个重复登录的消息,如果当前客户端是自己上次登录的,发送也不会收到。
oldSession.Send(new G2C_RepeatLogin());
// 给当前Session做一个定时销毁的任务因为不做这个定时销毁直接销毁的话有可能消息还没有发送过去就销毁了
oldSession.SetTimeout(3000);
}
}
// 给当前Session添加一个组件当Session销毁的时候会销毁这个组件。
var accountFlagComponent = session.AddComponent<PlayerFlagComponent>();
accountFlagComponent.AccountID = accountId;
accountFlagComponent.Player = account;
account.SessionRunTimeId = session.RuntimeId;
response.GameAccountInfo = account.GetGameAccountInfo();
Log.Debug($"当前的Gate服务器:{session.Scene.SceneConfigId} accountId:{accountId}");
//连接到游戏中心服
}
}

View File

@@ -2,18 +2,18 @@ using Fantasy.Entitas.Interface;
namespace NB.Gate;
public sealed class PlayerFlagComponentDestroySystem : DestroySystem<PlayerFlagComponent>
public sealed class SessionPlayerComponentDestroySystem : DestroySystem<SessionPlayerComponent>
{
protected override void Destroy(PlayerFlagComponent self)
protected override void Destroy(SessionPlayerComponent self)
{
if (self.AccountID != 0)
{
// 执行下线过程、并且要求在5分钟后完成缓存清理。也就是5分钟后会保存数据到数据库。
// 由于5分钟太长了、咱们测试的时候不方便测试也可以把这个时间改短一些比如10秒。
PlayerHelper.Disconnect(self.Scene, self.AccountID, 1000 * 60 * 5).Coroutine();
self.AccountID = 0;
// PlayerHelper.Disconnect(self.Scene, self.AccountID, 1000 * 60 * 5).Coroutine();
// self.AccountID = 0;
}
self.Player = null;
// self.Player = null;
}
}

View File

@@ -2,6 +2,7 @@
using Fantasy.Async;
using Fantasy.Event;
using NB.Authentication;
using NB.Game;
using NB.Gate;
namespace NB;
@@ -26,14 +27,12 @@ public class OnSceneCreate_Init : AsyncEventSystem<OnCreateScene>
{
// 用于验证JWT是否合法的组件
scene.AddComponent<GateJWTComponent>();
// 用于管理玩家的组件
scene.AddComponent<PlayerManageComponent>();
break;
}
case SceneType.Game:
{
//游戏服用于管理用户的组件
scene.AddComponent<RoleManagerComponent>();
//用于管理玩家的组件
scene.AddComponent<PlayerManageComponent>();
break;
}
}

View File

@@ -38,6 +38,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryPool_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F075adf13af424892b7e940211f3b0a6a24c00_003F44_003Fbf566ef7_003FMemoryPool_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemory_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8bc9cdb23bc146bcaaae0bb9e45e5d46d9dc00_003F47_003F6e33d1b5_003FMemory_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMiMalloc_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F60d0203982134324aae0d2ca760a88a54400_003F2e_003F39679261_003FMiMalloc_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMongoDataBase_002Ecs_002Fl_003AC_0021_003FUsers_003F60527_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fff8cbe4b3c6c469b86633ea0c41accd783200_003F21_003Fa6a0aafd_003FMongoDataBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMongoDataBase_002Ecs_002Fl_003AC_0021_003FUsers_003Fbob_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fef6258830955486e8fb0f971e12b16b183200_003F6e_003F2a3d5471_003FMongoDataBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMvcServiceCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7bc6d1e2e4b14ffd826a34ca3c8eac755a00_003F20_003F93fe3d76_003FMvcServiceCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AOuterReadOnlyMemoryPacketParser_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fef6258830955486e8fb0f971e12b16b183200_003F00_003F8c8caea8_003FOuterReadOnlyMemoryPacketParser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>

View File

@@ -16,7 +16,7 @@ using Fantasy.Serialize;
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8618
namespace NBC
namespace Fantasy
{
#else
using ProtoBuf;

View File

@@ -1,29 +0,0 @@
{
"Export": {
"NetworkProtocolDirectory": {
"Value": "../../Config/NetworkProtocol/",
"Comment": "ProtoBuf文件所在的文件夹位置"
},
"NetworkProtocolServerDirectory": {
"Value": "../../Entity/Generate/NetworkProtocol/",
"Comment": "ProtoBuf生成到服务端的文件夹位置"
},
"NetworkProtocolClientDirectory": {
"Value": "../../../Fishing2/Assets/Scripts/Generate/NetworkProtocol/",
"Comment": "ProtoBuf生成到客户端的文件夹位置"
},
"Serializes": {
"Value": [
// {
// "KeyIndex": 0,
// "NameSpace" : "MemoryPack",
// "SerializeName": "MemoryPack",
// "Attribute": "\t[MemoryPackable]",
// "Ignore": "\t\t[MemoryPackIgnore]",
// "Member": "MemoryPackOrder"
// }
],
"Comment": "自定义序列化器"
}
}
}

View File

@@ -1,264 +0,0 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v8.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v8.0": {
"Fantasy.Tools.NetworkProtocol/1.0.0": {
"dependencies": {
"CommandLineParser": "2.9.1",
"Microsoft.Extensions.Configuration.Json": "9.0.6",
"Newtonsoft.Json": "13.0.3"
},
"runtime": {
"Fantasy.Tools.NetworkProtocol.dll": {}
}
},
"CommandLineParser/2.9.1": {
"runtime": {
"lib/netstandard2.0/CommandLine.dll": {
"assemblyVersion": "2.9.1.0",
"fileVersion": "2.9.1.0"
}
}
},
"Microsoft.Extensions.Configuration/9.0.6": {
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "9.0.6",
"Microsoft.Extensions.Primitives": "9.0.6"
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.Configuration.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"Microsoft.Extensions.Configuration.Abstractions/9.0.6": {
"dependencies": {
"Microsoft.Extensions.Primitives": "9.0.6"
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"Microsoft.Extensions.Configuration.FileExtensions/9.0.6": {
"dependencies": {
"Microsoft.Extensions.Configuration": "9.0.6",
"Microsoft.Extensions.Configuration.Abstractions": "9.0.6",
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.6",
"Microsoft.Extensions.FileProviders.Physical": "9.0.6",
"Microsoft.Extensions.Primitives": "9.0.6"
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"Microsoft.Extensions.Configuration.Json/9.0.6": {
"dependencies": {
"Microsoft.Extensions.Configuration": "9.0.6",
"Microsoft.Extensions.Configuration.Abstractions": "9.0.6",
"Microsoft.Extensions.Configuration.FileExtensions": "9.0.6",
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.6",
"System.Text.Json": "9.0.6"
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"Microsoft.Extensions.FileProviders.Abstractions/9.0.6": {
"dependencies": {
"Microsoft.Extensions.Primitives": "9.0.6"
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"Microsoft.Extensions.FileProviders.Physical/9.0.6": {
"dependencies": {
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.6",
"Microsoft.Extensions.FileSystemGlobbing": "9.0.6",
"Microsoft.Extensions.Primitives": "9.0.6"
},
"runtime": {
"lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"Microsoft.Extensions.FileSystemGlobbing/9.0.6": {
"runtime": {
"lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"Microsoft.Extensions.Primitives/9.0.6": {
"runtime": {
"lib/net8.0/Microsoft.Extensions.Primitives.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"Newtonsoft.Json/13.0.3": {
"runtime": {
"lib/net6.0/Newtonsoft.Json.dll": {
"assemblyVersion": "13.0.0.0",
"fileVersion": "13.0.3.27908"
}
}
},
"System.IO.Pipelines/9.0.6": {
"runtime": {
"lib/net8.0/System.IO.Pipelines.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"System.Text.Encodings.Web/9.0.6": {
"runtime": {
"lib/net8.0/System.Text.Encodings.Web.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
},
"runtimeTargets": {
"runtimes/browser/lib/net8.0/System.Text.Encodings.Web.dll": {
"rid": "browser",
"assetType": "runtime",
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
},
"System.Text.Json/9.0.6": {
"dependencies": {
"System.IO.Pipelines": "9.0.6",
"System.Text.Encodings.Web": "9.0.6"
},
"runtime": {
"lib/net8.0/System.Text.Json.dll": {
"assemblyVersion": "9.0.0.0",
"fileVersion": "9.0.625.26613"
}
}
}
}
},
"libraries": {
"Fantasy.Tools.NetworkProtocol/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"CommandLineParser/2.9.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==",
"path": "commandlineparser/2.9.1",
"hashPath": "commandlineparser.2.9.1.nupkg.sha512"
},
"Microsoft.Extensions.Configuration/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-VWB5jdkxHsRiuoniTqwOL32R4OWyp5If/bAucLjRJczRVNcwb8iCXKLjn3Inv8fv+jHMVMnvQLg7xhSys+y5PA==",
"path": "microsoft.extensions.configuration/9.0.6",
"hashPath": "microsoft.extensions.configuration.9.0.6.nupkg.sha512"
},
"Microsoft.Extensions.Configuration.Abstractions/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3GgMIi2jP8g1fBW93Z9b9Unamc0SIsgyhiCmC91gq4loTixK9vQMuxxUsfJ1kRGwn+/FqLKwOHqmn0oYWn3Fvw==",
"path": "microsoft.extensions.configuration.abstractions/9.0.6",
"hashPath": "microsoft.extensions.configuration.abstractions.9.0.6.nupkg.sha512"
},
"Microsoft.Extensions.Configuration.FileExtensions/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-pCEueasI5JhJ24KYzMFxtG40zyLnWpcQYawpARh9FNq9XbWozuWgexmdkPa8p8YoVNlpi3ecKfcjfoRMkKAufw==",
"path": "microsoft.extensions.configuration.fileextensions/9.0.6",
"hashPath": "microsoft.extensions.configuration.fileextensions.9.0.6.nupkg.sha512"
},
"Microsoft.Extensions.Configuration.Json/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-N0dgOYQ9tDzJouL9Tyx2dgMCcHV2pBaY8yVtorbDqYYwiDRS2zd1TbhTA2FMHqXF3SMjBoO+gONZcDoA79gdSA==",
"path": "microsoft.extensions.configuration.json/9.0.6",
"hashPath": "microsoft.extensions.configuration.json.9.0.6.nupkg.sha512"
},
"Microsoft.Extensions.FileProviders.Abstractions/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-q9FPkSGVA9ipI255p3PBAvWNXas5Tzjyp/DwYSwT+46mIFw9fWZahsF6vHpoxLt5/vtANotH2sAm7HunuFIx9g==",
"path": "microsoft.extensions.fileproviders.abstractions/9.0.6",
"hashPath": "microsoft.extensions.fileproviders.abstractions.9.0.6.nupkg.sha512"
},
"Microsoft.Extensions.FileProviders.Physical/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-l+dFA0NRl90vSIiJNy5d7V0kpTEOWHTqbgoWYzlTwF5uiM5sWJ953haaELKE05jkyJdnemVTnqjrlgo4wo7oyg==",
"path": "microsoft.extensions.fileproviders.physical/9.0.6",
"hashPath": "microsoft.extensions.fileproviders.physical.9.0.6.nupkg.sha512"
},
"Microsoft.Extensions.FileSystemGlobbing/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-1HJCAbwukNEoYbHgHbKHmenU0V/0huw8+i7Qtf5rLUG1E+3kEwRJQxpwD3wbTEagIgPSQisNgJTvmUX9yYVc6g==",
"path": "microsoft.extensions.filesystemglobbing/9.0.6",
"hashPath": "microsoft.extensions.filesystemglobbing.9.0.6.nupkg.sha512"
},
"Microsoft.Extensions.Primitives/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-BHniU24QV67qp1pJknqYSofAPYGmijGI8D+ci9yfw33iuFdyOeB9lWTg78ThyYLyQwZw3s0vZ36VMb0MqbUuLw==",
"path": "microsoft.extensions.primitives/9.0.6",
"hashPath": "microsoft.extensions.primitives.9.0.6.nupkg.sha512"
},
"Newtonsoft.Json/13.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==",
"path": "newtonsoft.json/13.0.3",
"hashPath": "newtonsoft.json.13.0.3.nupkg.sha512"
},
"System.IO.Pipelines/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-0nlr0reXrRmkZNKifKqh2DgGhQgfkT7Qa3gQxIn/JI7/y3WDiTz67M+Sq3vFhUqcG8O5zVrpqHvIHeGPGUBsEw==",
"path": "system.io.pipelines/9.0.6",
"hashPath": "system.io.pipelines.9.0.6.nupkg.sha512"
},
"System.Text.Encodings.Web/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-uWRgViw2yJAUyGxrzDLCc6fkzE2dZIoXxs8V6YjCujKsJuP0pnpYSlbm2/7tKd0SjBnMtwfDQhLenk3bXonVOA==",
"path": "system.text.encodings.web/9.0.6",
"hashPath": "system.text.encodings.web.9.0.6.nupkg.sha512"
},
"System.Text.Json/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-h+ZtYTyTnTh5Ju6mHCKb3FPGx4ylJZgm9W7Y2psUnkhQRPMOIxX+TCN0ZgaR/+Yea+93XHWAaMzYTar1/EHIPg==",
"path": "system.text.json/9.0.6",
"hashPath": "system.text.json.9.0.6.nupkg.sha512"
}
}
}

View File

@@ -1,12 +0,0 @@
{
"runtimeOptions": {
"tfm": "net8.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "8.0.0"
},
"configProperties": {
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}

View File

@@ -1,23 +0,0 @@
@echo off
echo Please select an option:
echo 1. Client
echo 2. Server
echo 3. All
set /p choice=Please select an option:
if "%choice%"=="1" (
echo Client
dotnet Fantasy.Tools.NetworkProtocol.dll --p 1
) else if "%choice%"=="2" (
echo Server
dotnet Fantasy.Tools.NetworkProtocol.dll --p 2
) else if "%choice%"=="3" (
echo All
dotnet Fantasy.Tools.NetworkProtocol.dll --p 3
) else (
echo Invalid option
)
PAUSE

View File

@@ -1,24 +0,0 @@
#!/bin/bash
echo "1. Client"
echo "2. Server"
echo "3. All"
read -n 1 -p "Please select an option:" choice
echo ""
echo ""
script_dir=$(cd $(dirname $0) && pwd)
case $choice in
1)
dotnet $script_dir/Fantasy.Tools.NetworkProtocol.dll --p 1 --f $script_dir
;;
2)
dotnet $script_dir/Fantasy.Tools.NetworkProtocol.dll --p 2 --f $script_dir
;;
3)
dotnet $script_dir/Fantasy.Tools.NetworkProtocol.dll --p 3 --f $script_dir
;;
*)
echo "Invalid option"
;;
esac