diff --git a/Config/Json/Server/SceneConfigData.Json b/Config/Json/Server/SceneConfigData.Json
index dd6417b..f34067d 100644
--- a/Config/Json/Server/SceneConfigData.Json
+++ b/Config/Json/Server/SceneConfigData.Json
@@ -1,5 +1,6 @@
{"List":[
-{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":null,"OuterPort":0,"InnerPort":11001,"SceneType":2},
+{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Authentication","NetworkProtocol":"KCP","OuterPort":20001,"InnerPort":11001,"SceneType":1},
+{"Id":1006,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":null,"OuterPort":0,"InnerPort":11006,"SceneType":2},
{"Id":1002,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Gate","NetworkProtocol":"KCP","OuterPort":20000,"InnerPort":11002,"SceneType":3},
{"Id":1003,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Map","NetworkProtocol":null,"OuterPort":0,"InnerPort":11003,"SceneType":4},
{"Id":1004,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeMode":"MultiThread","SceneTypeString":"Chat","NetworkProtocol":null,"OuterPort":0,"InnerPort":11004,"SceneType":8},
diff --git a/Config/NetworkProtocol/Outer/OuterMessage.proto b/Config/NetworkProtocol/Outer/OuterMessage.proto
index 6c2a2f1..19da9f3 100644
--- a/Config/NetworkProtocol/Outer/OuterMessage.proto
+++ b/Config/NetworkProtocol/Outer/OuterMessage.proto
@@ -7,6 +7,56 @@ package Fantasy.Network.Message;
// 使用方式:
// 在message协议上方添加// Protocol+空格+协议名字
// 例如:// Protocol ProtoBuf 或 // Protocol MemoryPack
+message C2A_RegisterRequest // IRequest,A2C_RegisterResponse
+{
+ string Username = 1;
+ string Password = 2;
+}
+message A2C_RegisterResponse // IResponse
+{
+
+}
+message C2A_LoginRequest // IRequest,A2C_LoginResponse
+{
+ string Username = 1;
+ string Password = 2;
+ int32 LoginType = 3;
+}
+message A2C_LoginResponse // IResponse
+{
+ string ToKen = 1;
+}
+/// 客户端登录到Gate服务器
+message C2G_LoginRequest // IRequest,G2C_LoginResponse
+{
+ string ToKen = 1;
+}
+message G2C_LoginResponse // IResponse
+{
+ GameAccountInfo GameAccountInfo = 1;
+}
+/// 通知客户端重复登录
+message G2C_RepeatLogin // IMessage
+{
+
+}
+/// GameAccount实体类
+message GameAccountInfo
+{
+ int64 CreateTime = 1;
+ int64 LoginTime = 2;
+}
+/// 拿到当前账号的信息
+message C2G_GetAccountInfoRequest // IRequest,G2C_GetAccountInfoResponse
+{
+
+}
+message G2C_GetAccountInfoResponse // IResponse
+{
+ GameAccountInfo GameAccountInfo = 1;
+}
+
+
message C2G_TestMessage // IMessage
{
string Tag = 1;
@@ -19,15 +69,6 @@ message G2C_TestResponse // IResponse
{
string Tag = 1;
}
-message C2G_TestRequestPushMessage // IMessage
-{
-
-}
-/// Gate服务器推送一个消息给客户端
-message G2C_PushMessage // IMessage
-{
- string Tag = 1;
-}
message C2G_CreateAddressableRequest // IRequest,G2C_CreateAddressableResponse
{
@@ -70,113 +111,4 @@ message C2Chat_TestMessageRequest // ICustomRouteRequest,Chat2C_TestMessageRespo
message Chat2C_TestMessageResponse // ICustomRouteResponse
{
string Tag = 1;
-}
-/// 发送一个RPC消息给Map,让Map里的Entity转移到另外一个Map上
-message C2M_MoveToMapRequest // IAddressableRouteRequest,M2C_MoveToMapResponse
-{
-
-}
-message M2C_MoveToMapResponse // IAddressableRouteResponse
-{
-
-}
-/// 发送一个消息给Gate,让Gate发送一个Addressable消息给MAP
-message C2G_SendAddressableToMap // IMessage
-{
- string Tag = 1;
-}
-/// 发送一个消息给Chat,让Chat服务器主动推送一个RouteMessage消息给客户端
-message C2Chat_TestRequestPushMessage // ICustomRouteMessage,ChatRoute
-{
-
-}
-/// Chat服务器主动推送一个消息给客户端
-message Chat2C_PushMessage // ICustomRouteMessage,ChatRoute
-{
- string Tag = 1;
-}
-/// 客户端发送给Gate服务器通知map服务器创建一个SubScene
-message C2G_CreateSubSceneRequest // IRequest,G2C_CreateSubSceneResponse
-{
-
-}
-message G2C_CreateSubSceneResponse // IResponse
-{
-
-}
-/// 客户端通知Gate服务器给SubScene发送一个消息
-message C2G_SendToSubSceneMessage // IMessage
-{
-
-}
-/// 客户端通知Gate服务器创建一个SubScene的Address消息
-message C2G_CreateSubSceneAddressableRequest // IRequest,G2C_CreateSubSceneAddressableResponse
-{
-
-}
-message G2C_CreateSubSceneAddressableResponse // IResponse
-{
-
-}
-/// 客户端向SubScene发送一个测试消息
-message C2SubScene_TestMessage // IAddressableRouteMessage
-{
- string Tag = 1;
-}
-/// 客户端向SubScene发送一个销毁测试消息
-message C2SubScene_TestDisposeMessage // IAddressableRouteMessage
-{
-
-}
-/// 客户端向服务器发送连接消息(Roaming)
-message C2G_ConnectRoamingRequest // IRequest,G2C_ConnectRoamingResponse
-{
-
-}
-message G2C_ConnectRoamingResponse // IResponse
-{
-
-}
-/// 测试一个Chat漫游普通消息
-message C2Chat_TestRoamingMessage // IRoamingMessage,ChatRoamingType
-{
- string Tag = 1;
-}
-/// 测试一个Map漫游普通消息
-message C2Map_TestRoamingMessage // IRoamingMessage,MapRoamingType
-{
- string Tag = 1;
-}
-/// 测试一个Chat漫游RPC消息
-message C2Chat_TestRPCRoamingRequest // IRoamingRequest,Chat2C_TestRPCRoamingResponse,ChatRoamingType
-{
- string Tag = 1;
-}
-message Chat2C_TestRPCRoamingResponse // IRoamingResponse
-{
-
-}
-/// 客户端发送一个漫游消息给Map通知Map主动推送一个消息给客户端
-message C2Map_PushMessageToClient // IRoamingMessage,MapRoamingType
-{
- string Tag = 1;
-}
-/// 漫游端发送一个消息给客户端
-message Map2C_PushMessageToClient // IRoamingMessage,MapRoamingType
-{
- string Tag = 1;
-}
-/// 测试传送漫游的触发协议
-message C2Map_TestTransferRequest // IRoamingRequest,Map2C_TestTransferResponse,MapRoamingType
-{
-
-}
-message Map2C_TestTransferResponse // IRoamingResponse
-{
-
-}
-/// 测试一个Chat发送到Map之间漫游协议
-message C2Chat_TestSendMapMessage // IRoamingMessage,ChatRoamingType
-{
- string Tag = 1;
-}
+}
\ No newline at end of file
diff --git a/Entity/Authentication/AuthenticationComponent.cs b/Entity/Authentication/AuthenticationComponent.cs
new file mode 100644
index 0000000..288d748
--- /dev/null
+++ b/Entity/Authentication/AuthenticationComponent.cs
@@ -0,0 +1,15 @@
+namespace Fantasy;
+
+public sealed class AuthenticationComponent : Entitas.Entity
+{
+ ///
+ /// 代表当前服务器在鉴权服务器中的位置
+ ///
+ public int Position;
+ ///
+ /// 代表当前鉴权组的数量
+ ///
+ public int AuthenticationCount;
+ public readonly Dictionary Accounts = new Dictionary();
+ public readonly Dictionary LoginAccounts = new Dictionary();
+}
\ No newline at end of file
diff --git a/Entity/Authentication/AuthenticationJwtComponent.cs b/Entity/Authentication/AuthenticationJwtComponent.cs
new file mode 100644
index 0000000..1df96e7
--- /dev/null
+++ b/Entity/Authentication/AuthenticationJwtComponent.cs
@@ -0,0 +1,12 @@
+using Fantasy.Entitas;
+using Microsoft.IdentityModel.Tokens;
+
+namespace Fantasy;
+
+public sealed class AuthenticationJwtComponent : Entity
+{
+ public string PublicKeyPem = "MIIBCgKCAQEAqc1moV1nynBYVXhsXeTuDc/DcC7TSQ+dVmTsyeUZP+PaiZjxp/cIo0sj9OCAcAK2nCBpIjBjM7Rbg7Uslb4KvlH8eshsH8LOL9KybNsB0uFg/kPvSvIBcdWsxbbARxDGrTl+Nh1t6s2V1voK9g+OQqK/xIyhvrwFYIjc1/O6FI4uGyMag3D6MJATW2SCrwe1tKU9dfk72VrIqT4FVzbZUDQdFxEKHiQ4vcoBiGxsoYWr6lxbrrtDDNzPzVEgzDbsvaPvSCNRacFaBCJBeGCWGn/fKKBOl5NV2EfXa8oNFgw0VfC4JiRpPUjdhsKvzjtp5P3AYrnloGkTxp9HLkdDjwIDAQAB";
+ public string PrivateKeyPem = "MIIEowIBAAKCAQEAqc1moV1nynBYVXhsXeTuDc/DcC7TSQ+dVmTsyeUZP+PaiZjxp/cIo0sj9OCAcAK2nCBpIjBjM7Rbg7Uslb4KvlH8eshsH8LOL9KybNsB0uFg/kPvSvIBcdWsxbbARxDGrTl+Nh1t6s2V1voK9g+OQqK/xIyhvrwFYIjc1/O6FI4uGyMag3D6MJATW2SCrwe1tKU9dfk72VrIqT4FVzbZUDQdFxEKHiQ4vcoBiGxsoYWr6lxbrrtDDNzPzVEgzDbsvaPvSCNRacFaBCJBeGCWGn/fKKBOl5NV2EfXa8oNFgw0VfC4JiRpPUjdhsKvzjtp5P3AYrnloGkTxp9HLkdDjwIDAQABAoIBAAP7djm4mBOOWPQANAJruQ2H3tyFrJzdCeKZ0VfW0KXH8Tsi5B/9Ui2KOJionzqBRckZlX2gxuLSiwbmu9nzMAtQnuw+QRLpna5PcbHN3RgWAxFThIwsas5BpaCpbY79HLu5SnV4cTh9g9Mb4B/vM3XqnTa92ZlAjZu6+fryk12iAiWKGgMIJDG1TW7PLz9bAdhvfLcJ4ipP+dDtbbYuDSkykijYS7Vq94syhD00HCnPWeNb/UQBwYoD/rsQ9j0zTVNe5SAMhNVm2vC+TX38pYDzGahNo6Y5RnKQAPC7WchEhmesuQYaxZo+2ZtquN9OC2WanaHzoT5ru9yUXY6n9ikCgYEA7FtQXFaeAI7J2pSsb5LnKoGZsWnHBhLUMVUKEGx2ORk37kAbUBY1gNsRuIysEmpkWTFfLCWoqFEca/gK/79viggrwbkjzizZOICXONEgDm5YRK+0K728FGuPWCxj6J+nrcstBKem/zPxt7gqVXeCJWw9DAjySbsWeZ8nAQtDCTMCgYEAt+oWcLQLO/J46k8HA4euavrcDYrY5qCxiq/E7CeV7h9g5Cb/oMMICqNASlzL80uynLkCaVTvs+v25ZJeZU/Pyty9jNbYDtOxnABBNZNolrrgtw2cB47m93/3X1ABn0eJ451l0AEbBu5y/MoLEDdCD7s1FtvRZ0FEOynuLKZYNDUCgYAnUGUEhu/PHfEbZ4FrKZ9D5by/0t1k+DrNXdzHsJLVmolAGu+wGZGatlWzQcrZYVMBtwGioTz1ilBU8TQ7KAeQiR1mIrp+79zN1i3RKI/Rdq899Y/derjPGLkGLJQNvIiyksoRLSXM60H4kiyQfMlsGh3pY4+RjgoF/uAI/2uOGwKBgC/uWhrVUXg2IT0vi2xoGBTZfDArV4wDpUG3vWKujmyY0O+lGkoTiiz7ju3ScXTe7ZXawb4h3LbPcHE0TFWrD0SXcu8ZrwVuNoOprVUBLejam2YZrehqXddzCk1U1JdmVZF0m+wx3ZFY467uGSQIwrbG23cxosl+QQIKU4Bfee1hAoGBAJhnrD5GJmqrTQEZta9gjIhtHPoIWxwwYCkxbq/j2N7GLudlLzAs304ByqlKNNYysT9SahPS8oGvqdRFd2bo90MQy0L7U2z6SG+gNhX7EGzDU6AnpotuVy56r/9bLRW4rXrHgwz8dUJWjqmmIBpsjAhpIykBu3HefSoiMc0s3RvJ";
+ public SigningCredentials SigningCredentials;
+ public TokenValidationParameters TokenValidationParameters;
+}
\ No newline at end of file
diff --git a/Entity/Authentication/Model/Account.cs b/Entity/Authentication/Model/Account.cs
new file mode 100644
index 0000000..d988830
--- /dev/null
+++ b/Entity/Authentication/Model/Account.cs
@@ -0,0 +1,11 @@
+using Fantasy.Entitas;
+
+namespace Fantasy;
+
+public sealed class Account : Entity
+{
+ public string Username { get; set; }
+ public string Password { get; set; }
+ public long CreateTime { get; set; }
+ public long LoginTime { get; set; }
+}
\ No newline at end of file
diff --git a/Entity/Authentication/Model/AccountCacheInfo.cs b/Entity/Authentication/Model/AccountCacheInfo.cs
new file mode 100644
index 0000000..5c1701a
--- /dev/null
+++ b/Entity/Authentication/Model/AccountCacheInfo.cs
@@ -0,0 +1,8 @@
+using Fantasy.Entitas;
+
+namespace Fantasy;
+
+public class AccountCacheInfo : Entity
+{
+
+}
\ No newline at end of file
diff --git a/Entity/Authentication/TimeOut/AccountCacheInfoTimeOut.cs b/Entity/Authentication/TimeOut/AccountCacheInfoTimeOut.cs
new file mode 100644
index 0000000..7517f63
--- /dev/null
+++ b/Entity/Authentication/TimeOut/AccountCacheInfoTimeOut.cs
@@ -0,0 +1,9 @@
+using Fantasy.Entitas;
+
+namespace Fantasy;
+
+public class AccountCacheInfoTimeOut : Entity
+{
+ public long TimerId;
+ public string Key;
+}
\ No newline at end of file
diff --git a/Entity/Authentication/TimeOut/AccountTimeOut.cs b/Entity/Authentication/TimeOut/AccountTimeOut.cs
new file mode 100644
index 0000000..db2fe5e
--- /dev/null
+++ b/Entity/Authentication/TimeOut/AccountTimeOut.cs
@@ -0,0 +1,8 @@
+using Fantasy.Entitas;
+
+namespace Fantasy;
+
+public class AccountTimeOut : Entity
+{
+ public long TimerId;
+}
\ No newline at end of file
diff --git a/Entity/Entity.csproj b/Entity/Entity.csproj
index 7011de8..b4fb434 100644
--- a/Entity/Entity.csproj
+++ b/Entity/Entity.csproj
@@ -21,4 +21,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Entity/EntityTimeOutComponent.cs b/Entity/EntityTimeOutComponent.cs
new file mode 100644
index 0000000..d32096a
--- /dev/null
+++ b/Entity/EntityTimeOutComponent.cs
@@ -0,0 +1,21 @@
+using Fantasy.Entitas;
+
+namespace Fantasy;
+
+public class EntityTimeOutComponent : Entity
+{
+ ///
+ /// 主要是用于检测每次请求的间隔,这里存放是下一次能正常通信时间
+ ///
+ public long NextTime;
+
+ ///
+ /// 用来设置检查的间隔时间
+ ///
+ public int Interval;
+
+ ///
+ /// 用于记录时间计划任务的ID,后面可以通过这个ID随时取消这个任务
+ ///
+ public long TimerId;
+}
\ No newline at end of file
diff --git a/Entity/Gate/GameAccountManageComponent.cs b/Entity/Gate/GameAccountManageComponent.cs
new file mode 100644
index 0000000..1adab80
--- /dev/null
+++ b/Entity/Gate/GameAccountManageComponent.cs
@@ -0,0 +1,8 @@
+using Fantasy.Entitas;
+
+namespace Fantasy.Gate;
+
+public sealed class GameAccountManageComponent : Entity
+{
+ public readonly Dictionary Accounts = new();
+}
\ No newline at end of file
diff --git a/Entity/Gate/GateJWTComponent.cs b/Entity/Gate/GateJWTComponent.cs
new file mode 100644
index 0000000..089a4d4
--- /dev/null
+++ b/Entity/Gate/GateJWTComponent.cs
@@ -0,0 +1,11 @@
+using Fantasy.Entitas;
+using Microsoft.IdentityModel.Tokens;
+
+namespace Fantasy.Gate;
+
+public sealed class GateJWTComponent : Entity
+{
+ public string PublicKeyPem = "MIIBCgKCAQEAqc1moV1nynBYVXhsXeTuDc/DcC7TSQ+dVmTsyeUZP+PaiZjxp/cIo0sj9OCAcAK2nCBpIjBjM7Rbg7Uslb4KvlH8eshsH8LOL9KybNsB0uFg/kPvSvIBcdWsxbbARxDGrTl+Nh1t6s2V1voK9g+OQqK/xIyhvrwFYIjc1/O6FI4uGyMag3D6MJATW2SCrwe1tKU9dfk72VrIqT4FVzbZUDQdFxEKHiQ4vcoBiGxsoYWr6lxbrrtDDNzPzVEgzDbsvaPvSCNRacFaBCJBeGCWGn/fKKBOl5NV2EfXa8oNFgw0VfC4JiRpPUjdhsKvzjtp5P3AYrnloGkTxp9HLkdDjwIDAQAB";
+ public SigningCredentials SigningCredentials;
+ public TokenValidationParameters TokenValidationParameters;
+}
\ No newline at end of file
diff --git a/Entity/Gate/Model/GameAccount.cs b/Entity/Gate/Model/GameAccount.cs
new file mode 100644
index 0000000..589652f
--- /dev/null
+++ b/Entity/Gate/Model/GameAccount.cs
@@ -0,0 +1,16 @@
+using Fantasy.Entitas;
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace Fantasy.Gate;
+
+public sealed class GameAccount : Entity
+{
+ // 1、可以拿ToKen的传递过来的AId来当这个组件的Id.
+ // 2、让这个Id自动生成、在组件里做一个变量来记录ToKen的AId。 public long AuthenticationId;
+ public long CreateTime;
+ public long LoginTime;
+
+ [BsonIgnore]
+ // BsonIgnore特性是让Bson保存到数据库中忽略掉这个字段。
+ public long SessionRunTimeId;
+}
\ No newline at end of file
diff --git a/Entity/Gate/Model/GameAccountFlagComponent.cs b/Entity/Gate/Model/GameAccountFlagComponent.cs
new file mode 100644
index 0000000..6e01d75
--- /dev/null
+++ b/Entity/Gate/Model/GameAccountFlagComponent.cs
@@ -0,0 +1,13 @@
+using Fantasy.Entitas;
+
+namespace Fantasy.Gate;
+
+public sealed class GameAccountFlagComponent : Entity
+{
+ public long AccountID;
+
+ // 有一种可能,当在Account在其他地方被销毁
+ // 这时候因为这个Account是会回收到池子中,所以这个引用还是有效的
+ // 那这时候就会出现这个引用的Account可能是其他用户的了。
+ public EntityReference Account;
+}
\ No newline at end of file
diff --git a/Entity/Generate/NetworkProtocol/OuterMessage.cs b/Entity/Generate/NetworkProtocol/OuterMessage.cs
index 0b19540..3cb1015 100644
--- a/Entity/Generate/NetworkProtocol/OuterMessage.cs
+++ b/Entity/Generate/NetworkProtocol/OuterMessage.cs
@@ -17,6 +17,220 @@ using Fantasy.Serialize;
namespace Fantasy
{
+ [ProtoContract]
+ public partial class C2A_RegisterRequest : AMessage, IRequest, IProto
+ {
+ public static C2A_RegisterRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Username = default;
+ Password = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public A2C_RegisterResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2A_RegisterRequest; }
+ [ProtoMember(1)]
+ public string Username { get; set; }
+ [ProtoMember(2)]
+ public string Password { get; set; }
+ }
+ [ProtoContract]
+ public partial class A2C_RegisterResponse : AMessage, IResponse, IProto
+ {
+ public static A2C_RegisterResponse 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.A2C_RegisterResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2A_LoginRequest : AMessage, IRequest, IProto
+ {
+ public static C2A_LoginRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Username = default;
+ Password = default;
+ LoginType = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public A2C_LoginResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2A_LoginRequest; }
+ [ProtoMember(1)]
+ public string Username { get; set; }
+ [ProtoMember(2)]
+ public string Password { get; set; }
+ [ProtoMember(3)]
+ public int LoginType { get; set; }
+ }
+ [ProtoContract]
+ public partial class A2C_LoginResponse : AMessage, IResponse, IProto
+ {
+ public static A2C_LoginResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ ToKen = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.A2C_LoginResponse; }
+ [ProtoMember(1)]
+ public string ToKen { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 客户端登录到Gate服务器
+ ///
+ [ProtoContract]
+ public partial class C2G_LoginRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_LoginRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ToKen = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_LoginResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_LoginRequest; }
+ [ProtoMember(1)]
+ public string ToKen { get; set; }
+ }
+ [ProtoContract]
+ public partial class G2C_LoginResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_LoginResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ GameAccountInfo = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_LoginResponse; }
+ [ProtoMember(1)]
+ public GameAccountInfo GameAccountInfo { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 通知客户端重复登录
+ ///
+ [ProtoContract]
+ public partial class G2C_RepeatLogin : AMessage, IMessage, IProto
+ {
+ public static G2C_RepeatLogin Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_RepeatLogin; }
+ }
+ ///
+ /// GameAccount实体类
+ ///
+ [ProtoContract]
+ public partial class GameAccountInfo : AMessage, IProto
+ {
+ public static GameAccountInfo Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ CreateTime = default;
+ LoginTime = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoMember(1)]
+ public long CreateTime { get; set; }
+ [ProtoMember(2)]
+ public long LoginTime { get; set; }
+ }
+ ///
+ /// 拿到当前账号的信息
+ ///
+ [ProtoContract]
+ public partial class C2G_GetAccountInfoRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_GetAccountInfoRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_GetAccountInfoResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_GetAccountInfoRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_GetAccountInfoResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_GetAccountInfoResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ GameAccountInfo = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_GetAccountInfoResponse; }
+ [ProtoMember(1)]
+ public GameAccountInfo GameAccountInfo { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
[ProtoContract]
public partial class C2G_TestMessage : AMessage, IMessage, IProto
{
@@ -77,42 +291,6 @@ namespace Fantasy
public uint ErrorCode { get; set; }
}
[ProtoContract]
- public partial class C2G_TestRequestPushMessage : AMessage, IMessage, IProto
- {
- public static C2G_TestRequestPushMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2G_TestRequestPushMessage; }
- }
- ///
- /// Gate服务器推送一个消息给客户端
- ///
- [ProtoContract]
- public partial class G2C_PushMessage : AMessage, IMessage, IProto
- {
- public static G2C_PushMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.G2C_PushMessage; }
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- [ProtoContract]
public partial class C2G_CreateAddressableRequest : AMessage, IRequest, IProto
{
public static C2G_CreateAddressableRequest Create(Scene scene)
@@ -313,475 +491,4 @@ namespace Fantasy
[ProtoMember(2)]
public uint ErrorCode { get; set; }
}
- ///
- /// 发送一个RPC消息给Map,让Map里的Entity转移到另外一个Map上
- ///
- [ProtoContract]
- public partial class C2M_MoveToMapRequest : AMessage, IAddressableRouteRequest, IProto
- {
- public static C2M_MoveToMapRequest Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- [ProtoIgnore]
- public M2C_MoveToMapResponse ResponseType { get; set; }
- public uint OpCode() { return OuterOpcode.C2M_MoveToMapRequest; }
- }
- [ProtoContract]
- public partial class M2C_MoveToMapResponse : AMessage, IAddressableRouteResponse, IProto
- {
- public static M2C_MoveToMapResponse 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.M2C_MoveToMapResponse; }
- [ProtoMember(1)]
- public uint ErrorCode { get; set; }
- }
- ///
- /// 发送一个消息给Gate,让Gate发送一个Addressable消息给MAP
- ///
- [ProtoContract]
- public partial class C2G_SendAddressableToMap : AMessage, IMessage, IProto
- {
- public static C2G_SendAddressableToMap Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2G_SendAddressableToMap; }
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- ///
- /// 发送一个消息给Chat,让Chat服务器主动推送一个RouteMessage消息给客户端
- ///
- [ProtoContract]
- public partial class C2Chat_TestRequestPushMessage : AMessage, ICustomRouteMessage, IProto
- {
- public static C2Chat_TestRequestPushMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2Chat_TestRequestPushMessage; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RouteType.ChatRoute;
- }
- ///
- /// Chat服务器主动推送一个消息给客户端
- ///
- [ProtoContract]
- public partial class Chat2C_PushMessage : AMessage, ICustomRouteMessage, IProto
- {
- public static Chat2C_PushMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.Chat2C_PushMessage; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RouteType.ChatRoute;
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- ///
- /// 客户端发送给Gate服务器通知map服务器创建一个SubScene
- ///
- [ProtoContract]
- public partial class C2G_CreateSubSceneRequest : AMessage, IRequest, IProto
- {
- public static C2G_CreateSubSceneRequest Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- [ProtoIgnore]
- public G2C_CreateSubSceneResponse ResponseType { get; set; }
- public uint OpCode() { return OuterOpcode.C2G_CreateSubSceneRequest; }
- }
- [ProtoContract]
- public partial class G2C_CreateSubSceneResponse : AMessage, IResponse, IProto
- {
- public static G2C_CreateSubSceneResponse 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.G2C_CreateSubSceneResponse; }
- [ProtoMember(1)]
- public uint ErrorCode { get; set; }
- }
- ///
- /// 客户端通知Gate服务器给SubScene发送一个消息
- ///
- [ProtoContract]
- public partial class C2G_SendToSubSceneMessage : AMessage, IMessage, IProto
- {
- public static C2G_SendToSubSceneMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2G_SendToSubSceneMessage; }
- }
- ///
- /// 客户端通知Gate服务器创建一个SubScene的Address消息
- ///
- [ProtoContract]
- public partial class C2G_CreateSubSceneAddressableRequest : AMessage, IRequest, IProto
- {
- public static C2G_CreateSubSceneAddressableRequest Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- [ProtoIgnore]
- public G2C_CreateSubSceneAddressableResponse ResponseType { get; set; }
- public uint OpCode() { return OuterOpcode.C2G_CreateSubSceneAddressableRequest; }
- }
- [ProtoContract]
- public partial class G2C_CreateSubSceneAddressableResponse : AMessage, IResponse, IProto
- {
- public static G2C_CreateSubSceneAddressableResponse 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.G2C_CreateSubSceneAddressableResponse; }
- [ProtoMember(1)]
- public uint ErrorCode { get; set; }
- }
- ///
- /// 客户端向SubScene发送一个测试消息
- ///
- [ProtoContract]
- public partial class C2SubScene_TestMessage : AMessage, IAddressableRouteMessage, IProto
- {
- public static C2SubScene_TestMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2SubScene_TestMessage; }
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- ///
- /// 客户端向SubScene发送一个销毁测试消息
- ///
- [ProtoContract]
- public partial class C2SubScene_TestDisposeMessage : AMessage, IAddressableRouteMessage, IProto
- {
- public static C2SubScene_TestDisposeMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2SubScene_TestDisposeMessage; }
- }
- ///
- /// 客户端向服务器发送连接消息(Roaming)
- ///
- [ProtoContract]
- public partial class C2G_ConnectRoamingRequest : AMessage, IRequest, IProto
- {
- public static C2G_ConnectRoamingRequest Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- [ProtoIgnore]
- public G2C_ConnectRoamingResponse ResponseType { get; set; }
- public uint OpCode() { return OuterOpcode.C2G_ConnectRoamingRequest; }
- }
- [ProtoContract]
- public partial class G2C_ConnectRoamingResponse : AMessage, IResponse, IProto
- {
- public static G2C_ConnectRoamingResponse 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.G2C_ConnectRoamingResponse; }
- [ProtoMember(1)]
- public uint ErrorCode { get; set; }
- }
- ///
- /// 测试一个Chat漫游普通消息
- ///
- [ProtoContract]
- public partial class C2Chat_TestRoamingMessage : AMessage, IRoamingMessage, IProto
- {
- public static C2Chat_TestRoamingMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2Chat_TestRoamingMessage; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RoamingType.ChatRoamingType;
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- ///
- /// 测试一个Map漫游普通消息
- ///
- [ProtoContract]
- public partial class C2Map_TestRoamingMessage : AMessage, IRoamingMessage, IProto
- {
- public static C2Map_TestRoamingMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2Map_TestRoamingMessage; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RoamingType.MapRoamingType;
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- ///
- /// 测试一个Chat漫游RPC消息
- ///
- [ProtoContract]
- public partial class C2Chat_TestRPCRoamingRequest : AMessage, IRoamingRequest, IProto
- {
- public static C2Chat_TestRPCRoamingRequest Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- [ProtoIgnore]
- public Chat2C_TestRPCRoamingResponse ResponseType { get; set; }
- public uint OpCode() { return OuterOpcode.C2Chat_TestRPCRoamingRequest; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RoamingType.ChatRoamingType;
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- [ProtoContract]
- public partial class Chat2C_TestRPCRoamingResponse : AMessage, IRoamingResponse, IProto
- {
- public static Chat2C_TestRPCRoamingResponse 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.Chat2C_TestRPCRoamingResponse; }
- [ProtoMember(1)]
- public uint ErrorCode { get; set; }
- }
- ///
- /// 客户端发送一个漫游消息给Map通知Map主动推送一个消息给客户端
- ///
- [ProtoContract]
- public partial class C2Map_PushMessageToClient : AMessage, IRoamingMessage, IProto
- {
- public static C2Map_PushMessageToClient Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2Map_PushMessageToClient; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RoamingType.MapRoamingType;
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- ///
- /// 漫游端发送一个消息给客户端
- ///
- [ProtoContract]
- public partial class Map2C_PushMessageToClient : AMessage, IRoamingMessage, IProto
- {
- public static Map2C_PushMessageToClient Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.Map2C_PushMessageToClient; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RoamingType.MapRoamingType;
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
- ///
- /// 测试传送漫游的触发协议
- ///
- [ProtoContract]
- public partial class C2Map_TestTransferRequest : AMessage, IRoamingRequest, IProto
- {
- public static C2Map_TestTransferRequest Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- [ProtoIgnore]
- public Map2C_TestTransferResponse ResponseType { get; set; }
- public uint OpCode() { return OuterOpcode.C2Map_TestTransferRequest; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RoamingType.MapRoamingType;
- }
- [ProtoContract]
- public partial class Map2C_TestTransferResponse : AMessage, IRoamingResponse, IProto
- {
- public static Map2C_TestTransferResponse 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.Map2C_TestTransferResponse; }
- [ProtoMember(1)]
- public uint ErrorCode { get; set; }
- }
- ///
- /// 测试一个Chat发送到Map之间漫游协议
- ///
- [ProtoContract]
- public partial class C2Chat_TestSendMapMessage : AMessage, IRoamingMessage, IProto
- {
- public static C2Chat_TestSendMapMessage Create(Scene scene)
- {
- return scene.MessagePoolComponent.Rent();
- }
- public override void Dispose()
- {
- Tag = default;
-#if FANTASY_NET || FANTASY_UNITY
- GetScene().MessagePoolComponent.Return(this);
-#endif
- }
- public uint OpCode() { return OuterOpcode.C2Chat_TestSendMapMessage; }
- [ProtoIgnore]
- public int RouteType => Fantasy.RoamingType.ChatRoamingType;
- [ProtoMember(1)]
- public string Tag { get; set; }
- }
}
diff --git a/Entity/Generate/NetworkProtocol/OuterOpcode.cs b/Entity/Generate/NetworkProtocol/OuterOpcode.cs
index c37210e..9dd0ec8 100644
--- a/Entity/Generate/NetworkProtocol/OuterOpcode.cs
+++ b/Entity/Generate/NetworkProtocol/OuterOpcode.cs
@@ -2,43 +2,27 @@ namespace Fantasy
{
public static partial class OuterOpcode
{
- public const uint C2G_TestMessage = 134227729;
- public const uint C2G_TestRequest = 268445457;
- public const uint G2C_TestResponse = 402663185;
- public const uint C2G_TestRequestPushMessage = 134227730;
- public const uint G2C_PushMessage = 134227731;
- public const uint C2G_CreateAddressableRequest = 268445458;
- public const uint G2C_CreateAddressableResponse = 402663186;
+ public const uint C2A_RegisterRequest = 268445457;
+ public const uint A2C_RegisterResponse = 402663185;
+ public const uint C2A_LoginRequest = 268445458;
+ public const uint A2C_LoginResponse = 402663186;
+ public const uint C2G_LoginRequest = 268445459;
+ public const uint G2C_LoginResponse = 402663187;
+ public const uint G2C_RepeatLogin = 134227729;
+ public const uint C2G_GetAccountInfoRequest = 268445460;
+ public const uint G2C_GetAccountInfoResponse = 402663188;
+ public const uint C2G_TestMessage = 134227730;
+ public const uint C2G_TestRequest = 268445461;
+ public const uint G2C_TestResponse = 402663189;
+ public const uint C2G_CreateAddressableRequest = 268445462;
+ public const uint G2C_CreateAddressableResponse = 402663190;
public const uint C2M_TestMessage = 1342187281;
public const uint C2M_TestRequest = 1476405009;
public const uint M2C_TestResponse = 1610622737;
- public const uint C2G_CreateChatRouteRequest = 268445459;
- public const uint G2C_CreateChatRouteResponse = 402663187;
+ public const uint C2G_CreateChatRouteRequest = 268445463;
+ public const uint G2C_CreateChatRouteResponse = 402663191;
public const uint C2Chat_TestMessage = 2147493649;
public const uint C2Chat_TestMessageRequest = 2281711377;
public const uint Chat2C_TestMessageResponse = 2415929105;
- public const uint C2M_MoveToMapRequest = 1476405010;
- public const uint M2C_MoveToMapResponse = 1610622738;
- public const uint C2G_SendAddressableToMap = 134227732;
- public const uint C2Chat_TestRequestPushMessage = 2147493650;
- public const uint Chat2C_PushMessage = 2147493651;
- public const uint C2G_CreateSubSceneRequest = 268445460;
- public const uint G2C_CreateSubSceneResponse = 402663188;
- public const uint C2G_SendToSubSceneMessage = 134227733;
- public const uint C2G_CreateSubSceneAddressableRequest = 268445461;
- public const uint G2C_CreateSubSceneAddressableResponse = 402663189;
- public const uint C2SubScene_TestMessage = 1342187282;
- public const uint C2SubScene_TestDisposeMessage = 1342187283;
- public const uint C2G_ConnectRoamingRequest = 268445462;
- public const uint G2C_ConnectRoamingResponse = 402663190;
- public const uint C2Chat_TestRoamingMessage = 2550146833;
- public const uint C2Map_TestRoamingMessage = 2550146834;
- public const uint C2Chat_TestRPCRoamingRequest = 2684364561;
- public const uint Chat2C_TestRPCRoamingResponse = 2818582289;
- public const uint C2Map_PushMessageToClient = 2550146835;
- public const uint Map2C_PushMessageToClient = 2550146836;
- public const uint C2Map_TestTransferRequest = 2684364562;
- public const uint Map2C_TestTransferResponse = 2818582290;
- public const uint C2Chat_TestSendMapMessage = 2550146837;
}
}
diff --git a/Entity/LockType.cs b/Entity/LockType.cs
new file mode 100644
index 0000000..c0ea4d7
--- /dev/null
+++ b/Entity/LockType.cs
@@ -0,0 +1,9 @@
+namespace Fantasy;
+
+public enum LockType
+{
+ None = 0,
+ AuthenticationRegisterLock = 1, // 鉴权注册锁
+ AuthenticationRemoveLock = 1, // 鉴权移除锁
+ AuthenticationLoginLock = 2 // 鉴权登录锁
+}
\ No newline at end of file
diff --git a/Hotfix/CustomSystem/IRunSystem.cs b/Hotfix/CustomSystem/IRunSystem.cs
index 7b0d970..8c9fb69 100644
--- a/Hotfix/CustomSystem/IRunSystem.cs
+++ b/Hotfix/CustomSystem/IRunSystem.cs
@@ -2,12 +2,14 @@ using Fantasy.Entitas;
using Fantasy.Entitas.Interface;
namespace Fantasy;
+
// 这个是一个自定义系统类型,用于决定系统类型。
// 也可以用枚举,看个人怎么使用了。
public static class CustomSystemType
{
public const int RunSystem = 1;
}
+
// 这个是一个自定义系统,用于处理自定义事件。
public abstract class RunSystem : CustomSystem where T : Entity
{
@@ -15,23 +17,26 @@ public abstract class RunSystem : CustomSystem where T : Entity
/// 自定义事件类型,用于决定事件的类型。
///
public override int CustomEventType => CustomSystemType.RunSystem;
+
///
/// 不知道为什么这样定义的,就照搬就可以了。
///
///
protected abstract override void Custom(T self);
+
///
/// 不知道为什么这样定义的,就照搬就可以了。
///
///
public override Type EntitiesType() => typeof(T);
}
+
// 下面是一个测试自定义系统。
// 首先定义一个组件用来测试自定义系统。
public class TestCustomSystemComponent : Entity
{
-
}
+
// 现在给TestCustomSystemComponent组件添加一个自定义系统。
// 现在添加的就是上面定义的RunSystem自定义系统。
public class TestCustomSystemComponentRunSystem : RunSystem
@@ -47,4 +52,4 @@ public class TestCustomSystemComponentRunSystem : RunSystem();
+
+ if (sessionTimeOutComponent == null)
+ {
+ sessionTimeOutComponent = entity.AddComponent();
+ sessionTimeOutComponent.SetInterval(interval);
+ return true;
+ }
+
+ return sessionTimeOutComponent.CheckInterval();
+ }
+
+ public static void SetTimeout(this Entity entity, int timeout = 3000, Func? task = null)
+ {
+ var sessionTimeOutComponent = entity.GetComponent();
+
+ if (sessionTimeOutComponent == null)
+ {
+ sessionTimeOutComponent = entity.AddComponent();
+ }
+
+ sessionTimeOutComponent.TimeOut(timeout, task);
+ }
+
+ public static bool IsTimeOutComponent(this Entity entity)
+ {
+ return entity.GetComponent() != null;
+ }
+
+ public static void CancelTimeout(this Entity entity)
+ {
+ entity.RemoveComponent();
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/EntityTimeOutComponentSystem.cs b/Hotfix/EntityTimeOutComponentSystem.cs
new file mode 100644
index 0000000..05fabc0
--- /dev/null
+++ b/Hotfix/EntityTimeOutComponentSystem.cs
@@ -0,0 +1,78 @@
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Entitas.Interface;
+using Fantasy.Helper;
+
+namespace System.Authentication;
+
+public sealed class EntityTimeOutComponentDestroySystem : DestroySystem
+{
+ protected override void Destroy(EntityTimeOutComponent self)
+ {
+ if (self.TimerId != 0)
+ {
+ self.Scene.TimerComponent.Net.Remove(ref self.TimerId);
+ }
+
+ self.NextTime = 0;
+ self.Interval = 0;
+ }
+}
+
+public static class EntityTimeOutComponentSystem
+{
+ public static void SetInterval(this EntityTimeOutComponent self, int interval)
+ {
+ if (interval <= 0)
+ {
+ throw new ArgumentException("interval must be greater than 0", nameof(interval));
+ }
+
+ self.Interval = interval;
+ self.NextTime = TimeHelper.Now + interval;
+ }
+
+ public static bool CheckInterval(this EntityTimeOutComponent self)
+ {
+ if (self.NextTime > TimeHelper.Now)
+ {
+ Log.Warning("当前连接请求的间隔过小");
+ return false;
+ }
+
+ self.NextTime = TimeHelper.Now + self.Interval;
+ return true;
+ }
+
+ public static void TimeOut(this EntityTimeOutComponent self, int timeout, Func? task = null)
+ {
+ var scene = self.Scene;
+ var parentRunTimeId = self.Parent.RuntimeId;
+
+ if (self.TimerId != 0)
+ {
+ self.Scene.TimerComponent.Net.Remove(ref self.TimerId);
+ }
+
+ self.TimerId =
+ scene.TimerComponent.Net.OnceTimer(timeout, () => { self.Handler(parentRunTimeId, task).Coroutine(); });
+ }
+
+ private static async FTask Handler(this EntityTimeOutComponent self, long parentRunTimeId, Func? task = null)
+ {
+ var selfParent = self.Parent;
+
+ if (selfParent == null || parentRunTimeId != selfParent.RuntimeId)
+ {
+ return;
+ }
+
+ if (task != null)
+ {
+ await task();
+ }
+
+ self.TimerId = 0;
+ selfParent.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Hotfix.csproj b/Hotfix/Hotfix.csproj
index b39f153..22d03c7 100644
--- a/Hotfix/Hotfix.csproj
+++ b/Hotfix/Hotfix.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/Hotfix/OnSceneCreate_Init.cs b/Hotfix/OnSceneCreate_Init.cs
new file mode 100644
index 0000000..4f3f203
--- /dev/null
+++ b/Hotfix/OnSceneCreate_Init.cs
@@ -0,0 +1,38 @@
+using System.Authentication;
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Authentication;
+using Fantasy.Event;
+using Fantasy.Gate;
+
+namespace System;
+
+public class OnSceneCreate_Init : AsyncEventSystem
+{
+ protected override async FTask Handler(OnCreateScene self)
+ {
+ var scene = self.Scene;
+
+ switch (scene.SceneType)
+ {
+ case SceneType.Authentication:
+ {
+ // 用于鉴权服务器注册和登录相关逻辑的组件
+ scene.AddComponent().UpdatePosition();
+ // 用于颁发ToKen证书相关的逻辑。
+ scene.AddComponent();
+ break;
+ }
+ case SceneType.Gate:
+ {
+ // 用于验证JWT是否合法的组件
+ scene.AddComponent();
+ // 用于管理GameAccount的组件
+ scene.AddComponent();
+ break;
+ }
+ }
+
+ await FTask.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/Handler/C2A_LoginRequestHandler.cs b/Hotfix/Outer/Authentication/Handler/C2A_LoginRequestHandler.cs
new file mode 100644
index 0000000..8e80eb0
--- /dev/null
+++ b/Hotfix/Outer/Authentication/Handler/C2A_LoginRequestHandler.cs
@@ -0,0 +1,38 @@
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Authentication.Jwt;
+using Fantasy.Network;
+using Fantasy.Network.Interface;
+using Fantasy.Platform.Net;
+
+namespace Fantasy.Authentication.Handler;
+
+public class C2A_LoginRequestHandler : MessageRPC
+{
+ protected override async FTask Run(Session session, C2A_LoginRequest request, A2C_LoginResponse response,
+ Action reply)
+ {
+ var scene = session.Scene;
+ var result = await AuthenticationHelper.Login(scene, request.Username, request.Password);
+
+ if (result.ErrorCode == 0)
+ {
+ // 通过配置表或其他方式拿到Gate服务器组的信息
+ var gates = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Gate);
+ // 通过当前账号的ID拿到要分配Gate服务器
+ var gatePosition = result.AccountId % gates.Count;
+ // 通过计算出来的位置下标拿到Gate服务器的配置
+ var gateSceneConfig = gates[(int)gatePosition];
+ // 通过Gate的SceneConfig文件拿到外网的ID地址和端口
+ var outerPort = gateSceneConfig.OuterPort;
+ var processConfig = ProcessConfigData.Instance.Get(gateSceneConfig.ProcessConfigId);
+ var machineConfig = MachineConfigData.Instance.Get(processConfig.MachineId);
+ // 颁发一个ToKen令牌给客户端
+ response.ToKen = AuthenticationJwtHelper.GetToken(scene, result.AccountId,
+ $"{machineConfig.OuterIP}:{outerPort}", gateSceneConfig.Id);
+ }
+
+ response.ErrorCode = result.ErrorCode;
+ Log.Debug($"Login 当前的服务器是:{scene.SceneConfigId}");
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/Handler/C2A_RegisterRequestHandler.cs b/Hotfix/Outer/Authentication/Handler/C2A_RegisterRequestHandler.cs
new file mode 100644
index 0000000..5fa3be1
--- /dev/null
+++ b/Hotfix/Outer/Authentication/Handler/C2A_RegisterRequestHandler.cs
@@ -0,0 +1,25 @@
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Network;
+using Fantasy.Network.Interface;
+
+namespace Fantasy.Authentication.Handler;
+
+public sealed class C2A_RegisterRequestHandler : MessageRPC
+{
+ protected override async FTask Run(Session session, C2A_RegisterRequest request, A2C_RegisterResponse response,
+ Action reply)
+ {
+ if (!session.CheckInterval(2000))
+ {
+ // 返回这个3代表操作过于频繁。
+ response.ErrorCode = 3;
+ return;
+ }
+
+ session.SetTimeout(3000);
+ response.ErrorCode =
+ await AuthenticationHelper.Register(session.Scene, request.Username, request.Password, "用户注册");
+ Log.Debug($"Register 当前的服务器是:{session.Scene.SceneConfigId}");
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/System/AccountSystem.cs b/Hotfix/Outer/Authentication/System/AccountSystem.cs
new file mode 100644
index 0000000..6696f3c
--- /dev/null
+++ b/Hotfix/Outer/Authentication/System/AccountSystem.cs
@@ -0,0 +1,15 @@
+using Fantasy;
+using Fantasy.Entitas.Interface;
+
+namespace Fantasy.Authentication;
+
+public class AccountDestroySystem : DestroySystem
+{
+ protected override void Destroy(Account self)
+ {
+ self.Username = null;
+ self.Password = null;
+ self.CreateTime = 0;
+ self.LoginTime = 0;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/System/AuthenticationComponentSystem.cs b/Hotfix/Outer/Authentication/System/AuthenticationComponentSystem.cs
new file mode 100644
index 0000000..35c015a
--- /dev/null
+++ b/Hotfix/Outer/Authentication/System/AuthenticationComponentSystem.cs
@@ -0,0 +1,239 @@
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Entitas;
+using Fantasy.Entitas.Interface;
+using Fantasy.Helper;
+using Fantasy.Platform.Net;
+
+// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
+#pragma warning disable CS8602 // Dereference of a possibly null reference.
+#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
+
+namespace Fantasy.Authentication;
+
+public sealed class AuthenticationComponentDestroySystem : DestroySystem
+{
+ protected override void Destroy(AuthenticationComponent self)
+ {
+ foreach (var (_, account) in self.Accounts.ToArray())
+ {
+ account.Dispose();
+ }
+
+ self.Accounts.Clear();
+ }
+}
+
+internal static class AuthenticationComponentSystem
+{
+ public static void UpdatePosition(this AuthenticationComponent self)
+ {
+ // 1、通过远程接口或者本地文件来拿到鉴权组
+ // 2、通过配置文件来拿
+ var authentications = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Authentication);
+ // 拿到当前Scene的配置文件
+ var sceneConfig = SceneConfigData.Instance.Get(self.Scene.SceneConfigId);
+ // 获取到当前Scene在鉴权组的位置
+ self.Position = authentications.IndexOf(sceneConfig);
+ // 获得鉴权组的总数
+ self.AuthenticationCount = authentications.Count;
+ Log.Info($"鉴权服务器启动成功!Position:{self.Position} AuthenticationCount:{self.AuthenticationCount}");
+ }
+
+ internal static async FTask<(uint ErrorCode, long AccountId)> Login(this AuthenticationComponent self, string userName, string password)
+ {
+ // 1、检查传递的参数是否完整
+
+ if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
+ {
+ // 这个1代表的是参数不完整。
+ return (1, 0);
+ }
+
+ // 检查账号是否应该在当前鉴权服务器中处理
+
+ var position = HashCodeHelper.MurmurHash3(userName) % self.AuthenticationCount;
+ if (self.Position != position)
+ {
+ // 这个3代表的是当前账号不应该在这个鉴权服务器处理。
+ return (3, 0);
+ }
+
+ var scene = self.Scene;
+ var worldDateBase = scene.World.DataBase;//DateBase
+ var usernameHashCode = userName.GetHashCode();
+
+ using (var @lock = await scene.CoroutineLockComponent.Wait((int)LockType.AuthenticationLoginLock, usernameHashCode))
+ {
+ // 如果用户频繁发生登录的请求,导致服务器会频繁请求数据库或缓存。
+ // 针对这个问题咱们可以利用缓存来解决这个问题。
+ // 1、创建一个新的字典容器在AuthenticationComponent中存储登录的信息。
+ // 2、key:userName + password, Value = ?
+ // 3、为了防止缓存暴涨、肯定需要一个定期清理的过程,Value肯定是要一个实体了。
+ // 4、因为这个实体下面咱们可以挂载一个组件,这个组件的作用就是定时清理这个缓存。
+
+ // 问题
+ // 1、如果用户的密码改了怎么办?
+ // 因为缓存中有定时清除的,所以遇到改密码的情况下,最多等待这个缓存清除了,然后就可以登录了。
+ // 2、如果我不这样做,还有什么其他办法?
+ // 通过防火墙的策略来限制用户请求,比如100ms请求一次。
+
+ // 作业:
+ // 在这个AccountCacheInfo下创建一个组件,这个组件的功能就是定时清理这个缓存。
+
+ Account account = null;
+ var loginAccountsKey = userName + password;
+
+ if (self.LoginAccounts.TryGetValue(loginAccountsKey, out var accountCacheInfo))
+ {
+ account = accountCacheInfo.GetComponent();
+
+ if (account == null)
+ {
+ return (2, 0);
+ }
+
+ return (0, account.Id);
+ }
+
+ uint result = 0;
+ accountCacheInfo = Entity.Create(scene, true, true);
+ account = await worldDateBase.First(d => d.Username == userName && d.Password == password);
+
+ if (account == null)
+ {
+ // 这个2代表的是该用户没有注册或者用户或密码错误
+ result = 2;
+ }
+ else
+ {
+ // 更新登录时间,并保存到数据库
+ account.LoginTime = TimeHelper.Now;
+ await worldDateBase.Save(account);
+ // 添加Account到缓存中
+ account.Deserialize(scene);
+ accountCacheInfo.AddComponent(account);
+ }
+
+ accountCacheInfo.AddComponent().TimeOut(loginAccountsKey, 5000);
+ self.LoginAccounts.Add(loginAccountsKey, accountCacheInfo);
+
+ if (result != 0)
+ {
+ return (result, 0);
+ }
+
+ return (0, account.Id);
+ }
+ }
+
+ ///
+ /// 鉴权注册接口
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static async FTask Register(this AuthenticationComponent self, string username, string password, string source)
+ {
+ // 1、检查传递的参数是否完整
+
+ if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
+ {
+ // 这个1代表的是参数不完整。
+ return 1;
+ }
+
+ // 检查账号是否应该在当前鉴权服务器中处理
+
+ var position = HashCodeHelper.MurmurHash3(username) % self.AuthenticationCount;
+ if (self.Position != position)
+ {
+ // 这个3代表的是当前账号不应该在这个鉴权服务器处理。
+ return 3;
+ }
+
+ var usernameHashCode = username.GetHashCode();
+ var scene = self.Scene;
+
+ // 利用协程锁来解决异步的原子问题
+ using (var @lock = await scene.CoroutineLockComponent.Wait((int)LockType.AuthenticationRegisterLock, usernameHashCode))
+ {
+ // 利用缓存来减少频繁请求数据库或缓存的压力。
+
+ if (self.Accounts.TryGetValue(username, out var account))
+ {
+ // 这个2代表的是该用户已经存在。
+ return 2;
+ }
+
+ // 2、数据库查询该账号是否存在
+ var worldDateBase = scene.World.DataBase;
+ var isExist = await worldDateBase.Exist(d => d.Username == username);
+ if (isExist)
+ {
+ // 这个2代表的是该用户已经存在。
+ return 2;
+ }
+
+ //3、执行到这里的话,表示数据库或缓存没有该账号的注册信息,需要咱们创建一个。
+ account = Entity.Create(scene, true, true);
+ account.Username = username;
+ account.Password = password;
+ account.CreateTime = TimeHelper.Now;
+ // 写入这个实体到数据中
+ await worldDateBase.Save(account);
+ var accountId = account.Id;
+ // 把当前账号添加到缓存字典中。
+ self.Accounts.Add(username, account);
+ // 添加AccountTimeOut组件用来定时清除缓存
+ account.AddComponent().TimeOut(4000);
+ // 这个0代表的是操作成功
+ Log.Info($"Register source:{source} username:{username} accountId:{accountId}");
+ return 0;
+ }
+ }
+
+ internal static void RemoveLoginAccounts(this AuthenticationComponent self, string key, bool isDispose)
+ {
+ if (!self.LoginAccounts.Remove(key, out var accountCacheInfo))
+ {
+ return;
+ }
+
+ if (isDispose)
+ {
+ accountCacheInfo.Dispose();
+ }
+ }
+
+ internal static void RemoveCache(this AuthenticationComponent self, string username, bool isDispose)
+ {
+ if (!self.Accounts.Remove(username, out var account))
+ {
+ return;
+ }
+
+ Log.Debug($"Remove cache username:{username} Count:{self.Accounts.Count}");
+
+ if (isDispose)
+ {
+ account.Dispose();
+ }
+ }
+
+ internal static async FTask Remove(this AuthenticationComponent self, long accountId, string source)
+ {
+ var scene = self.Scene;
+
+ // 其实呢,这里没必要加协程锁,这里加是为了给大家加深下这个协程锁的印象。
+
+ using (var @lock = await scene.CoroutineLockComponent.Wait((int)LockType.AuthenticationRemoveLock, accountId))
+ {
+ var worldDateBase = scene.World.DataBase;
+ await worldDateBase.Remove(accountId);
+ Log.Info($"Remove source:{source} accountId:{accountId}");
+ return 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/System/AuthenticationHelper.cs b/Hotfix/Outer/Authentication/System/AuthenticationHelper.cs
new file mode 100644
index 0000000..fe178a4
--- /dev/null
+++ b/Hotfix/Outer/Authentication/System/AuthenticationHelper.cs
@@ -0,0 +1,66 @@
+using Fantasy;
+using Fantasy.Async;
+
+namespace Fantasy.Authentication;
+
+public static class AuthenticationHelper
+{
+ ///
+ /// 登录账号
+ ///
+ ///
+ /// 用户名
+ /// 用户密码
+ ///
+ public static async FTask<(uint ErrorCode, long AccountId)> Login(Scene scene, string userName, string password)
+ {
+ return await scene.GetComponent().Login(userName, password);
+ }
+
+ ///
+ /// 注册一个新的账号
+ ///
+ ///
+ /// 用户名
+ /// 用户密码
+ /// 注册的来源/原因
+ ///
+ public static async FTask Register(Scene scene, string username, string password, string source)
+ {
+ return await scene.GetComponent().Register(username, password, source);
+ }
+
+ ///
+ /// 移除一个账号
+ ///
+ ///
+ /// 账号ID
+ /// 移除的来源/原因
+ ///
+ public static async FTask Remove(Scene scene, long accountId, string source)
+ {
+ return await scene.GetComponent().Remove(accountId, source);
+ }
+
+ ///
+ /// 移除缓存中的Account
+ ///
+ ///
+ /// 账号名字
+ /// 是否销毁
+ public static void RemoveCache(Scene scene, string username, bool isDispose)
+ {
+ scene.GetComponent().RemoveCache(username, isDispose);
+ }
+
+ ///
+ /// 移除LoginAccounts缓存中的数据,仅供内部调用,不明白原理的不要调用,否则后果自负。
+ ///
+ ///
+ ///
+ ///
+ internal static void RemoveLoginAccounts(Scene scene, string key, bool isDispose)
+ {
+ scene.GetComponent().RemoveLoginAccounts(key, isDispose);
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/System/Jwt/AuthenticationJwtComponentSystem.cs b/Hotfix/Outer/Authentication/System/Jwt/AuthenticationJwtComponentSystem.cs
new file mode 100644
index 0000000..7b5cd06
--- /dev/null
+++ b/Hotfix/Outer/Authentication/System/Jwt/AuthenticationJwtComponentSystem.cs
@@ -0,0 +1,55 @@
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Cryptography;
+using Fantasy;
+using Fantasy.Entitas.Interface;
+using Microsoft.IdentityModel.Tokens;
+
+namespace Fantasy.Authentication.Jwt;
+
+public sealed class AuthenticationJwtComponentAwakeSystem : AwakeSystem
+{
+ protected override void Awake(AuthenticationJwtComponent self)
+ {
+ self.Awake();
+ }
+}
+
+public static class AuthenticationJwtComponentSystem
+{
+ public static void Awake(this AuthenticationJwtComponent self)
+ {
+ var rsa = RSA.Create();
+ rsa.ImportRSAPublicKey(Convert.FromBase64String(self.PublicKeyPem), out _);
+ rsa.ImportRSAPrivateKey(Convert.FromBase64String(self.PrivateKeyPem), out _);
+ self.SigningCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256);
+ // 创建 TokenValidationParameters 对象,用于配置验证参数
+ self.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateLifetime = false, // 禁止令牌验证时间是否过期
+ ValidateIssuer = true, // 验证发行者
+ ValidateAudience = true, // 验证受众
+ ValidateIssuerSigningKey = true, // 验证签名密钥
+ ValidIssuer = "Fantasy", // 有效的发行者
+ ValidAudience = "Fantasy", // 有效的受众
+ IssuerSigningKey = new RsaSecurityKey(rsa) // RSA公钥作为签名密钥
+ };
+ }
+
+ public static string GetToken(this AuthenticationJwtComponent self, long aId, string address, uint sceneId)
+ {
+ var jwtPayload = new JwtPayload()
+ {
+ { "aId", aId },
+ { "Address", address },
+ { "SceneId", sceneId }
+ };
+
+ var jwtSecurityToken = new JwtSecurityToken(
+ issuer: "Fantasy",
+ audience: "Fantasy",
+ claims: jwtPayload.Claims,
+ expires: DateTime.UtcNow.AddMilliseconds(3000),
+ signingCredentials: self.SigningCredentials);
+ return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/System/Jwt/AuthenticationJwtHelper.cs b/Hotfix/Outer/Authentication/System/Jwt/AuthenticationJwtHelper.cs
new file mode 100644
index 0000000..48fa320
--- /dev/null
+++ b/Hotfix/Outer/Authentication/System/Jwt/AuthenticationJwtHelper.cs
@@ -0,0 +1,19 @@
+using Fantasy;
+
+namespace Fantasy.Authentication.Jwt;
+
+public static class AuthenticationJwtHelper
+{
+ ///
+ /// 获取一个新的令牌
+ ///
+ ///
+ /// AccountId
+ /// 目标服务器的地址
+ /// 分配的Scene的Id
+ ///
+ public static string GetToken(Scene scene, long aId, string address, uint sceneId)
+ {
+ return scene.GetComponent().GetToken(aId, address, sceneId);
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/System/TimeOut/AccountCacheInfoTimeOutSystem.cs b/Hotfix/Outer/Authentication/System/TimeOut/AccountCacheInfoTimeOutSystem.cs
new file mode 100644
index 0000000..a81849b
--- /dev/null
+++ b/Hotfix/Outer/Authentication/System/TimeOut/AccountCacheInfoTimeOutSystem.cs
@@ -0,0 +1,40 @@
+using Fantasy;
+using Fantasy.Entitas.Interface;
+// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
+
+namespace Fantasy.Authentication;
+
+public sealed class AccountCacheInfoTimeOutDestroySystem : DestroySystem
+{
+ protected override void Destroy(AccountCacheInfoTimeOut self)
+ {
+ if (self.TimerId != 0)
+ {
+ self.Scene.TimerComponent.Net.Remove(ref self.TimerId);
+ }
+
+ self.Key = null;
+ }
+}
+
+public static class AccountCacheInfoTimeOutSystem
+{
+ public static void TimeOut(this AccountCacheInfoTimeOut self, string key, int timeout)
+ {
+ self.Key = key;
+ // 创建一个任务计时器、用在timeout时间后执行,并且要清楚掉当前鉴权服务器缓存
+ var scene = self.Scene;
+ var runTimeId = self.RuntimeId;
+
+ self.TimerId = scene.TimerComponent.Net.OnceTimer(timeout, () =>
+ {
+ if (runTimeId != self.RuntimeId)
+ {
+ return;
+ }
+
+ self.TimerId = 0;
+ AuthenticationHelper.RemoveLoginAccounts(scene, self.Key,true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Authentication/System/TimeOut/AccountTimeOutSystem.cs b/Hotfix/Outer/Authentication/System/TimeOut/AccountTimeOutSystem.cs
new file mode 100644
index 0000000..8906e62
--- /dev/null
+++ b/Hotfix/Outer/Authentication/System/TimeOut/AccountTimeOutSystem.cs
@@ -0,0 +1,37 @@
+using Fantasy;
+using Fantasy.Entitas.Interface;
+
+namespace Fantasy.Authentication;
+
+public sealed class AccountTimeOutDestroySystem : DestroySystem
+{
+ protected override void Destroy(AccountTimeOut self)
+ {
+ if (self.TimerId != 0)
+ {
+ self.Scene.TimerComponent.Net.Remove(ref self.TimerId);
+ }
+ }
+}
+
+public static class AccountTimeOutSystem
+{
+ public static void TimeOut(this AccountTimeOut self, int timeout)
+ {
+ // 创建一个任务计时器、用在timeout时间后执行,并且要清楚掉当前鉴权服务器缓存
+ var scene = self.Scene;
+ var account = (Account)self.Parent;
+ var accountRunTimeId = account.RuntimeId;
+
+ self.TimerId = scene.TimerComponent.Net.OnceTimer(timeout, () =>
+ {
+ if (accountRunTimeId != account.RuntimeId)
+ {
+ return;
+ }
+
+ self.TimerId = 0;
+ AuthenticationHelper.RemoveCache(scene, account.Username,true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Addresable/C2G_CreateAddressableRequestHandler.cs b/Hotfix/Outer/Demo/Addresable/C2G_CreateAddressableRequestHandler.cs
deleted file mode 100644
index 6424749..0000000
--- a/Hotfix/Outer/Demo/Addresable/C2G_CreateAddressableRequestHandler.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Route;
-using Fantasy.Platform.Net;
-
-namespace Fantasy;
-
-public sealed class
- C2G_CreateAddressableRequestHandler : MessageRPC
-{
- protected override async FTask Run(Session session, C2G_CreateAddressableRequest request,
- G2C_CreateAddressableResponse response, Action reply)
- {
- var scene = session.Scene;
- // 1、首先要通过SceneConfig配置文件拿到进行注册Addressable协议的服务器
- // 实际开发的时候,可能会根据一些规则来选择不同的Map服务器。
- // 演示的例子里只有一个MapScene,所以我就拿第一个Map服务器进行通讯了。
- // 我这里仅是演示功能,不是一定要这样拿Map
- var sceneConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Map)[0];
- // 2、使用Scene.NetworkMessagingComponent.CallInnerRoute方法跟Gate服务器进行通讯。
- // b,这个Id在sceneConfig.RouteId可以获取到。
- // 第二个参数是需要发送网络协议,这个协议在Fantasy/Examples/Config/ProtoBuf里的InnerBson或Inner文件定义。
- var responseAddressableId =
- (M2G_ResponseAddressableId)await scene.NetworkMessagingComponent.CallInnerRoute(sceneConfig.RouteId,
- new G2M_RequestAddressableId());
- // 3、给session添加一个AddressableRouteComponent组件,这个组件很重要、能否转发Addressable协议主要是通过这个。
- var addressableRouteComponent = session.AddComponent();
- // 4、拿到MapScene返回的AddressableId赋值给addressableRouteComponent.AddressableId。
- addressableRouteComponent.AddressableId = responseAddressableId.AddressableId;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Addresable/C2G_SendAddressableToMapHandler.cs b/Hotfix/Outer/Demo/Addresable/C2G_SendAddressableToMapHandler.cs
deleted file mode 100644
index 6fa4f89..0000000
--- a/Hotfix/Outer/Demo/Addresable/C2G_SendAddressableToMapHandler.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Route;
-// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
-
-namespace Fantasy;
-
-public sealed class C2G_SendAddressableToMapHandler : Message
-{
- protected override async FTask Run(Session session, C2G_SendAddressableToMap message)
- {
- var addressableRouteComponent = session.GetComponent();
-
- if (addressableRouteComponent == null)
- {
- return;
- }
-
- // Gate发送一个Addressable消息给MAP
-
- await session.Scene.NetworkMessagingComponent.SendAddressable(addressableRouteComponent.AddressableId,
- new G2M_SendAddressableMessage()
- {
- Tag = message.Tag
- });
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Addresable/C2M_MoveToMapRequestHandler.cs b/Hotfix/Outer/Demo/Addresable/C2M_MoveToMapRequestHandler.cs
deleted file mode 100644
index 8d9630a..0000000
--- a/Hotfix/Outer/Demo/Addresable/C2M_MoveToMapRequestHandler.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using Fantasy.Async;
-using Fantasy.Entitas;
-using Fantasy.Entitas.Interface;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Route;
-using Fantasy.Platform.Net;
-using Fantasy.Serialize;
-
-namespace Fantasy;
-
-public class C2M_MoveToMapRequestHandler : AddressableRPC
-{
- protected override async FTask Run(Unit unit, C2M_MoveToMapRequest request, M2C_MoveToMapResponse response, Action reply)
- {
- // 1、首先要通过SceneConfig配置文件拿到MapScene的配置文件。
- // 这里Map[1]就是要发送的服务器,因为Map[0]是当前的Scene。
- var scene = unit.Scene;
- var mapSceneConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Map)[1];
- // 2、锁定Addressable防止在转移期间有消息发送过来。
- // LockAndRelease方法是先锁定Addressable消息后再销毁这个组件。
- // 注意:只有这个方法的销毁组件不会去Addressable里删除自己的位置信息。
- // 其他的任何销毁这个AddressableMessageComponent方法都会去Addressable里删除自己的位置信息。
- await unit.GetComponent().LockAndRelease();
- // 3、通过NetworkMessagingComponent发送内部消息给Map的Scene。
- var sendResponse = await scene.NetworkMessagingComponent.CallInnerRoute(mapSceneConfig.RouteId,
- new M2M_SendUnitRequest()
- {
- Unit = unit
- });
- if (sendResponse.ErrorCode != 0)
- {
- Log.Error($"转移Unit到目标Map服务器失败 ErrorCode={sendResponse.ErrorCode}");
- return;
- }
- // 这个Unit已经转移到另外的Map服务器了,所以就不需要这个组件了。
- unit.Dispose();
- Log.Debug("转移Unit到目标Map服务器成功");
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Addresable/C2M_TestMessageHandler.cs b/Hotfix/Outer/Demo/Addresable/C2M_TestMessageHandler.cs
deleted file mode 100644
index 3d289f4..0000000
--- a/Hotfix/Outer/Demo/Addresable/C2M_TestMessageHandler.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public sealed class C2M_TestMessageHandler : Addressable
-{
- protected override async FTask Run(Unit unit, C2M_TestMessage message)
- {
- Log.Debug($"C2M_TestMessageHandler = {message.Tag} Scene:{unit.Scene.Scene.SceneConfigId}");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Addresable/C2M_TestRequestHandler.cs b/Hotfix/Outer/Demo/Addresable/C2M_TestRequestHandler.cs
deleted file mode 100644
index 4d48001..0000000
--- a/Hotfix/Outer/Demo/Addresable/C2M_TestRequestHandler.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public sealed class C2M_TestRequestHandler : AddressableRPC
-{
- protected override async FTask Run(Unit unit, C2M_TestRequest request, M2C_TestResponse response, Action reply)
- {
- Log.Debug($"Receive C2M_TestRequest Tag = {request.Tag}");
- response.Tag = "Hello M2C_TestResponse";
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Addresable/G2M_SendAddressableMessageHandler.cs b/Hotfix/Outer/Demo/Addresable/G2M_SendAddressableMessageHandler.cs
deleted file mode 100644
index 342bf1a..0000000
--- a/Hotfix/Outer/Demo/Addresable/G2M_SendAddressableMessageHandler.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public sealed class G2M_SendAddressableMessageHandler : Addressable
-{
- protected override async FTask Run(Unit unit, G2M_SendAddressableMessage message)
- {
- Log.Debug($"收到Gate发送来的Addressable消息 message:{message.Tag}");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Addresable/M2M_SendUnitRequestHandler.cs b/Hotfix/Outer/Demo/Addresable/M2M_SendUnitRequestHandler.cs
deleted file mode 100644
index 51e109c..0000000
--- a/Hotfix/Outer/Demo/Addresable/M2M_SendUnitRequestHandler.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Route;
-
-namespace Fantasy;
-
-public class M2M_SendUnitRequestHandler : RouteRPC
-{
- protected override async FTask Run(Scene scene, M2M_SendUnitRequest request, M2M_SendUnitResponse response, Action reply)
- {
- var requestUnit = request.Unit;
- // 反序列化Unit,把Unit注册到框架中
- requestUnit.Deserialize(scene);
- // 解锁这个Unit的Addressable消息,解锁后,Gate上缓存的消息会发送到这里。
- // 由于AddressableMessageComponent不支持存数据库,所以在发送Unit的时候,会自动把这个给忽略掉。
- // 所以需要再次手动的添加下才可以。
- await requestUnit.AddComponent().UnLock("M2M_SendUnitRequestHandler");
- Log.Debug($"传送完成 {scene.SceneConfigId}");
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestMessageHandler.cs b/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestMessageHandler.cs
deleted file mode 100644
index 4649d23..0000000
--- a/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestMessageHandler.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Entitas;
-using Fantasy.Entitas.Interface;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-
-namespace Fantasy.Gate;
-
-public sealed class C2G_TestMessageHandler : Message
-{
- protected override async FTask Run(Session session, C2G_TestMessage message)
- {
- Log.Debug($"Receive C2G_TestMessage Tag={message.Tag}");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestRequestHandler.cs b/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestRequestHandler.cs
deleted file mode 100644
index a15f605..0000000
--- a/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestRequestHandler.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-
-namespace Fantasy.Gate;
-
-public sealed class C2G_TestRequestHandler : MessageRPC
-{
- protected override async FTask Run(Session session, C2G_TestRequest request, G2C_TestResponse response, Action reply)
- {
- Log.Debug($"Receive C2G_TestRequest Tag = {request.Tag}");
- response.Tag = "Hello G2C_TestResponse";
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestRequestPushMessageHandler.cs b/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestRequestPushMessageHandler.cs
deleted file mode 100644
index 3d5e00e..0000000
--- a/Hotfix/Outer/Demo/NormalMessage/Gate/C2G_TestRequestPushMessageHandler.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-
-namespace Fantasy.Gate;
-
-public sealed class C2G_TestRequestPushMessageHandler : Message
-{
- protected override async FTask Run(Session session, C2G_TestRequestPushMessage message)
- {
- // 因为没有服务器的相关的逻辑,所以制作了一个协议来触发服务器发送消息给客户端的环境。
- // 使用当前会话的Session.Send发送消息给客户端。
- // 如果需要群发,你可以用一个容器保存起来,发送的时候遍历这个容器调用Send方法就可以了。
- session.Send(new G2C_PushMessage()
- {
- Tag = "Hi G2C_PushMessage"
- });
- await FTask.CompletedTask;
- }
-}
diff --git a/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestRPCRoamingRequestHandler.cs b/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestRPCRoamingRequestHandler.cs
deleted file mode 100644
index 008a34c..0000000
--- a/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestRPCRoamingRequestHandler.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Roaming;
-using Fantasy.Roaming;
-
-namespace Fantasy;
-
-public class C2Chat_TestRPCRoamingRequestHandler : RoamingRPC
-{
- protected override async FTask Run(Terminus terminus, C2Chat_TestRPCRoamingRequest request, Chat2C_TestRPCRoamingResponse response, Action reply)
- {
- Log.Debug($"C2Chat_TestRPCRoamingRequestHandler message:{request.Tag} SceneType:{terminus.Scene.SceneType} SceneId:{terminus.Scene.RuntimeId}");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestRoamingMessageHandler.cs b/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestRoamingMessageHandler.cs
deleted file mode 100644
index 4139f86..0000000
--- a/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestRoamingMessageHandler.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Roaming;
-using Fantasy.Roaming;
-
-namespace Fantasy;
-
-public sealed class C2Chat_TestRoamingMessageHandler : Roaming
-{
- protected override async FTask Run(Terminus terminus, C2Chat_TestRoamingMessage message)
- {
- Log.Debug($"C2Chat_TestRoamingMessageHandler message:{message.Tag} SceneType:{terminus.Scene.SceneType} SceneId:{terminus.Scene.RuntimeId}");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestSendMapMessageHandler.cs b/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestSendMapMessageHandler.cs
deleted file mode 100644
index 3a337fa..0000000
--- a/Hotfix/Outer/Demo/Roaming/Chat/C2Chat_TestSendMapMessageHandler.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Roaming;
-using Fantasy.Roaming;
-
-namespace Fantasy;
-
-public sealed class C2Chat_TestSendMapMessageHandler : Roaming
-{
- protected override async FTask Run(Terminus terminus, C2Chat_TestSendMapMessage message)
- {
- terminus.Send(RoamingType.MapRoamingType, new Chat2M_TestMessage()
- {
- Tag = "Hi Inner Roaming Message!"
- });
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Roaming/Gate/C2G_ConnectRoamingRequestHandler.cs b/Hotfix/Outer/Demo/Roaming/Gate/C2G_ConnectRoamingRequestHandler.cs
deleted file mode 100644
index ac318d4..0000000
--- a/Hotfix/Outer/Demo/Roaming/Gate/C2G_ConnectRoamingRequestHandler.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Roaming;
-using Fantasy.Platform.Net;
-using Fantasy.Roaming;
-
-namespace Fantasy;
-
-public sealed class C2G_ConnectRoamingRequestHandler : MessageRPC
-{
- protected override async FTask Run(Session session, C2G_ConnectRoamingRequest request, G2C_ConnectRoamingResponse response, Action reply)
- {
- // 给session创建一个漫游功能。
- // 这个功能很重要,这个组件是整个Roaming系统最核心的组件,这个组件会处理Roaming协议
- // 这个功能会处理Roaming协议,所以创建这个是必须的。
- // CreateRoaming需要支持三个参数:
- // roamingId:这个参数是RoamingId,RoamingId是Roaming的唯一标识,不能重复。
- // 指定了这个RoamingId后,服务器其他漫游终端的Id会是你设置的RoamingId。
- // 这样操作方便统一管理漫游协议。
- // 一般这个RoamingId是一个角色的Id,这样方便管理。
- // isAutoDispose:是否在Session断开的时候自动断开漫游功能。
- // delayRemove:如果开启了自定断开漫游功能需要设置一个延迟多久执行断开。
- // 这里没有角色的Id,所以这里使用1来代替。
- // isAutoDispose我选择自动断开,这个断开的时机是Session断开后执行。
- // delayRemove断开漫游功能后,Session会自动断开,所以这里设置延迟1000毫秒执行断开。
- // 这里创建的漫游功能会自动处理Roaming协议,所以不需要手动处理Roaming协议。
- var roaming = session.CreateRoaming(1,true,1000);
- // 通过SceneConfigData.Instance.GetSceneBySceneType(SceneType.Map)[0]拿到Map场景的配置信息
- // 如果需要协议漫游其他Scene可以在配置中查找要漫游的服务器。
- // 可以同时漫游多个Scene,但每个Scene的漫游都有一个固定的类型,不能重复。
- var mapConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Map)[0];
- // 通过RoamingComponent.Link(session, mapConfig, 1, 1)链接Map场景
- // 第一个参数是Session,第二个参数是Map场景的配置信息,第三个参数是Map场景的RouteId,第四个参数是Map场景的RoamingType。
- // 这个RoamingType是通过RoamingType.Config文件中定义的。
- // RouteType.Config文件位置在你定义的网络文件协议文件夹下。如果找不到RoamingType.Config文件,可以运行下导出协议工具导出一个协议后会自动创建。
- // 该示例工程下文件位置在Config/NetworkProtocol/RoamingType.Config
- // 执行完后漫游会自动把Session绑定到Map场景上。
- // 后面发送该类型的消息到Session上会自动转发给Map场景。
- var linkResponse = await roaming.Link(session, mapConfig, RoamingType.MapRoamingType);
- if (linkResponse != 0)
- {
- response.ErrorCode = linkResponse;
- return;
- }
- // 同样,你可以创建多个漫游的场景,但每个场景的RouteId和RoamingType不能重复。
- // 这里创建Chat场景的漫游。
- var chatConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Chat)[0];
- linkResponse = await roaming.Link(session, chatConfig, RoamingType.ChatRoamingType);
- if (linkResponse != 0)
- {
- response.ErrorCode = linkResponse;
- return;
- }
- // 如果你觉的每次创建一个场景的漫游都麻烦,你可以利用RoamingType.RoamingTypes遍历创建。
- // 但这样的会把你在RoamingType.Config定义的都创建出来
- foreach (var roamingType in RoamingType.RoamingTypes)
- {
- // 这里添加roaming.Link的方法进行创建。
- }
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Roaming/Map/C2Map_PushMessageToClientHandler.cs b/Hotfix/Outer/Demo/Roaming/Map/C2Map_PushMessageToClientHandler.cs
deleted file mode 100644
index 75b1108..0000000
--- a/Hotfix/Outer/Demo/Roaming/Map/C2Map_PushMessageToClientHandler.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Roaming;
-
-namespace Fantasy;
-
-public sealed class C2Map_PushMessageToClientHandler : Roaming
-{
- protected override async FTask Run(Terminus terminus, C2Map_PushMessageToClient message)
- {
- terminus.Send(new Map2C_PushMessageToClient()
- {
- Tag = message.Tag
- });
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Roaming/Map/C2Map_TestRoamingMessageHandler.cs b/Hotfix/Outer/Demo/Roaming/Map/C2Map_TestRoamingMessageHandler.cs
deleted file mode 100644
index 0149d19..0000000
--- a/Hotfix/Outer/Demo/Roaming/Map/C2Map_TestRoamingMessageHandler.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Roaming;
-using Fantasy.Roaming;
-
-namespace Fantasy;
-
-public class C2Map_TestRoamingMessageHandler : Roaming
-{
- protected override async FTask Run(Terminus terminus, C2Map_TestRoamingMessage message)
- {
- Log.Debug($"C2Map_TestRoamingMessageHandler message:{message.Tag} SceneType:{terminus.Scene.SceneType} SceneId:{terminus.Scene.RuntimeId}");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Roaming/Map/C2Map_TestTransferRequestHandler.cs b/Hotfix/Outer/Demo/Roaming/Map/C2Map_TestTransferRequestHandler.cs
deleted file mode 100644
index e736ab5..0000000
--- a/Hotfix/Outer/Demo/Roaming/Map/C2Map_TestTransferRequestHandler.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Roaming;
-using Fantasy.Platform.Net;
-using Fantasy.Roaming;
-
-namespace Fantasy;
-
-public class C2Map_TestTransferRequestHandler : RoamingRPC
-{
- protected override async FTask Run(Terminus terminus, C2Map_TestTransferRequest request, Map2C_TestTransferResponse response, Action reply)
- {
- Log.Debug($"C2Map_TestTransferRequestHandler1 terminus:{terminus.RuntimeId}");
- var mapConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Map)[1];
- response.ErrorCode = await terminus.StartTransfer(mapConfig.RouteId);
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/Roaming/Map/Chat2M_TestMessageHandler.cs b/Hotfix/Outer/Demo/Roaming/Map/Chat2M_TestMessageHandler.cs
deleted file mode 100644
index 357e662..0000000
--- a/Hotfix/Outer/Demo/Roaming/Map/Chat2M_TestMessageHandler.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Roaming;
-using Fantasy.Roaming;
-
-namespace Fantasy;
-
-public sealed class Chat2M_TestMessageHandler : Roaming
-{
- protected override async FTask Run(Terminus terminus, Chat2M_TestMessage message)
- {
- Log.Debug($"Chat2M_TestMessageHandler message:{message.Tag} SceneType:{terminus.Scene.SceneType} SceneId:{terminus.Scene.RuntimeId}");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestMessageHandler.cs b/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestMessageHandler.cs
deleted file mode 100644
index a417d22..0000000
--- a/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestMessageHandler.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public sealed class C2Chat_TestMessageHandler : Route
-{
- protected override async FTask Run(ChatUnit entity, C2Chat_TestMessage message)
- {
- Log.Debug($"C2Chat_TestMessageHandler.c2Chat_TestMessage: {message}");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestMessageRequestHandler.cs b/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestMessageRequestHandler.cs
deleted file mode 100644
index 85b9626..0000000
--- a/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestMessageRequestHandler.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public sealed class C2Chat_TestMessageRequestHandler : RouteRPC
-{
- protected override async FTask Run(ChatUnit entity, C2Chat_TestMessageRequest request, Chat2C_TestMessageResponse response, Action reply)
- {
- Log.Debug($"C2Chat_TestMessageRequestHandler request = {request}");
- response.Tag = "Hello RouteRPC";
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestRequestPushMessageHandler.cs b/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestRequestPushMessageHandler.cs
deleted file mode 100644
index 5292421..0000000
--- a/Hotfix/Outer/Demo/RouteMessage/C2Chat_TestRequestPushMessageHandler.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public sealed class C2Chat_TestRequestPushMessageHandler : Route
-{
- protected override async FTask Run(ChatUnit chatUnit, C2Chat_TestRequestPushMessage message)
- {
- // 因为没有服务器的相关的逻辑,所以制作了一个协议来触发服务器发送消息给客户端的环境。
- // 使用当前Scene.NetworkMessagingComponent.SendInnerRoute发送消息给客户端。
- // 只需要把消息发送给创建链接的Gate上就会自动转发消息到客户端上。
- // 因为chatUnit.GateRouteId是在G2Chat_CreateRouteRequestHandler方法里记录的所以直接使用这个就可以了。
-
- chatUnit.Scene.NetworkMessagingComponent.SendInnerRoute(chatUnit.GateRouteId, new Chat2C_PushMessage()
- {
- Tag = "Hi Route Chat2C_PushMessage"
- });
-
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/RouteMessage/C2G_CreateChatRouteRequestHandler.cs b/Hotfix/Outer/Demo/RouteMessage/C2G_CreateChatRouteRequestHandler.cs
deleted file mode 100644
index 3917542..0000000
--- a/Hotfix/Outer/Demo/RouteMessage/C2G_CreateChatRouteRequestHandler.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System;
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-using Fantasy.Platform.Net;
-
-namespace Fantasy;
-
-public sealed class C2G_CreateChatRouteRequestHandler : MessageRPC
-{
- protected override async FTask Run(Session session, C2G_CreateChatRouteRequest request, G2C_CreateChatRouteResponse response, Action reply)
- {
- // 首先需要找到一个需要建立Route的Scene的SceneConfig。
- // 例子演示的连接的ChatScene,所以这里我通过SceneConfigData拿到这个SceneConfig。
- // 如果是其他Scene,用法跟这个没有任何区别。
- var chatSceneConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Chat)[0];
- // 通过chatSceneConfig拿到这个Scene的RouteId
- var chatRouteId = chatSceneConfig.RouteId;
- // 通过Scene拿到当前Scene的NetworkMessagingComponent。
- // NetworkMessagingComponent是服务器之间通讯的唯一手段。
- var networkMessagingComponent = session.Scene.NetworkMessagingComponent;
- // 通过CallInnerRoute方法发送一个RPC消息给ChatScene上。
- // 任何一个实体的RunTimeId都可以做为RouteId使用。
- // 所以这个传递了一个session.RunTimeId,是方便Chat发送消息回Gate上。
- var routeResponse = (Chat2G_CreateRouteResponse)await networkMessagingComponent.CallInnerRoute(chatRouteId,
- new G2Chat_CreateRouteRequest()
- {
- GateRouteId = session.RouteId
- });
- if (routeResponse.ErrorCode != 0)
- {
- // 如果ErrorCode不是0表示请求的协议发生错误,应该提示给客户端。
- // 这里就不做这个了。
- return;
- }
- // 要实现Route协议的转发,需要给Session添加一个RouteComponent,这个非常重要。
- var routeComponent = session.AddComponent();
- // 需要再Examples/Config/NetworkProtocol/RouteType.Config里添加一个ChatRoute
- // 然后点击导表工具,会自动生成一个RouteType.cs文件。
- // 使用你定义的ChatRoute当routeType的参数传递进去。
- // routeResponse会返回一个ChatRouteId,这个就是Chat的RouteId。
- routeComponent.AddAddress((int)RouteType.ChatRoute,routeResponse.ChatRouteId);
- // 这些操作完成后,就完成了Route消息的建立。
- // 后面可以直接发送Route消息通过Gate自动中转给Chat了。
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/SubScene/C2G_CreateSubSceneAddressableRequestHandler.cs b/Hotfix/Outer/Demo/SubScene/C2G_CreateSubSceneAddressableRequestHandler.cs
deleted file mode 100644
index cb6f70d..0000000
--- a/Hotfix/Outer/Demo/SubScene/C2G_CreateSubSceneAddressableRequestHandler.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-using Fantasy.Network.Route;
-
-namespace Fantasy;
-
-public sealed class C2G_CreateSubSceneAddressableRequestHandler : MessageRPC
-{
- protected override async FTask Run(Session session, C2G_CreateSubSceneAddressableRequest request, G2C_CreateSubSceneAddressableResponse response, Action reply)
- {
- var scene = session.Scene;
- var subSceneRouteId = session.GetComponent().SubSceneRouteId;
- // 1、向SubScene请求AddressableId
- var responseAddressableId = (SubScene2G_AddressableIdResponse)await scene.NetworkMessagingComponent.CallInnerRoute(subSceneRouteId, new G2SubScene_AddressableIdRequest());
- // 2、给session添加一个AddressableRouteComponent组件,这个组件很重要、能否转发Addressable协议主要是通过这个。
- var addressableRouteComponent = session.AddComponent();
- // 3、拿到SubScene返回的AddressableId赋值给addressableRouteComponent.AddressableId。
- addressableRouteComponent.AddressableId = responseAddressableId.AddressableId;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/SubScene/C2G_CreateSubSceneRequestHandler.cs b/Hotfix/Outer/Demo/SubScene/C2G_CreateSubSceneRequestHandler.cs
deleted file mode 100644
index 5b6709d..0000000
--- a/Hotfix/Outer/Demo/SubScene/C2G_CreateSubSceneRequestHandler.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-using Fantasy.Platform.Net;
-
-namespace Fantasy;
-
-public sealed class C2G_CreateSubSceneRequestHandler : MessageRPC
-{
- protected override async FTask Run(Session session, C2G_CreateSubSceneRequest request, G2C_CreateSubSceneResponse response, Action reply)
- {
- var scene = session.Scene;
- var sceneConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Map)[0];
- var createSubSceneResponse = (M2G_CreateSubSceneResponse)await scene.NetworkMessagingComponent.CallInnerRoute(sceneConfig.RouteId, new G2M_CreateSubSceneRequest());
-
- if (createSubSceneResponse.ErrorCode != 0)
- {
- // 创建SubScene失败。
- response.ErrorCode = createSubSceneResponse.ErrorCode;
- return;
- }
-
- // 记录下这个RouteId,以便后续的消息转发。
- session.AddComponent().SubSceneRouteId = createSubSceneResponse.SubSceneRouteId;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/SubScene/C2G_SendToSubSceneMessageHandler.cs b/Hotfix/Outer/Demo/SubScene/C2G_SendToSubSceneMessageHandler.cs
deleted file mode 100644
index 8fe1d1e..0000000
--- a/Hotfix/Outer/Demo/SubScene/C2G_SendToSubSceneMessageHandler.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public class C2G_SendToSubSceneMessageHandler : Message
-{
- protected override async FTask Run(Session session, C2G_SendToSubSceneMessage message)
- {
- var subSceneRouteId = session.GetComponent().SubSceneRouteId;
- session.Scene.NetworkMessagingComponent.SendInnerRoute(subSceneRouteId, new G2SubScene_SentMessage()
- {
- Tag = "Hi SubScene",
- });
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/SubScene/C2SubScene_TestDisposeMessageHandler.cs b/Hotfix/Outer/Demo/SubScene/C2SubScene_TestDisposeMessageHandler.cs
deleted file mode 100644
index bec78e6..0000000
--- a/Hotfix/Outer/Demo/SubScene/C2SubScene_TestDisposeMessageHandler.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public class C2SubScene_TestDisposeMessageHandler : Addressable
-{
- protected override async FTask Run(Unit unit, C2SubScene_TestDisposeMessage message)
- {
- var unitScene = unit.Scene;
- var unitSceneSceneType = unitScene.SceneType;
- unitScene.Dispose();
- Log.Debug($"{unitSceneSceneType} {unitScene.RuntimeId} is Dispose!");
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Demo/SubScene/C2SubScene_TestMessageHandler.cs b/Hotfix/Outer/Demo/SubScene/C2SubScene_TestMessageHandler.cs
deleted file mode 100644
index 3140351..0000000
--- a/Hotfix/Outer/Demo/SubScene/C2SubScene_TestMessageHandler.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Fantasy.Async;
-using Fantasy.Network.Interface;
-
-namespace Fantasy;
-
-public class C2SubScene_TestMessageHandler : Addressable
-{
- protected override async FTask Run(Unit unit, C2SubScene_TestMessage message)
- {
- Log.Debug($"C2M_TestMessageHandler = {message.Tag} SceneType:{unit.Scene.SceneType} {unit.Scene.GetComponent() == null}");
-
- await FTask.CompletedTask;
- }
-}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/C2G_LoginMessageHandler.cs b/Hotfix/Outer/Gate/C2G_LoginMessageHandler.cs
deleted file mode 100644
index 40ac137..0000000
--- a/Hotfix/Outer/Gate/C2G_LoginMessageHandler.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// using Fantasy.Async;
-// using Fantasy.Network;
-// using Fantasy.Network.Interface;
-//
-// namespace Fantasy.Gate;
-//
-// public class C2G_LoginMessageHandler : Message
-// {
-// protected override async FTask Run(Session session, C2G_TestMessage message)
-// {
-// Log.Debug($"Receive C2G_TestMessage Tag={message.Tag}");
-// await FTask.CompletedTask;
-// }
-// }
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/Handler/Outer/C2G_GetAccountInfoRequestHandler.cs b/Hotfix/Outer/Gate/Handler/Outer/C2G_GetAccountInfoRequestHandler.cs
new file mode 100644
index 0000000..96e9cda
--- /dev/null
+++ b/Hotfix/Outer/Gate/Handler/Outer/C2G_GetAccountInfoRequestHandler.cs
@@ -0,0 +1,33 @@
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Gate;
+using Fantasy.Network;
+using Fantasy.Network.Interface;
+
+namespace System.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;
+ }
+
+ GameAccount account = gameAccountFlagComponent.Account;
+
+ if (account == null)
+ {
+ // 表示这个Account已经被销毁过了。不是咱们想要的了
+ }
+
+ response.GameAccountInfo = account.GetGameAccountInfo();
+ await FTask.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/Handler/Outer/C2G_LoginRequestHandler.cs b/Hotfix/Outer/Gate/Handler/Outer/C2G_LoginRequestHandler.cs
new file mode 100644
index 0000000..a6b27cd
--- /dev/null
+++ b/Hotfix/Outer/Gate/Handler/Outer/C2G_LoginRequestHandler.cs
@@ -0,0 +1,102 @@
+using System.Gate.System;
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Gate;
+using Fantasy.Network;
+using Fantasy.Network.Interface;
+
+#pragma warning disable CS8604 // Possible null reference argument.
+
+namespace System.Gate.Handler;
+
+public sealed class C2G_LoginRequestHandler : MessageRPC
+{
+ 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;
+
+ if (!GateJWTHelper.ValidateToken(scene, request.ToKen, out var accountId))
+ {
+ // 如果失败,表示肯定是恶意攻击、所以毫不犹疑,直接断开当前会话。
+ session.Dispose();
+ return;
+ }
+
+ // 在缓存中检查该账号是否存在
+ var gameAccountManageComponent = scene.GetComponent();
+ Log.Debug("检查账号是否在缓存中");
+ if (!gameAccountManageComponent.TryGet(accountId, out var account))
+ {
+ // 首先要先到数据库中查询是否有这个账号
+ account = await GameAccountHelper.LoadDataBase(scene, accountId);
+ // 如果有的话,就直接加入在缓存中就可以了
+ if (account == null)
+ {
+ Log.Debug("检查到账号没有在数据库中,需要创建一个新的账号并且保存到数据库中");
+ // 如果没有,就要创建一个新的并且保存到数据库。
+ // 如果不存在,表示这是一个新的账号,需要创建一下这个账号。
+ account = await GameAccountFactory.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(account.SessionRunTimeId, out var oldSession))
+ {
+ Log.Debug("当前账号的Session在当前的系统中,所以需要发送一个重复登录的命令,并且要断开这个Session");
+ // 如果这个Session在当前框架中可以查询到。
+ // 那表示就是当前的会话还是在存在的,有如下几个可能:
+ // 1、客户端断线重连,要给这个Session发送一个消息,通知它有人登录了。
+ // 2、其他的客户端登录了这个账号,要给这个Session发送一个消息,通知它有人登录了。
+
+ var gameAccountFlagComponent = oldSession.GetComponent();
+ gameAccountFlagComponent.AccountID = 0;
+ gameAccountFlagComponent.Account = null;
+ // 给客户端发送一个重复登录的消息,如果当前客户端是自己上次登录的,发送也不会收到。
+ oldSession.Send(new G2C_RepeatLogin());
+ // 给当前Session做一个定时销毁的任务,因为不做这个定时销毁,直接销毁的话,有可能消息还没有发送过去就销毁了
+ oldSession.SetTimeout(3000);
+ }
+ }
+
+ // 给当前Session添加一个组件,当Session销毁的时候会销毁这个组件。
+ var accountFlagComponent = session.AddComponent();
+ accountFlagComponent.AccountID = accountId;
+ accountFlagComponent.Account = account;
+
+ account.SessionRunTimeId = session.RuntimeId;
+ response.GameAccountInfo = account.GetGameAccountInfo();
+ Log.Debug($"当前的Gate服务器:{session.Scene.SceneConfigId} accountId:{accountId}");
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/System/GameAccount/GameAccountFactory.cs b/Hotfix/Outer/Gate/System/GameAccount/GameAccountFactory.cs
new file mode 100644
index 0000000..e48ddd0
--- /dev/null
+++ b/Hotfix/Outer/Gate/System/GameAccount/GameAccountFactory.cs
@@ -0,0 +1,30 @@
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Entitas;
+using Fantasy.Gate;
+using Fantasy.Helper;
+
+namespace System.Gate;
+
+public static class GameAccountFactory
+{
+ ///
+ /// 创建一个新的GameAccount
+ ///
+ ///
+ /// ToKen令牌传递过来的aId
+ /// 是否在创建的过程中保存到数据库
+ ///
+ public static async FTask Create(Scene scene, long aId, bool isSaveDataBase = true)
+ {
+ var gameAccount = Entity.Create(scene, aId, false, false);
+ gameAccount.LoginTime = gameAccount.CreateTime = TimeHelper.Now;
+
+ if (isSaveDataBase)
+ {
+ await gameAccount.SaveDataBase();
+ }
+
+ return gameAccount;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/System/GameAccount/GameAccountFlagComponentSystem.cs b/Hotfix/Outer/Gate/System/GameAccount/GameAccountFlagComponentSystem.cs
new file mode 100644
index 0000000..ec9b7cb
--- /dev/null
+++ b/Hotfix/Outer/Gate/System/GameAccount/GameAccountFlagComponentSystem.cs
@@ -0,0 +1,20 @@
+using Fantasy.Entitas.Interface;
+using Fantasy.Gate;
+
+namespace System.Gate;
+
+public sealed class GameAccountFlagComponentDestroySystem : DestroySystem
+{
+ protected override void Destroy(GameAccountFlagComponent self)
+ {
+ if (self.AccountID != 0)
+ {
+ // 执行下线过程、并且要求在5分钟后完成缓存清理。也就是5分钟后会保存数据到数据库。
+ // 由于5分钟太长了、咱们测试的时候,不方便测试,也可以把这个时间改短一些,比如10秒。
+ GameAccountHelper.Disconnect(self.Scene, self.AccountID, 1000 * 60 * 5).Coroutine();
+ self.AccountID = 0;
+ }
+
+ self.Account = null;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/System/GameAccount/GameAccountHelper.cs b/Hotfix/Outer/Gate/System/GameAccount/GameAccountHelper.cs
new file mode 100644
index 0000000..59b92c7
--- /dev/null
+++ b/Hotfix/Outer/Gate/System/GameAccount/GameAccountHelper.cs
@@ -0,0 +1,114 @@
+using System.Gate.System;
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Gate;
+using Fantasy.Network;
+
+namespace System.Gate;
+
+public static class GameAccountHelper
+{
+ ///
+ /// 从数据库中读取GameAccount
+ ///
+ ///
+ /// 账号Id
+ ///
+ public static async FTask LoadDataBase(Scene scene, long accountId)
+ {
+ var account = await scene.World.DataBase.First(d => d.Id == accountId);
+ if (account == null)
+ {
+ return null;
+ }
+
+ account.Deserialize(scene);
+ return account;
+ }
+
+ ///
+ /// 保存账号到数据库中
+ ///
+ ///
+ public static async FTask SaveDataBase(this GameAccount self)
+ {
+ await self.Scene.World.DataBase.Save(self);
+ }
+
+ ///
+ /// 执行该账号的断开逻辑,不要非必要不要使用这个接口,这个接口是内部使用。
+ ///
+ ///
+ public static async FTask Disconnect(this GameAccount self)
+ {
+ // 保存该账号信息到数据库中。
+ await SaveDataBase(self);
+ // 在缓存中移除自己,并且执行自己的Dispose方法。
+ self.Scene.GetComponent().Remove(self.Id);
+ }
+
+ ///
+ /// 账号完整的断开逻辑,执行了这个接口后,该账号会完全下线。
+ ///
+ ///
+ ///
+ ///
+ public static async FTask Disconnect(Scene scene, long accountId, int timeOut = 1000 * 60 * 3)
+ {
+ // 调用该方法有如下几种情况:
+ // 1、客户端主动断开,如:退出游戏、切换账号、等。 客户端会主动发送一个协议给服务器通知服务器断开。
+ // 2、客户端断断线 客户端不会主动发送一个协议给服务器,是由服务器的心跳来检测是否断开了。
+ // 如果是心跳检测断开的Session,我怎么能拿到当前的这个账号来进行下线处理呢?
+ // 通过给当前的Session挂载一个组件,当销毁这个Session时候呢,也会销毁这个组件。
+ // 这样的话,是不是可以在登录的时候,给这个组件把AccountId存到这个组件呢?
+
+ // 要检查当前缓存中是否存在该账号的数据
+ var gameAccountManageComponent = scene.GetComponent();
+ if (!gameAccountManageComponent.TryGet(accountId, out var account))
+ {
+ // 如果缓存中没有、那表示已经下线或者根本不存在该账号,应该在打印一个警告,因为正常的情况下是不会出现的。
+ Log.Warning($"GameAccountHelper Disconnect accountId : {accountId} not found");
+ return;
+ }
+ // 为了防止逻辑的错误,加一个警告来排除下
+ if (!scene.TryGetEntity(account.SessionRunTimeId, out var session))
+ {
+ // 如果没有找到对应的Session,那只有一种可能就是当前的链接会话已经断开了,一般的情况下也不会出现的,所以咱们也要打印一个警告。
+ Log.Warning($"GameAccountHelper Disconnect accountId : {accountId} SessionRunTimeId : {account.SessionRunTimeId} not found");
+ return;
+ }
+ // 如果不存在定时任务的组件,那就添加并设置定时任务
+ if (account.IsTimeOutComponent())
+ {
+ // 如果已经存在了,那就表示当然已经有一个延时断开的任务了,那就不需要重复添加了
+ return;
+ }
+ // 立即下线处理
+ if (timeOut <= 0)
+ {
+ // 如果timeOut销毁或等会0的情况下,执行立即下线。
+ await account.Disconnect();
+ return;
+ }
+ // 设置延迟下线
+ account.SetTimeout(timeOut, account.Disconnect);
+ }
+
+ ///
+ /// 获得GameAccountInfo
+ ///
+ ///
+ ///
+ public static GameAccountInfo GetGameAccountInfo(this GameAccount self)
+ {
+ // 其实可以不用每次都NEW一个新的GameAccountInfo
+ // 可以在当前账号下创建一个GameAccountInfo,每次变动会提前通知这个GameAccountInfo
+ // 又或者每次调用该方法的时候,把值重新赋值一下。
+
+ return new GameAccountInfo()
+ {
+ CreateTime = self.CreateTime,
+ LoginTime = self.LoginTime
+ };
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/System/GameAccount/GameAccountSystem.cs b/Hotfix/Outer/Gate/System/GameAccount/GameAccountSystem.cs
new file mode 100644
index 0000000..fcb11e2
--- /dev/null
+++ b/Hotfix/Outer/Gate/System/GameAccount/GameAccountSystem.cs
@@ -0,0 +1,14 @@
+using Fantasy.Entitas.Interface;
+using Fantasy.Gate;
+
+namespace System.Gate;
+
+public sealed class GameAccountDestroySystem : DestroySystem
+{
+ protected override void Destroy(GameAccount self)
+ {
+ self.CreateTime = 0;
+ self.LoginTime = 0;
+ self.SessionRunTimeId = 0;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/System/GameAccountManageComponentSystem.cs b/Hotfix/Outer/Gate/System/GameAccountManageComponentSystem.cs
new file mode 100644
index 0000000..7db5d6b
--- /dev/null
+++ b/Hotfix/Outer/Gate/System/GameAccountManageComponentSystem.cs
@@ -0,0 +1,50 @@
+using Fantasy.Entitas.Interface;
+using Fantasy.Gate;
+
+namespace System.Gate.System;
+
+public sealed class GameAccountManageComponentDestroySystem : DestroySystem
+{
+ 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();
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/System/JWT/GateJWTComponentSystem.cs b/Hotfix/Outer/Gate/System/JWT/GateJWTComponentSystem.cs
new file mode 100644
index 0000000..d3f9887
--- /dev/null
+++ b/Hotfix/Outer/Gate/System/JWT/GateJWTComponentSystem.cs
@@ -0,0 +1,65 @@
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Cryptography;
+using Fantasy.Entitas.Interface;
+using Fantasy.Gate;
+using Microsoft.IdentityModel.Tokens;
+#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
+
+namespace System.Gate;
+
+public sealed class GateJWTComponentAwakeSystem : AwakeSystem
+{
+ protected override void Awake(GateJWTComponent self)
+ {
+ self.Awake();
+ }
+}
+
+public static class GateJWTComponentSystem
+{
+ public static void Awake(this GateJWTComponent self)
+ {
+ var rsa = RSA.Create();
+ rsa.ImportRSAPublicKey(Convert.FromBase64String(self.PublicKeyPem), out _);
+ self.SigningCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256);
+ // 创建 TokenValidationParameters 对象,用于配置验证参数
+ self.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateLifetime = false, // 禁止令牌验证时间是否过期
+ ValidateIssuer = true, // 验证发行者
+ ValidateAudience = true, // 验证受众
+ ValidateIssuerSigningKey = true, // 验证签名密钥
+ ValidIssuer = "Fantasy", // 有效的发行者
+ ValidAudience = "Fantasy", // 有效的受众
+ IssuerSigningKey = new RsaSecurityKey(rsa) // RSA公钥作为签名密钥
+ };
+ }
+
+ public static bool ValidateToken(this GateJWTComponent self, string token, out JwtPayload payload)
+ {
+ payload = null;
+
+ try
+ {
+ var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
+ jwtSecurityTokenHandler.ValidateToken(token, self.TokenValidationParameters, out _);
+ payload = jwtSecurityTokenHandler.ReadJwtToken(token).Payload;
+ return true;
+ }
+ catch (SecurityTokenInvalidAudienceException)
+ {
+ Console.WriteLine("验证受众失败!");
+ return false;
+ }
+ catch (SecurityTokenInvalidIssuerException)
+ {
+ Console.WriteLine("验证发行者失败!");
+ return false;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ throw;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Outer/Gate/System/JWT/GateJWTHelper.cs b/Hotfix/Outer/Gate/System/JWT/GateJWTHelper.cs
new file mode 100644
index 0000000..2e3deff
--- /dev/null
+++ b/Hotfix/Outer/Gate/System/JWT/GateJWTHelper.cs
@@ -0,0 +1,36 @@
+using System.IdentityModel.Tokens.Jwt;
+using Fantasy;
+using Fantasy.Gate;
+
+namespace System.Gate;
+
+public static class GateJWTHelper
+{
+ ///
+ /// 验证令牌是否合法
+ ///
+ ///
+ /// ToKen
+ /// 如果验证成功会返回正常的AccountId
+ /// 如果是True表示验证成功,False表示验证失败
+ public static bool ValidateToken(Scene scene, string token, out long accountId)
+ {
+ if (!ValidateToken(scene, token, out JwtPayload payload))
+ {
+ // 如果令牌验证失败,表示当前令牌不合法、那就返回为false,让上层处理。
+ accountId = 0;
+ return false;
+ }
+
+ // 如果不等于当前Scene的ConfigId的话,把就表示该连接不应该连接到当前的Gate里。
+ // 所以理应把当前连接关闭掉。
+ var sceneId = Convert.ToInt64(payload["SceneId"]);
+ accountId = Convert.ToInt64(payload["aId"]);
+ return sceneId == scene.SceneConfigId;
+ }
+
+ private static bool ValidateToken(Scene scene, string token, out JwtPayload payload)
+ {
+ return scene.GetComponent().ValidateToken(token, out payload);
+ }
+}
\ No newline at end of file
diff --git a/Main/Program.cs b/Main/Program.cs
index eb3c405..bed81e3 100644
--- a/Main/Program.cs
+++ b/Main/Program.cs
@@ -4,14 +4,6 @@ using Fantasy.Helper;
using Fantasy.IdFactory;
using Fantasy.Platform.Net;
-//Scene 255
-//gate 20个以内
-//游戏服 1个
-//Addressable管理中心 一个
-//游戏服 50个内
-//聊天服 1个1
-
-
// 设置配置表的路径
ConfigTableHelper.Initialize("../../../Config/Binary");
// 设置ID生成规则
diff --git a/OutputClient/Generate/NetworkProtocol/OuterMessage.cs b/OutputClient/Generate/NetworkProtocol/OuterMessage.cs
new file mode 100644
index 0000000..3b84d3d
--- /dev/null
+++ b/OutputClient/Generate/NetworkProtocol/OuterMessage.cs
@@ -0,0 +1,485 @@
+using ProtoBuf;
+
+using System.Collections.Generic;
+using Fantasy;
+using Fantasy.Network.Interface;
+using Fantasy.Serialize;
+#pragma warning disable CS8618
+
+namespace Fantasy
+{
+ [ProtoContract]
+ public partial class C2A_RegisterRequest : AMessage, IRequest, IProto
+ {
+ public static C2A_RegisterRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Username = default;
+ Password = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public A2C_RegisterResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2A_RegisterRequest; }
+ [ProtoMember(1)]
+ public string Username { get; set; }
+ [ProtoMember(2)]
+ public string Password { get; set; }
+ }
+ [ProtoContract]
+ public partial class A2C_RegisterResponse : AMessage, IResponse, IProto
+ {
+ public static A2C_RegisterResponse 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.A2C_RegisterResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2A_LoginRequest : AMessage, IRequest, IProto
+ {
+ public static C2A_LoginRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Username = default;
+ Password = default;
+ LoginType = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public A2C_LoginResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2A_LoginRequest; }
+ [ProtoMember(1)]
+ public string Username { get; set; }
+ [ProtoMember(2)]
+ public string Password { get; set; }
+ [ProtoMember(3)]
+ public int LoginType { get; set; }
+ }
+ [ProtoContract]
+ public partial class A2C_LoginResponse : AMessage, IResponse, IProto
+ {
+ public static A2C_LoginResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ ToKen = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.A2C_LoginResponse; }
+ [ProtoMember(1)]
+ public string ToKen { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 客户端登录到Gate服务器
+ ///
+ [ProtoContract]
+ public partial class C2G_LoginRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_LoginRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ToKen = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_LoginResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_LoginRequest; }
+ [ProtoMember(1)]
+ public string ToKen { get; set; }
+ }
+ [ProtoContract]
+ public partial class G2C_LoginResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_LoginResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ GameAccountInfo = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_LoginResponse; }
+ [ProtoMember(1)]
+ public GameAccountInfo GameAccountInfo { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 通知客户端重复登录
+ ///
+ [ProtoContract]
+ public partial class G2C_RepeatLogin : AMessage, IMessage, IProto
+ {
+ public static G2C_RepeatLogin Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_RepeatLogin; }
+ }
+ ///
+ /// GameAccount实体类
+ ///
+ [ProtoContract]
+ public partial class GameAccountInfo : AMessage, IProto
+ {
+ public static GameAccountInfo Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ CreateTime = default;
+ LoginTime = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoMember(1)]
+ public long CreateTime { get; set; }
+ [ProtoMember(2)]
+ public long LoginTime { get; set; }
+ }
+ ///
+ /// 拿到当前账号的信息
+ ///
+ [ProtoContract]
+ public partial class C2G_GetAccountInfoRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_GetAccountInfoRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_GetAccountInfoResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_GetAccountInfoRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_GetAccountInfoResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_GetAccountInfoResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ GameAccountInfo = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_GetAccountInfoResponse; }
+ [ProtoMember(1)]
+ public GameAccountInfo GameAccountInfo { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2G_TestMessage : AMessage, IMessage, IProto
+ {
+ public static C2G_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2G_TestMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2G_TestRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_TestRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_TestResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_TestRequest; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class G2C_TestResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_TestResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.G2C_TestResponse; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2G_CreateAddressableRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_CreateAddressableRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_CreateAddressableResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_CreateAddressableRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_CreateAddressableResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_CreateAddressableResponse 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.G2C_CreateAddressableResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2M_TestMessage : AMessage, IAddressableRouteMessage, IProto
+ {
+ public static C2M_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2M_TestMessage; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class C2M_TestRequest : AMessage, IAddressableRouteRequest, IProto
+ {
+ public static C2M_TestRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public M2C_TestResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2M_TestRequest; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class M2C_TestResponse : AMessage, IAddressableRouteResponse, IProto
+ {
+ public static M2C_TestResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.M2C_TestResponse; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 通知Gate服务器创建一个Chat的Route连接
+ ///
+ [ProtoContract]
+ public partial class C2G_CreateChatRouteRequest : AMessage, IRequest, IProto
+ {
+ public static C2G_CreateChatRouteRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public G2C_CreateChatRouteResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2G_CreateChatRouteRequest; }
+ }
+ [ProtoContract]
+ public partial class G2C_CreateChatRouteResponse : AMessage, IResponse, IProto
+ {
+ public static G2C_CreateChatRouteResponse 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.G2C_CreateChatRouteResponse; }
+ [ProtoMember(1)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 发送一个Route消息给Chat
+ ///
+ [ProtoContract]
+ public partial class C2Chat_TestMessage : AMessage, ICustomRouteMessage, IProto
+ {
+ public static C2Chat_TestMessage Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.C2Chat_TestMessage; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.ChatRoute;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ ///
+ /// 发送一个RPCRoute消息给Chat
+ ///
+ [ProtoContract]
+ public partial class C2Chat_TestMessageRequest : AMessage, ICustomRouteRequest, IProto
+ {
+ public static C2Chat_TestMessageRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public Chat2C_TestMessageResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2Chat_TestMessageRequest; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.ChatRoute;
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ }
+ [ProtoContract]
+ public partial class Chat2C_TestMessageResponse : AMessage, ICustomRouteResponse, IProto
+ {
+ public static Chat2C_TestMessageResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ Tag = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Chat2C_TestMessageResponse; }
+ [ProtoMember(1)]
+ public string Tag { get; set; }
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+}
diff --git a/OutputClient/Generate/NetworkProtocol/OuterOpcode.cs b/OutputClient/Generate/NetworkProtocol/OuterOpcode.cs
new file mode 100644
index 0000000..9dd0ec8
--- /dev/null
+++ b/OutputClient/Generate/NetworkProtocol/OuterOpcode.cs
@@ -0,0 +1,28 @@
+namespace Fantasy
+{
+ public static partial class OuterOpcode
+ {
+ public const uint C2A_RegisterRequest = 268445457;
+ public const uint A2C_RegisterResponse = 402663185;
+ public const uint C2A_LoginRequest = 268445458;
+ public const uint A2C_LoginResponse = 402663186;
+ public const uint C2G_LoginRequest = 268445459;
+ public const uint G2C_LoginResponse = 402663187;
+ public const uint G2C_RepeatLogin = 134227729;
+ public const uint C2G_GetAccountInfoRequest = 268445460;
+ public const uint G2C_GetAccountInfoResponse = 402663188;
+ public const uint C2G_TestMessage = 134227730;
+ public const uint C2G_TestRequest = 268445461;
+ public const uint G2C_TestResponse = 402663189;
+ public const uint C2G_CreateAddressableRequest = 268445462;
+ public const uint G2C_CreateAddressableResponse = 402663190;
+ public const uint C2M_TestMessage = 1342187281;
+ public const uint C2M_TestRequest = 1476405009;
+ public const uint M2C_TestResponse = 1610622737;
+ public const uint C2G_CreateChatRouteRequest = 268445463;
+ public const uint G2C_CreateChatRouteResponse = 402663191;
+ public const uint C2Chat_TestMessage = 2147493649;
+ public const uint C2Chat_TestMessageRequest = 2281711377;
+ public const uint Chat2C_TestMessageResponse = 2415929105;
+ }
+}
diff --git a/OutputClient/Generate/NetworkProtocol/RoamingType.cs b/OutputClient/Generate/NetworkProtocol/RoamingType.cs
new file mode 100644
index 0000000..96d932c
--- /dev/null
+++ b/OutputClient/Generate/NetworkProtocol/RoamingType.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+namespace Fantasy
+{
+ // Roaming协议定义(需要定义10000以上、因为10000以内的框架预留)
+ public static class RoamingType
+ {
+ public const int MapRoamingType = 10001;
+ public const int ChatRoamingType = 10002;
+ public static IEnumerable RoamingTypes
+ {
+ get
+ {
+ yield return 10001;
+ yield return 10002;
+ }
+ }
+ }
+}
diff --git a/OutputClient/Generate/NetworkProtocol/RouteType.cs b/OutputClient/Generate/NetworkProtocol/RouteType.cs
new file mode 100644
index 0000000..cdd0df0
--- /dev/null
+++ b/OutputClient/Generate/NetworkProtocol/RouteType.cs
@@ -0,0 +1,9 @@
+namespace Fantasy
+{
+ // Route协议定义(需要定义1000以上、因为1000以内的框架预留)
+ public static class RouteType
+ {
+ public const int GateRoute = 1001; // Gate
+ public const int ChatRoute = 1002; // Chat
+ }
+}
diff --git a/Server.sln.DotSettings.user b/Server.sln.DotSettings.user
index 38edbbb..59e24e9 100644
--- a/Server.sln.DotSettings.user
+++ b/Server.sln.DotSettings.user
@@ -1,6 +1,7 @@
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
@@ -9,6 +10,7 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
@@ -49,6 +51,7 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
diff --git a/Tools/NetworkProtocol/ExporterSettings.json b/Tools/NetworkProtocol/ExporterSettings.json
index 5c9303b..0a26191 100644
--- a/Tools/NetworkProtocol/ExporterSettings.json
+++ b/Tools/NetworkProtocol/ExporterSettings.json
@@ -9,7 +9,7 @@
"Comment": "ProtoBuf生成到服务端的文件夹位置"
},
"NetworkProtocolClientDirectory": {
- "Value": "../../OutputClient/Generate/NetworkProtocol/",
+ "Value": "../../../Fishing2/Assets/Scripts/Generate/NetworkProtocol/",
"Comment": "ProtoBuf生成到客户端的文件夹位置"
},
"Serializes": {