Browse Source

【优化】增加session心跳组件,优化顶号和断线

johnclot69 1 year ago
parent
commit
bdfc5a5c8d

+ 8 - 4
DotNet/Hotfix/Scenes/Game/Handler/C2G_BindPlayerHandler.cs

@@ -96,11 +96,15 @@ namespace ET.Server
             if (player != null)
             {
                 // todo 顶号
-                player.Dispose();
-                scene.GetComponent<GamePlayerComponent>().Remove(request.PlayerId);
+                MessageHelper.SendToClient(player, new R2C_Disconnect());
+                player.Session.Disconnect().Coroutine();
+                // 重新赋值session
+                player.Session = session;
+            }
+            else
+            {
+                player = await PlayerFactory.CreatPlayer(session, playerInfo);
             }
-
-            player = await PlayerFactory.CreatPlayer(session, playerInfo);
 
             // 绑定选择的玩家
             session.GetComponent<SessionPlayerComponent>().BindPlayerId(request.PlayerId > 0 ? request.PlayerId : player.GetId());

+ 1 - 0
DotNet/Hotfix/Scenes/Game/Handler/C2G_LoginGameHandler.cs

@@ -34,6 +34,7 @@ namespace ET.Server
             // 移除session自动超时组件
             session.RemoveComponent<SessionAcceptTimeoutComponent>();
             // 添加session组件,用于绑定角色
+            session.AddComponent<HeartBeatComponent, Session>(session);
             session.AddComponent<SessionPlayerComponent>().UserId = request.UserId;
             session.AddComponent<MailBoxComponent, MailboxType>(MailboxType.GateSession);
 

+ 7 - 0
DotNet/Hotfix/Scenes/Game/Handler/C2G_PingHandler.cs

@@ -2,11 +2,18 @@
 
 namespace ET.Server
 {
+    /// <summary>
+    /// 心跳消息
+    /// </summary>
     [MessageHandler(SceneType.Game)]
 	public class C2G_PingHandler : AMRpcHandler<C2G_Ping, G2C_Ping>
 	{
 		protected override async ETTask Run(Session session, C2G_Ping request, G2C_Ping response, Action reply)
 		{
+            if (session.GetComponent<HeartBeatComponent>() != null)
+            {
+                session.GetComponent<HeartBeatComponent>().CurrentTime = TimeHelper.ClientNowSeconds();
+            }
 			response.Time = TimeHelper.ServerNow();
 			reply();
 			await ETTask.CompletedTask;

+ 43 - 0
DotNet/Hotfix/Scenes/Game/Player/HeartBeatComponentSystem.cs

@@ -0,0 +1,43 @@
+namespace ET.Server
+{
+    [FriendOf(typeof (HeartBeatComponent))]
+    public static class HeartBeatComponentSystem
+    {
+        public class HeartBeatComponentAwakeSystem: AwakeSystem<HeartBeatComponent, Session>
+        {
+            protected override void Awake(HeartBeatComponent self, Session session)
+            {
+                // 初始化
+                self.Session = session;
+                self.UpdateInterval = 5;
+                self.OutInterval = 3;
+                self.RecordDeltaTime = 0;
+                self.CurrentTime = 0;
+            }
+        }
+
+        public class HeartBeatComponentUpdateSystem: UpdateSystem<HeartBeatComponent>
+        {
+            protected override void Update(HeartBeatComponent self)
+            {
+                // 如果没有到达发包时间、直接返回
+                if (!((TimeHelper.ClientNowSeconds() - self.RecordDeltaTime) > self.UpdateInterval) || self.CurrentTime == 0)
+                {
+                    return;
+                }
+
+                // 记录当前时间
+                self.RecordDeltaTime = TimeHelper.ClientNowSeconds();
+
+                // 移除Session
+                if (TimeHelper.ClientNowSeconds() - self.CurrentTime <= self.OutInterval)
+                {
+                    return;
+                }
+
+                Log.Debug($"移除Session Parent.Id = {self.Parent.Id}");
+                self.Session.Disconnect().Coroutine();
+            }
+        }
+    }
+}

+ 3 - 3
DotNet/Hotfix/Scenes/Game/Player/PlayerSystem.cs

@@ -168,16 +168,16 @@ namespace ET.Server
             self.OnEndEnterScene();
 
             // 登录第一次进场景处理,此次登陆登出期间只处理一次
-            if (self.readyFirst)
+            if (self.ReadyFirst)
             {
-                self.readyFirst = false;
+                self.ReadyFirst = false;
             }
         }
 
         /** 玩家登录事件 **/
         public static void OnLogin(this WNPlayer self)
         {
-            self.readyFirst = true;
+            self.ReadyFirst = true;
             self.DomainScene().GetComponent<GamePlayerComponent>().Add(self.GetId(), self);
         }
 

+ 29 - 0
DotNet/Model/Scenes/Game/Player/HeartBeatComponent.cs

@@ -0,0 +1,29 @@
+namespace ET.Server
+{
+    [ComponentOf(typeof (Session))]
+    public class HeartBeatComponent: Entity, IAwake<Session>, IUpdate
+    {
+        public Session Session { get; set; }
+
+        /// <summary>
+        /// 更新间隔
+        /// </summary>
+        public long UpdateInterval { get; set; }
+
+        /// <summary>
+        /// 超出时间
+        /// </summary>
+        /// <remarks>如果跟客户端连接时间间隔大于在服务器上删除该Session</remarks>
+        public long OutInterval { get; set; }
+
+        /// <summary>
+        /// 记录时间
+        ///</summary>
+        public long RecordDeltaTime { get; set; }
+
+        /// <summary>
+        /// 当前Session连接时间
+        /// </summary>
+        public long CurrentTime { get; set; }
+    }
+}

+ 4 - 1
DotNet/Model/Scenes/Game/Player/WNPlayer.cs

@@ -28,7 +28,10 @@ namespace ET.Server
         public int EnterState { get; set; }
 
         /** 登录首次进入场景,用于onready,进行一次消息推送(只在登陆时候首次进场景推送)*/
-        public bool readyFirst { get; set; }
+        public bool ReadyFirst { get; set; }
+
+        /** 在线状态 **/
+        public bool IsOnline { get; set; }
 
         /** 战斗服技能数据 **/
         public List<Struct.SkillInfo> ToJson4BattleServerSkillInfos { get; set; }

+ 4 - 0
Unity/Assets/Scripts/Codes/Model/Share/Module/Message/ErrorCode.cs

@@ -51,6 +51,10 @@
         public const int ERR_EnterMapError = 200019;
         /** 配置错误 **/
         public const int ERR_ConfigError = 200020;
+        /** 账号已在其他地方登录 **/
+        public const int ERR_AccountAlreadyLoggedInElsewhere = 200021;
+        /** 角色已在其他地方登录 **/
+        public const int ERR_PlayerAlreadyLoggedInElsewhere = 200022;
 
         public enum EnterMap
         {