From 70bfe43a801e59b3ceb3b31bb6f77290a55fec3a Mon Sep 17 00:00:00 2001 From: BobSong <605277374@qq.com> Date: Thu, 7 Aug 2025 09:16:23 +0800 Subject: [PATCH] chat --- .../NetworkProtocol/Outer/OuterMessage.proto | 24 +++++- Config/private_key.pem | 28 +++++++ Config/public_key.pem | 9 ++ Config/密钥20250805230750/应用公钥RSA2048.txt | 1 + .../应用私钥RSA2048-敏感数据,请妥善保管.txt | 1 + Entity/Authentication/Entity/Account.cs | 1 + Entity/Def/RegionDef.cs | 29 +++++++ Entity/Game/Player/PlayerManageComponent.cs | 5 -- Entity/Gate/GateUnit.cs | 14 ++++ Entity/Gate/GateUnitManageComponent.cs | 9 ++ Entity/Gate/GateUnitSessionComponent.cs | 8 ++ Entity/Gate/SessionPlayerComponent.cs | 10 --- .../Generate/NetworkProtocol/OuterMessage.cs | 72 ++++++++++++++++ .../Generate/NetworkProtocol/OuterOpcode.cs | 3 + Entity/Model/Def/ErrorCode.cs | 10 +++ .../Core/Entitas/Component/EntityComponent.cs | 4 + .../Handler/C2A_LoginRequestHandler.cs | 8 +- Hotfix/Authentication/System/AccountSystem.cs | 1 + .../System/AuthenticationComponentSystem.cs | 25 +++--- .../System/AuthenticationHelper.cs | 9 +- .../Jwt/AuthenticationJwtComponentSystem.cs | 13 +-- .../System/Jwt/AuthenticationJwtHelper.cs | 5 +- .../C2Chat_SendMessageRequestHandler.cs | 15 ++++ Hotfix/Chat/Helper/ChatSceneHelper.cs | 29 +++++++ Hotfix/Game/Helper/GameSceneHelper.cs | 16 ++++ .../C2G_GetAccountInfoRequestHandler.cs | 32 -------- .../Gate/Handler/C2G_LoginRequestHandler.cs | 82 +++++++++---------- Hotfix/Gate/Helper/GateLoginHelper.cs | 75 +++++++++++++++++ .../System/GateUnitManageComponentSystem.cs | 55 +++++++++++++ .../System/GateUnitSessionComponentSystem.cs | 17 ++++ Hotfix/Gate/System/GateUnitSystem.cs | 16 ++++ .../Gate/System/PlayerFlagComponentSystem.cs | 38 ++++----- Hotfix/OnSceneCreate_Init.cs | 2 + Server.sln.DotSettings.user | 1 + 34 files changed, 532 insertions(+), 135 deletions(-) create mode 100644 Config/private_key.pem create mode 100644 Config/public_key.pem create mode 100644 Config/密钥20250805230750/应用公钥RSA2048.txt create mode 100644 Config/密钥20250805230750/应用私钥RSA2048-敏感数据,请妥善保管.txt create mode 100644 Entity/Def/RegionDef.cs create mode 100644 Entity/Gate/GateUnit.cs create mode 100644 Entity/Gate/GateUnitManageComponent.cs create mode 100644 Entity/Gate/GateUnitSessionComponent.cs delete mode 100644 Entity/Gate/SessionPlayerComponent.cs create mode 100644 Hotfix/Chat/Handler/C2Chat_SendMessageRequestHandler.cs create mode 100644 Hotfix/Chat/Helper/ChatSceneHelper.cs create mode 100644 Hotfix/Game/Helper/GameSceneHelper.cs delete mode 100644 Hotfix/Gate/Handler/C2G_GetAccountInfoRequestHandler.cs create mode 100644 Hotfix/Gate/Helper/GateLoginHelper.cs create mode 100644 Hotfix/Gate/System/GateUnitManageComponentSystem.cs create mode 100644 Hotfix/Gate/System/GateUnitSessionComponentSystem.cs create mode 100644 Hotfix/Gate/System/GateUnitSystem.cs diff --git a/Config/NetworkProtocol/Outer/OuterMessage.proto b/Config/NetworkProtocol/Outer/OuterMessage.proto index c347b24..224e1dc 100644 --- a/Config/NetworkProtocol/Outer/OuterMessage.proto +++ b/Config/NetworkProtocol/Outer/OuterMessage.proto @@ -1,5 +1,8 @@ syntax = "proto3"; package Fantasy.Network.Message; + + + // 协议分为: // ProtoBuf:可以在Outer和Inner文件里使用。 // MemoryPack:可以在Outer和Inner文件里使用。 @@ -11,12 +14,14 @@ message C2A_LoginRequest // IRequest,A2C_LoginResponse { string Username = 1; string Password = 2; - int32 LoginType = 3; + int32 LoginType = 3; //登录方式 + int32 Region = 4; //登录地区,如果是注册,则必须传入 } message A2C_LoginResponse // IResponse { string ToKen = 1; } + /// 客户端登录到Gate服务器 message C2G_LoginRequest // IRequest,G2C_LoginResponse { @@ -71,4 +76,21 @@ message Game2C_MailState // ICustomRouteMessage,GameRoute { int32 MailState = 1; int64 MailId = 2; +} + +///发送聊天 +message C2Chat_SendMessageRequest // ICustomRouteRequest,Caht2C_SendMessageResponse,ChatRoute +{ + string Message = 1; +} +///发送聊天响应 +message Caht2C_SendMessageResponse // ICustomRouteResponse +{ + +} + +///推送消息 +message Chat2C_Message // ICustomRouteMessage,ChatRoute +{ + string Message = 1; } \ No newline at end of file diff --git a/Config/private_key.pem b/Config/private_key.pem new file mode 100644 index 0000000..8e1c59b --- /dev/null +++ b/Config/private_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPgvJvOMVwyzhw +CjMXpmuopnsiPVt5OCAlYa4u32MxLbQ/hzGWt5BEnJtrzlHRzgI20Z5pNtco6w5R +JU26y+RixmcNp28kWIVmHKA457HiexdamnThdDVGjsTZ98BZHQNWAdmlR0AWjyaF +Se0w/7qBDLgebn+OENxKfga10i7jVgVfwtomTDBwFl2dDwL+rYVxrt7iWFtAvJ6b +aV9UAjmNXvy/MH9pIBUOAJ6mvDkq/wNSTTrBX1Kun/M7axoheaZ5fDbdLrHnOEew +LAjsncRl1+XXwEbhHa7UQk4qa7DJhUQkx61CT2WS1+q45g2Z0N5Caop+CpVZPWBd +yNkLbedNAgMBAAECggEAM7LwYxjeCfK7giBsZ8NA1cD6cwad3FbJHX8XVhq2HAnC +u0QbrOzZTtrElwiNVmvQnec+JADzfICJbdqRIc2L/jbndF2nYUMDozPVEDBbX21i +3WIXZhcdcdF+hj6FJ76EdwBZgOW+OBCcnH8VTsybouywD3bgpRyawZ1h3xk5MM5p +udZBTv6pHJu4KDCWBziWyLFAFOd2u9NgaRxeHbpq09AvwHyjXK5bKTwOCWFNW9mj +FHGo0Pk7hYeYVGa3HktIQ3oAiMiyKLdeB/4SZc35RH6wWGOhLi1jqDgAKuTzVMt+ +jDWh6ozggEVx8NCrEWtZpSsxlBhWDfxzZd1lFOwMAQKBgQD4KaybHNCPLmJhg8fS +J5MhJZBEfyE5fenrMjftLI7c4wo805idggk8c6mBERstYjLPg+hDnjoQHZmy8i0I +MLfebH2ts+tqyx12gmKC7zRjNfEBW3QjH8mH5Lq0bF9cPrZj7AVDpzxCAuB9xGfn +WwvuNdcx1cWGgAl5zE5CcfvbTQKBgQDWEJ5kHRH39tXbz0Mqbj3CXKsCskZvqSGt +4WH35Jx7lZV1iIU/IL+mmQcZLALczOTRuN0Vq3LcyoZSaS/3d3OQEsKKYzJGZNOg +nqtS4v2sO/ywSBpduw5cQfZrmOk3x4v1CTzsx6IhCCZFR5S9kWrnqSCVzdtvasnV +z3zq3Dw8AQKBgQCaXGnGDhVYipSdbXgUq5MkEhZ71MwY0852AsWw3H98vCi5DzEm +ACW4mYU9CCPsheFvHPCTZs9dCNx655LFPnCQhNFkA78SrYcFGTMnmJzwfTQNERLb +akFUKx1LbwGeAlA3NS9NFrAvq1RyRoIO8Z4pLQpPMFZuRCQgw8mGIRp1HQKBgQCc +EW+5Y+xm0cKnyJuagtdqLi/L/ngWDsRsRmcr2bQw8iUOlOM43EJ+TxF6y7imjIfD +U7l0hBRxXwLBcMk07hUGFHdbd+j+o6Ibd7NG8hGqke2wBFGcxrU4lCr51XkrXsPu +eba+lunglVV5qy+Jakz76zXDolt7ButyhBz6CmmsAQKBgHVDjpIGsyojxq19OtLm +xm3GuK2/+9VruRJ9B4yX2uwj2+x53rCxV6zWkBDMJtjyUjb7epz4xkau73KYoncR +B9om+4Nmo+R/p3ACgGjMDoaadyUD1hVM4R+d4VqNv3Ck7YPd/Ehiz3uZRD4njo8D +w7xwwzHNjgpL5+xeiMsaUOL9 +-----END PRIVATE KEY----- diff --git a/Config/public_key.pem b/Config/public_key.pem new file mode 100644 index 0000000..8c2fea3 --- /dev/null +++ b/Config/public_key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz4LybzjFcMs4cAozF6Zr +qKZ7Ij1beTggJWGuLt9jMS20P4cxlreQRJyba85R0c4CNtGeaTbXKOsOUSVNusvk +YsZnDadvJFiFZhygOOex4nsXWpp04XQ1Ro7E2ffAWR0DVgHZpUdAFo8mhUntMP+6 +gQy4Hm5/jhDcSn4GtdIu41YFX8LaJkwwcBZdnQ8C/q2Fca7e4lhbQLyem2lfVAI5 +jV78vzB/aSAVDgCeprw5Kv8DUk06wV9Srp/zO2saIXmmeXw23S6x5zhHsCwI7J3E +Zdfl18BG4R2u1EJOKmuwyYVEJMetQk9lktfquOYNmdDeQmqKfgqVWT1gXcjZC23n +TQIDAQAB +-----END PUBLIC KEY----- diff --git a/Config/密钥20250805230750/应用公钥RSA2048.txt b/Config/密钥20250805230750/应用公钥RSA2048.txt new file mode 100644 index 0000000..687589b --- /dev/null +++ b/Config/密钥20250805230750/应用公钥RSA2048.txt @@ -0,0 +1 @@ +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj6EL7hSzceNVL5NFa8HLhtqvxEUHSVh8ChDRhHmltDyZ7pdsesiOBPS2lU++LztOrwNv4Q4KyUnoJ2OPHZAObaZyxXMW89SDJo8hkfx7mgPxhCtLxazcnBBoq+FVEbV24hRlYYpXpEkc2gAu7EmnphnCLpsMLn1WP2d+URxCNbHxy8IKD6Cl9NErKTgbmm5AB0bL+fd2vtxH/u3rVPBHM7Cu3rO37NjsUdY62nE88+IBp6jLT099F7ixz2mVqFeCvubnWv8vowl0Sj9zOhx+xz+h9UjysnJA0fPK6xl0s2ArGfGmNJNHQncAPxDj8t7t4/8oJr4oBiYrw4TChMikmwIDAQAB \ No newline at end of file diff --git a/Config/密钥20250805230750/应用私钥RSA2048-敏感数据,请妥善保管.txt b/Config/密钥20250805230750/应用私钥RSA2048-敏感数据,请妥善保管.txt new file mode 100644 index 0000000..98577a5 --- /dev/null +++ b/Config/密钥20250805230750/应用私钥RSA2048-敏感数据,请妥善保管.txt @@ -0,0 +1 @@ +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCPoQvuFLNx41Uvk0VrwcuG2q/ERQdJWHwKENGEeaW0PJnul2x6yI4E9LaVT74vO06vA2/hDgrJSegnY48dkA5tpnLFcxbz1IMmjyGR/HuaA/GEK0vFrNycEGir4VURtXbiFGVhilekSRzaAC7sSaemGcIumwwufVY/Z35RHEI1sfHLwgoPoKX00SspOBuabkAHRsv593a+3Ef+7etU8EczsK7es7fs2OxR1jracTzz4gGnqMtPT30XuLHPaZWoV4K+5uda/y+jCXRKP3M6HH7HP6H1SPKyckDR88rrGXSzYCsZ8aY0k0dCdwA/EOPy3u3j/ygmvigGJivDhMKEyKSbAgMBAAECggEAdMsUlGko8jdWEfXDwbg49FPoEcXAAxh85QKAHSV+ZW3SDn37rGxhcA4+WnQZxvaHKTG2TF/KzZvXuA/xVKzLzsZHFeBcjbIFY9mIBto0+Cy0vDEo0Hmcexuswffd4SSao4TKW+LPGbyKRYtYnLPYK+1ORe+2nCc3dx+FTBeaj2X9d1d4f1PsdvNrPEkNz+p+dhY/g9Gm7FyS3WLSnUt0j25m3p+fvxvUInwhLBE9fyUlP2t/wHXOkd/KR1ncw5HebYK/dgN1RSa/izXmfFpKGGfxb4o5ZeYJgzvn5nkJHfBerki+5nuYhlcXm4qJn95V8LZ8yixSq7hTNy3tJx4CYQKBgQD32JI579iw2F/fLKwjnv1o61uLQJYvGB8JsWACVdny5kJt+AJaggCHNhMUOLgj1/Gywt6V9CEUhCminxIKC5gW12HfQtV6L9/lyA3ymND5lyWZKFqvLlksHqyvqlyK31uLm6UE4nP6NQ+NWfo5ue6gS1vp/wvhiM3LOFsPxDNgzQKBgQCUWrs3wX3YvHIODu8bgYBpgSin6tpNIxm1iojHnp5XtXcP5fNgOpRb0QjJjckdpFoLvCWURybhhDbJDwDiucm69RlT1fkKeQrAeiKpEQuKySN1xUjqQyKYVd4LKJl7rJT7RSgxar5nsbF5dCb98wj8TXeKeTNbYEI6O0MKhVj7BwKBgBpjot4sXYQm5b5bgVChoxXCyZKAI/2LsfJUQoa9IWGthrEy0P1WDjxXU5y5lVGrsn54JT8OKV+H2u8HxOHw7hawhClDcnt6EXrj3ChSgR2yLDysgUtZwgDimzxxBT18HsE0p1Nn0TV45NkGFZCD7ZZ/r5+wmlE/Qbo7m+aH23iZAoGAMHTKPdXnYwl6P3lFRDiyVsOnIeGl2Bgk55UORBVdJszQzNKRAddgafUG5751+EacWsTjiWEMJBDpTBaodWW1rGkuEqILLA6JIoFCHPLCUFyORoNf45R2EkfJtN9X8ntWVhQqoql486mojEESE1R0lORArWwVCD2SpC6DIUaY37UCgYAHbSfZUUeDMHlVMF6ZF4SbDsYw1ATPkhPOWnoBhm2zk0marGnXKlUdsRBL2JwYek648dSQ9Y9G4+sFt6qROBWel1U72Y76zczs34OkeYIEUPYLlL2P859tWtDLv3gnA4m65EdxfrxkUyFJiS+4+c4MDLPt3mNhNHA19/wtRsJsjA== \ No newline at end of file diff --git a/Entity/Authentication/Entity/Account.cs b/Entity/Authentication/Entity/Account.cs index 8982809..125e8b3 100644 --- a/Entity/Authentication/Entity/Account.cs +++ b/Entity/Authentication/Entity/Account.cs @@ -6,6 +6,7 @@ public sealed class Account : Entity { public string Username { get; set; } public string Password { get; set; } + public int Region { get; set; } public long CreateTime { get; set; } public long LoginTime { get; set; } } \ No newline at end of file diff --git a/Entity/Def/RegionDef.cs b/Entity/Def/RegionDef.cs new file mode 100644 index 0000000..d0e41fe --- /dev/null +++ b/Entity/Def/RegionDef.cs @@ -0,0 +1,29 @@ +namespace NB; + +public static class RegionDef +{ + /// + /// 中国区 + /// + public const int CN = 1; + + /// + /// 亚太区 + /// + public const int Asia = 2; + + /// + /// 欧洲区 + /// + public const int Europe = 3; + + /// + /// 美洲区 + /// + public const int America = 4; + + /// + /// 独联体区 + /// + public const int CIS = 5; +} \ No newline at end of file diff --git a/Entity/Game/Player/PlayerManageComponent.cs b/Entity/Game/Player/PlayerManageComponent.cs index 99bbac4..f153818 100644 --- a/Entity/Game/Player/PlayerManageComponent.cs +++ b/Entity/Game/Player/PlayerManageComponent.cs @@ -12,9 +12,4 @@ public sealed class PlayerManageComponent : Entity public long AutoSaveTimerId; public readonly Dictionary Players = new(); - - /// - /// 需要保存到数据库的玩家 - /// - public readonly HashSet NeedSavePlayer = new(); } \ No newline at end of file diff --git a/Entity/Gate/GateUnit.cs b/Entity/Gate/GateUnit.cs new file mode 100644 index 0000000..03529de --- /dev/null +++ b/Entity/Gate/GateUnit.cs @@ -0,0 +1,14 @@ +using Fantasy.Entitas; +using Fantasy.Network; + +namespace NB.Gate; + +public class GateUnit : Entity +{ + public bool Kick; + public long AccountID; + public int Region; + public long GameSceneRouteId; + public long ChatSceneRouteId; + public EntityReference Session; +} \ No newline at end of file diff --git a/Entity/Gate/GateUnitManageComponent.cs b/Entity/Gate/GateUnitManageComponent.cs new file mode 100644 index 0000000..e5187cd --- /dev/null +++ b/Entity/Gate/GateUnitManageComponent.cs @@ -0,0 +1,9 @@ +using Fantasy.Entitas; +using Fantasy.Network; + +namespace NB.Gate; + +public class GateUnitManageComponent : Entity +{ + public readonly Dictionary Units = new(); +} \ No newline at end of file diff --git a/Entity/Gate/GateUnitSessionComponent.cs b/Entity/Gate/GateUnitSessionComponent.cs new file mode 100644 index 0000000..88dcba7 --- /dev/null +++ b/Entity/Gate/GateUnitSessionComponent.cs @@ -0,0 +1,8 @@ +using Fantasy.Entitas; + +namespace NB.Gate; + +public sealed class GateUnitSessionComponent : Entity +{ + public long AccountID; +} \ No newline at end of file diff --git a/Entity/Gate/SessionPlayerComponent.cs b/Entity/Gate/SessionPlayerComponent.cs deleted file mode 100644 index 8090aff..0000000 --- a/Entity/Gate/SessionPlayerComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Fantasy.Entitas; - -namespace NB.Gate; - -public sealed class SessionPlayerComponent : Entity -{ - public bool Kick { get; set; } - - public long AccountID; -} \ No newline at end of file diff --git a/Entity/Generate/NetworkProtocol/OuterMessage.cs b/Entity/Generate/NetworkProtocol/OuterMessage.cs index de5e21b..ef2aaf4 100644 --- a/Entity/Generate/NetworkProtocol/OuterMessage.cs +++ b/Entity/Generate/NetworkProtocol/OuterMessage.cs @@ -29,6 +29,7 @@ namespace Fantasy Username = default; Password = default; LoginType = default; + Region = default; #if FANTASY_NET || FANTASY_UNITY GetScene().MessagePoolComponent.Return(this); #endif @@ -42,6 +43,8 @@ namespace Fantasy public string Password { get; set; } [ProtoMember(3)] public int LoginType { get; set; } + [ProtoMember(4)] + public int Region { get; set; } } [ProtoContract] public partial class A2C_LoginResponse : AMessage, IResponse, IProto @@ -284,4 +287,73 @@ namespace Fantasy [ProtoMember(2)] public long MailId { get; set; } } + /// + /// 发送聊天 + /// + [ProtoContract] + public partial class C2Chat_SendMessageRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Chat_SendMessageRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Message = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Caht2C_SendMessageResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Chat_SendMessageRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.ChatRoute; + [ProtoMember(1)] + public string Message { get; set; } + } + /// + /// 发送聊天响应 + /// + [ProtoContract] + public partial class Caht2C_SendMessageResponse : AMessage, ICustomRouteResponse, IProto + { + public static Caht2C_SendMessageResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Caht2C_SendMessageResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 推送消息 + /// + [ProtoContract] + public partial class Chat2C_Message : AMessage, ICustomRouteMessage, IProto + { + public static Chat2C_Message Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Message = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Chat2C_Message; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.ChatRoute; + [ProtoMember(1)] + public string Message { get; set; } + } } diff --git a/Entity/Generate/NetworkProtocol/OuterOpcode.cs b/Entity/Generate/NetworkProtocol/OuterOpcode.cs index 231afc0..c686785 100644 --- a/Entity/Generate/NetworkProtocol/OuterOpcode.cs +++ b/Entity/Generate/NetworkProtocol/OuterOpcode.cs @@ -13,5 +13,8 @@ namespace Fantasy public const uint Game2C_GetMailsResponse = 2415929106; public const uint Game2C_HaveMail = 2147493649; public const uint Game2C_MailState = 2147493650; + public const uint C2Chat_SendMessageRequest = 2281711379; + public const uint Caht2C_SendMessageResponse = 2415929107; + public const uint Chat2C_Message = 2147493651; } } diff --git a/Entity/Model/Def/ErrorCode.cs b/Entity/Model/Def/ErrorCode.cs index 277e856..ac96af0 100644 --- a/Entity/Model/Def/ErrorCode.cs +++ b/Entity/Model/Def/ErrorCode.cs @@ -4,6 +4,11 @@ public class ErrorCode { public const uint Successful = 0; + /// + /// 服务器上线失败 + /// + public const uint OnlineSceneFailed = 1; + /// /// 参数有误 /// @@ -29,4 +34,9 @@ public class ErrorCode /// 账号或密码有误 /// public const uint ErrAccountOrPass = 11002; + + /// + /// 登录自动注册没有设置地区 + /// + public const uint RegisterNotRegion = 11011; } \ No newline at end of file diff --git a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs index 5baa63e..b367448 100644 --- a/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs +++ b/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs @@ -157,6 +157,10 @@ namespace Fantasy.Entitas case IDestroySystem iDestroySystem: { entitiesType = iDestroySystem.EntitiesType(); + if (_destroySystems.ContainsKey(entitiesType)) + { + + } _destroySystems.Add(entitiesType, iDestroySystem); break; } diff --git a/Hotfix/Authentication/Handler/C2A_LoginRequestHandler.cs b/Hotfix/Authentication/Handler/C2A_LoginRequestHandler.cs index 9c8b37d..c0ce6a7 100644 --- a/Hotfix/Authentication/Handler/C2A_LoginRequestHandler.cs +++ b/Hotfix/Authentication/Handler/C2A_LoginRequestHandler.cs @@ -26,9 +26,13 @@ public class C2A_LoginRequestHandler : MessageRPC self.Password = null; self.CreateTime = 0; self.LoginTime = 0; + self.Region = 0; } } \ No newline at end of file diff --git a/Hotfix/Authentication/System/AuthenticationComponentSystem.cs b/Hotfix/Authentication/System/AuthenticationComponentSystem.cs index 83b6124..436a6cd 100644 --- a/Hotfix/Authentication/System/AuthenticationComponentSystem.cs +++ b/Hotfix/Authentication/System/AuthenticationComponentSystem.cs @@ -40,13 +40,13 @@ internal static class AuthenticationComponentSystem Log.Info($"鉴权服务器启动成功!Position:{self.Position} AuthenticationCount:{self.AuthenticationCount}"); } - internal static async FTask<(uint ErrorCode, long AccountId)> Login(this AuthenticationComponent self, + internal static async FTask<(uint ErrorCode, long AccountId, int region)> Login(this AuthenticationComponent self, string userName, string password) { // 1、检查传递的参数是否完整 if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password)) { - return (ErrorCode.ErrArgs, 0); + return (ErrorCode.ErrArgs, 0, 0); } // 检查账号是否应该在当前鉴权服务器中处理 @@ -55,7 +55,7 @@ internal static class AuthenticationComponentSystem { // 这个3代表的是当前账号不应该在这个鉴权服务器处理。 // return (3, 0); - return (ErrorCode.ErrServer, 0); + return (ErrorCode.ErrServer, 0, 0); } var scene = self.Scene; @@ -90,10 +90,10 @@ internal static class AuthenticationComponentSystem if (account == null) { - return (ErrorCode.ErrAccountOrPass, 0); + return (ErrorCode.ErrAccountOrPass, 0, 0); } - return (ErrorCode.Successful, account.Id); + return (ErrorCode.Successful, account.Id, account.Region); } uint result = 0; @@ -103,7 +103,7 @@ internal static class AuthenticationComponentSystem if (account == null) { // 没有注册 - return (ErrorCode.ErrAccountOrPass, -1); //返回-1,用于判断是否需要自动注册 + return (ErrorCode.ErrAccountOrPass, -1, 0); //返回-1,用于判断是否需要自动注册 } if (account.Password != password) @@ -126,10 +126,10 @@ internal static class AuthenticationComponentSystem if (result != 0) { - return (result, 0); + return (result, 0, 0); } - return (ErrorCode.Successful, account.Id); + return (ErrorCode.Successful, account.Id, account.Region); } } @@ -138,14 +138,14 @@ internal static class AuthenticationComponentSystem /// /// /// - /// + /// /// - internal static async FTask Register(this AuthenticationComponent self, string username, string password, + internal static async FTask Register(this AuthenticationComponent self, string username, int region, string source) { // 1、检查传递的参数是否完整 - if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) + if (string.IsNullOrEmpty(username)) { // 这个1代表的是参数不完整。 return ErrorCode.ErrArgs; @@ -187,7 +187,8 @@ internal static class AuthenticationComponentSystem //3、执行到这里的话,表示数据库或缓存没有该账号的注册信息,需要咱们创建一个。 account = Entity.Create(scene, true, true); account.Username = username; - account.Password = password; + account.Password = username; + account.Region = region; account.CreateTime = TimeHelper.Now; // 写入这个实体到数据中 await worldDateBase.Save(account); diff --git a/Hotfix/Authentication/System/AuthenticationHelper.cs b/Hotfix/Authentication/System/AuthenticationHelper.cs index b319b86..39ccf59 100644 --- a/Hotfix/Authentication/System/AuthenticationHelper.cs +++ b/Hotfix/Authentication/System/AuthenticationHelper.cs @@ -12,7 +12,8 @@ public static class AuthenticationHelper /// 用户名 /// 用户密码 /// - public static async FTask<(uint ErrorCode, long AccountId)> Login(Scene scene, string userName, string password) + public static async FTask<(uint ErrorCode, long AccountId, int region)> Login(Scene scene, string userName, + string password) { return await scene.GetComponent().Login(userName, password); } @@ -22,12 +23,12 @@ public static class AuthenticationHelper /// /// /// 用户名 - /// 用户密码 + /// 注册地区 /// 注册的来源/原因 /// - public static async FTask Register(Scene scene, string username, string password, string source) + public static async FTask Register(Scene scene, string username, int region, string source) { - return await scene.GetComponent().Register(username, password, source); + return await scene.GetComponent().Register(username, region, source); } /// diff --git a/Hotfix/Authentication/System/Jwt/AuthenticationJwtComponentSystem.cs b/Hotfix/Authentication/System/Jwt/AuthenticationJwtComponentSystem.cs index cd3bf77..739dbcd 100644 --- a/Hotfix/Authentication/System/Jwt/AuthenticationJwtComponentSystem.cs +++ b/Hotfix/Authentication/System/Jwt/AuthenticationJwtComponentSystem.cs @@ -29,24 +29,25 @@ public static class AuthenticationJwtComponentSystem ValidateIssuer = true, // 验证发行者 ValidateAudience = true, // 验证受众 ValidateIssuerSigningKey = true, // 验证签名密钥 - ValidIssuer = "Fantasy", // 有效的发行者 - ValidAudience = "Fantasy", // 有效的受众 + ValidIssuer = "NoBug", // 有效的发行者 + ValidAudience = "NoBug", // 有效的受众 IssuerSigningKey = new RsaSecurityKey(rsa) // RSA公钥作为签名密钥 }; } - public static string GetToken(this AuthenticationJwtComponent self, long aId, string address, uint sceneId) + public static string GetToken(this AuthenticationJwtComponent self, long aId, string address, uint sceneId, int region) { var jwtPayload = new JwtPayload() { { "aId", aId }, { "Address", address }, - { "SceneId", sceneId } + { "SceneId", sceneId }, + { "Region", region }, }; var jwtSecurityToken = new JwtSecurityToken( - issuer: "Fantasy", - audience: "Fantasy", + issuer: "NoBug", + audience: "NoBug", claims: jwtPayload.Claims, expires: DateTime.UtcNow.AddMilliseconds(3000), signingCredentials: self.SigningCredentials); diff --git a/Hotfix/Authentication/System/Jwt/AuthenticationJwtHelper.cs b/Hotfix/Authentication/System/Jwt/AuthenticationJwtHelper.cs index 1ed5bf5..80c16c5 100644 --- a/Hotfix/Authentication/System/Jwt/AuthenticationJwtHelper.cs +++ b/Hotfix/Authentication/System/Jwt/AuthenticationJwtHelper.cs @@ -11,9 +11,10 @@ public static class AuthenticationJwtHelper /// AccountId /// 目标服务器的地址 /// 分配的Scene的Id + /// 账号所属地区 /// - public static string GetToken(Scene scene, long aId, string address, uint sceneId) + public static string GetToken(Scene scene, long aId, string address, uint sceneId, int region) { - return scene.GetComponent().GetToken(aId, address, sceneId); + return scene.GetComponent().GetToken(aId, address, sceneId, region); } } \ No newline at end of file diff --git a/Hotfix/Chat/Handler/C2Chat_SendMessageRequestHandler.cs b/Hotfix/Chat/Handler/C2Chat_SendMessageRequestHandler.cs new file mode 100644 index 0000000..2907994 --- /dev/null +++ b/Hotfix/Chat/Handler/C2Chat_SendMessageRequestHandler.cs @@ -0,0 +1,15 @@ +using Fantasy; +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace NB.Chat; + +public sealed class + C2Chat_SendMessageRequestHandler : RouteRPC +{ + protected override async FTask Run(ChatUnit chatUnit, C2Chat_SendMessageRequest request, + Caht2C_SendMessageResponse response, Action reply) + { + ChatSceneHelper.Broadcast(chatUnit.Scene, request.Message); + } +} \ No newline at end of file diff --git a/Hotfix/Chat/Helper/ChatSceneHelper.cs b/Hotfix/Chat/Helper/ChatSceneHelper.cs new file mode 100644 index 0000000..9417fd2 --- /dev/null +++ b/Hotfix/Chat/Helper/ChatSceneHelper.cs @@ -0,0 +1,29 @@ +using Fantasy; +using Fantasy.Platform.Net; + +namespace NB.Chat; + +public static class ChatSceneHelper +{ + /// + /// 广播消息 + /// + /// + /// + public static void Broadcast(Scene scene, string message) + { + //发送给所有Gate服务器,让Gate转发给其他客户端 + var gateConfigs = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Gate); + + var sendMessage = new Chat2C_Message() + { + Message = message + }; + var networkMessagingComponent = scene.NetworkMessagingComponent; + foreach (var config in gateConfigs) + { + //发送给Gate服务器转发消息 + networkMessagingComponent.SendInnerRoute(config.RouteId, sendMessage); + } + } +} \ No newline at end of file diff --git a/Hotfix/Game/Helper/GameSceneHelper.cs b/Hotfix/Game/Helper/GameSceneHelper.cs new file mode 100644 index 0000000..993db41 --- /dev/null +++ b/Hotfix/Game/Helper/GameSceneHelper.cs @@ -0,0 +1,16 @@ +using System.Net; +using Fantasy; +using Fantasy.Network; +using Fantasy.Platform.Net; + +namespace NB.Game; + +public static class GameSceneHelper +{ + public static SceneConfig GetSceneConfig(Session session) + { + var gameSceneConfigs = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Game); + + return gameSceneConfigs.First(); + } +} \ No newline at end of file diff --git a/Hotfix/Gate/Handler/C2G_GetAccountInfoRequestHandler.cs b/Hotfix/Gate/Handler/C2G_GetAccountInfoRequestHandler.cs deleted file mode 100644 index a286832..0000000 --- a/Hotfix/Gate/Handler/C2G_GetAccountInfoRequestHandler.cs +++ /dev/null @@ -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 -// { -// protected override async FTask Run(Session session, C2G_GetAccountInfoRequest request, G2C_GetAccountInfoResponse response, Action reply) -// { -// var gameAccountFlagComponent = session.GetComponent(); -// -// if (gameAccountFlagComponent == null) -// { -// // 表示不应该访问这个接口,要先访问登录的接口。 -// // response.ErrorCode = 1; -// session.Dispose(); -// return; -// } -// -// Player account = gameAccountFlagComponent.Player; -// -// if (account == null) -// { -// // 表示这个Account已经被销毁过了。不是咱们想要的了 -// } -// -// response.GameAccountInfo = account.GetGameAccountInfo(); -// await FTask.CompletedTask; -// } -// } \ No newline at end of file diff --git a/Hotfix/Gate/Handler/C2G_LoginRequestHandler.cs b/Hotfix/Gate/Handler/C2G_LoginRequestHandler.cs index 326541d..607a931 100644 --- a/Hotfix/Gate/Handler/C2G_LoginRequestHandler.cs +++ b/Hotfix/Gate/Handler/C2G_LoginRequestHandler.cs @@ -3,6 +3,7 @@ using Fantasy.Async; using Fantasy.Network; using Fantasy.Network.Interface; using Fantasy.Platform.Net; +using NB.Game; namespace NB.Gate.Handler; @@ -13,14 +14,11 @@ public sealed class C2G_LoginRequestHandler : MessageRPC(); + + if (!gateUnitManageComponent.TryGet(accountId, out var gateUnit)) { - // 如果ErrorCode不是0表示请求的协议发生错误,应该提示给客户端。 - // 这里就不做这个了。 - response.ErrorCode = gameResponse.ErrorCode; - return; + gateUnit = gateUnitManageComponent.Add(session, accountId); } - // 要实现Route协议的转发,需要给Session添加一个RouteComponent,这个非常重要。 - var routeComponent = session.AddComponent(); - // 需要再Examples/Config/NetworkProtocol/RouteType.Config里添加一个ChatRoute - // 然后点击导表工具,会自动生成一个RouteType.cs文件。 - // 使用你定义的ChatRoute当routeType的参数传递进去。 - // routeResponse会返回一个ChatRouteId,这个就是Chat的RouteId。 - routeComponent.AddAddress(RouteType.GameRoute, gameResponse.RoleRouteId); - // 这些操作完成后,就完成了Route消息的建立。 - // 后面可以直接发送Route消息通过Gate自动中转给Chat了。 + if (gateUnit == null) + { + Log.Error("创建GateUnit失败"); + session.Dispose(); + return; + } - - // 给当前Session添加一个组件,当Session销毁的时候会销毁这个组件。 - var accountFlagComponent = session.AddComponent(); - accountFlagComponent.AccountID = accountId; - - // account.SessionRunTimeId = session.RuntimeId; - // response.GameAccountInfo = account.GetGameAccountInfo(); - + response.ErrorCode = await GateLoginHelper.Online(gateUnit); Log.Debug($"当前的Gate服务器:{session.Scene.SceneConfigId} accountId:{accountId}"); - - - Log.Debug($"网关内网连接到游戏服成功 routerId={gameResponse.RoleRouteId}"); + // var gameSceneConfig = GameSceneHelper.GetSceneConfig(session); + // + // // 通过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.AddAddress(RouteType.GameRoute, gameResponse.RoleRouteId); + // + // // 给当前Session添加一个组件,当Session销毁的时候会销毁这个组件。 + // var accountFlagComponent = session.AddComponent(); + // accountFlagComponent.AccountID = accountId; + } } \ No newline at end of file diff --git a/Hotfix/Gate/Helper/GateLoginHelper.cs b/Hotfix/Gate/Helper/GateLoginHelper.cs new file mode 100644 index 0000000..bb8b844 --- /dev/null +++ b/Hotfix/Gate/Helper/GateLoginHelper.cs @@ -0,0 +1,75 @@ +using Fantasy; +using Fantasy.Async; +using Fantasy.Network; +using NB.Game; + +namespace NB.Gate; + +public static class GateLoginHelper +{ + /// + /// 网关通知其他服务器上线 + /// + /// + /// + public static async FTask Online(GateUnit gateUnit) + { + if (gateUnit == null) + { + return ErrorCode.ErrArgs; + } + + Session session = gateUnit.Session; + if (session == null) + { + return ErrorCode.ErrArgs; + } + + var gateUnitSessionComponent = session.GetComponent(); + if (gateUnitSessionComponent == null) + { + gateUnitSessionComponent = session.AddComponent(); + } + + var routeComponent = session.GetComponent(); + if (routeComponent == null) + { + routeComponent = session.AddComponent(); + } + + gateUnitSessionComponent.AccountID = gateUnit.AccountID; + + //安排服务器,并通知进入 + var gameSceneConfig = GameSceneHelper.GetSceneConfig(session); + var gameRouteId = gameSceneConfig.RouteId; + //连接到游戏中心服 + var gameResponse = (Game2G_EnterResponse)await session.Scene.NetworkMessagingComponent.CallInnerRoute( + gameRouteId, new G2Game_EnterRequest() + { + AccountId = gateUnit.AccountID, + GateRouteId = session.RuntimeId + }); + + if (gameResponse.ErrorCode != 0) + { + return ErrorCode.OnlineSceneFailed; + } + + routeComponent.AddAddress(RouteType.GameRoute, gameResponse.RoleRouteId); + gateUnit.GameSceneRouteId = gameRouteId; + + + return ErrorCode.Successful; + } + + /// + /// 网关通知其他服务器下线 + /// + /// + /// + public static async FTask Offline(GateUnit gateUnit) + { + //通知服务器下线 + return ErrorCode.Successful; + } +} \ No newline at end of file diff --git a/Hotfix/Gate/System/GateUnitManageComponentSystem.cs b/Hotfix/Gate/System/GateUnitManageComponentSystem.cs new file mode 100644 index 0000000..cd3c4cd --- /dev/null +++ b/Hotfix/Gate/System/GateUnitManageComponentSystem.cs @@ -0,0 +1,55 @@ +using Fantasy; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Network; +using Fantasy.Platform.Net; +using NB.Game; + +namespace NB.Gate; + +public static class GateUnitManageComponentSystem +{ + public static GateUnit Add(this GateUnitManageComponent self, Session session, long accountId) + { + if (self.Units.TryGetValue(accountId, out var unit)) + { + unit.Session = session; + return unit; + } + + unit = Entity.Create(self.Scene, accountId, true, true); + unit.AccountID = accountId; + unit.Session = session; + self.Units.Add(accountId, unit); + return unit; + } + + public static GateUnit? Get(this GateUnitManageComponent self, long accountId) + { + return self.Units.GetValueOrDefault(accountId); + } + + public static bool TryGet(this GateUnitManageComponent self, long accountId, out GateUnit? unit) + { + return self.Units.TryGetValue(accountId, out unit); + } + + public static async FTask Remove(this GateUnitManageComponent self, long accountId, bool isDispose = true) + { + if (!self.Units.TryGetValue(accountId, out var unit)) return; + //通知其他服务器下线 + var result = await GateLoginHelper.Offline(unit); + if (result != 0) + { + Log.Error($"通知其他服务器下线失败,错误码:{result}"); + return; + } + + Log.Info($"accountId:{accountId} 下线成功"); + self.Units.Remove(accountId); + if (isDispose) + { + unit.Dispose(); + } + } +} \ No newline at end of file diff --git a/Hotfix/Gate/System/GateUnitSessionComponentSystem.cs b/Hotfix/Gate/System/GateUnitSessionComponentSystem.cs new file mode 100644 index 0000000..98c1fe1 --- /dev/null +++ b/Hotfix/Gate/System/GateUnitSessionComponentSystem.cs @@ -0,0 +1,17 @@ +using Fantasy.Entitas.Interface; + +namespace NB.Gate; + +public class GateUnitSessionComponentSystem : DestroySystem +{ + protected override void Destroy(GateUnitSessionComponent self) + { + var gateUnitManageComponent = self.Scene.GetComponent(); + if (gateUnitManageComponent != null) + { + _ = gateUnitManageComponent.Remove(self.AccountID); + } + + self.AccountID = 0; + } +} \ No newline at end of file diff --git a/Hotfix/Gate/System/GateUnitSystem.cs b/Hotfix/Gate/System/GateUnitSystem.cs new file mode 100644 index 0000000..5ad76f9 --- /dev/null +++ b/Hotfix/Gate/System/GateUnitSystem.cs @@ -0,0 +1,16 @@ +using Fantasy.Entitas.Interface; + +namespace NB.Gate; + +public class GateUnitDestroySystem : DestroySystem +{ + protected override void Destroy(GateUnit self) + { + self.AccountID = 0; + self.Kick = false; + } +} + +public class GateUnitSystem +{ +} \ No newline at end of file diff --git a/Hotfix/Gate/System/PlayerFlagComponentSystem.cs b/Hotfix/Gate/System/PlayerFlagComponentSystem.cs index 77f0d53..825c6f5 100644 --- a/Hotfix/Gate/System/PlayerFlagComponentSystem.cs +++ b/Hotfix/Gate/System/PlayerFlagComponentSystem.cs @@ -1,19 +1,19 @@ -using Fantasy.Entitas.Interface; - -namespace NB.Gate; - -public sealed class SessionPlayerComponentDestroySystem : DestroySystem -{ - 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; - } - - // self.Player = null; - } -} \ No newline at end of file +// using Fantasy.Entitas.Interface; +// +// namespace NB.Gate; +// +// public sealed class SessionPlayerComponentDestroySystem : DestroySystem +// { +// protected override void Destroy(GateUnitSessionComponent self) +// { +// if (self.AccountID != 0) +// { +// // 执行下线过程、并且要求在5分钟后完成缓存清理。也就是5分钟后会保存数据到数据库。 +// // 由于5分钟太长了、咱们测试的时候,不方便测试,也可以把这个时间改短一些,比如10秒。 +// // PlayerHelper.Disconnect(self.Scene, self.AccountID, 1000 * 60 * 5).Coroutine(); +// // self.AccountID = 0; +// } +// +// // self.Player = null; +// } +// } \ No newline at end of file diff --git a/Hotfix/OnSceneCreate_Init.cs b/Hotfix/OnSceneCreate_Init.cs index ef991b5..0a5cc6a 100644 --- a/Hotfix/OnSceneCreate_Init.cs +++ b/Hotfix/OnSceneCreate_Init.cs @@ -25,6 +25,8 @@ public class OnSceneCreate_Init : AsyncEventSystem } case SceneType.Gate: { + // 用于管理网关所有连接的组件 + scene.AddComponent(); // 用于验证JWT是否合法的组件 scene.AddComponent(); break; diff --git a/Server.sln.DotSettings.user b/Server.sln.DotSettings.user index 3bbff5d..08fab59 100644 --- a/Server.sln.DotSettings.user +++ b/Server.sln.DotSettings.user @@ -31,6 +31,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded