//**********************************************// //作者:#AUTHOR# //日期:#DATE# //简述:#DESCRIPTION# //*********************************************// using Thousandto.Code.Center; using Thousandto.Core.Base; using Thousandto.Plugins.Common; using UnityEngine; namespace Thousandto.Code.Logic { /// /// 断线重连 /// public class ReconnectSystem : BaseSystem { #region//常量定义 //重连尝试次数 private const int CN_RECONNECT_TRY_COUNT = 5; //Socket连接的等待时间 private const float CN_SOCKET_CONNECT_WAIT_TIME = 3; //等待网络消息的时间 private const float CN_NET_MESSAGE_WAIT_TIME = 3; #endregion #region //成员变量 private string _sign; //是否允许断线重连 private bool _enable = false; //当前状态 private ReconnectStateCode _state = ReconnectStateCode.Idle; //尝试次数 private int _remainCount = 5; //等待时间 秒 private float _waitTime = 3; #endregion #region //属性 //断线前的地图id public int LastMapId { get; set; } //正常切换场景记录切换前的坐标、分线等等,以防万一真的重连,这里能取数据 public Vector3 LastPlayerPos { get; set; } //正在重连的次数 public int TryCount { get { return CN_RECONNECT_TRY_COUNT - _remainCount; } } //剩余次数 public int RemainCount { get { return _remainCount; } } #endregion #region//公共接口处理 #region //初始化 public void Initialize() { GameCenter.Networker.OnSocketDisconnect = OnMonitorSocketState; } #endregion #region //公有函数 public void Reconnect() { //开始重连的 LastMapId = -1; LastPlayerPos = Vector3.zero; _state = ReconnectStateCode.StartReconnect; } //在重连中返回到登陆 public void ReturnToLogin() { //当前状态为空闲 _state = ReconnectStateCode.Idle; //现在不是重连状态 GameGlobalData.IsReconnecting = false; //不能重连 _enable = false; //返回到登陆 GameCenter.GameSceneSystem.ReturnToLogin(); } //设置是否激活 public void SetEnable(bool value) { //当前状态为空闲 _state = ReconnectStateCode.Idle; //不能重连 _enable = value; } #endregion #region//处理网络消息 //public bool TestRightSign = true; //3.发送请求重连的消息 public void SendReqReconnect() { Debug.LogError("SendReqReconnect=" + _sign); MSG_heart.ReqReconnect req = new MSG_heart.ReqReconnect(); req.playerId = GameCenter.GameSceneSystem.GetLocalPlayerID(); //req.sign = TestRightSign ? _sign : "00"; req.sign = _sign; req.Send(); } //发送已经设置了sign成功的消息 public void SendReqSetReconnectSignSuccess() { //收到sign就要告诉服务器 MSG_heart.ReqSetReconnectSignSuccess req = new MSG_heart.ReqSetReconnectSignSuccess(); req.Send(); } //断线重连需要用到的sign值,每10分钟刷新这个值,随后重连用这个值 public void GS2U_ResReconnectSign(MSG_heart.ResReconnectSign result) { //Debug.LogError("接收到:sign=" + result.sign); _sign = result.sign; SendReqSetReconnectSignSuccess(); } //断线重连失败 public void GS2U_ResHeartFailed(MSG_heart.ResHeartFailed result) { //设置全局标志当前不在重连了 GameGlobalData.IsReconnecting = false; //重连成功 if (result.reason == 0) { Debug.LogError("3.1 接受到服务器的断线重连成功"); _state = ReconnectStateCode.ReconnectSuccess; //可以心跳 GameCenter.HeartSystem.EnabelHeartMsg(true); //关闭重连界面 GameCenter.EventManager.PushFixEvent((int)UIEventDefine.UI_RECONNECTFORM_CLOSE); if (result.mapModelId == GameCenter.ReconnectSystem.LastMapId || result.mapModelId == -1) { Debug.Log("3.1.1 断线重连成功,最后的地图与重连返回的服务器地图相同,当前地图ID: " + result.mapModelId); //断线重连,如果没有切换地图,需要向服务器发送loadFinish消息 NetHandler.SendMessage_ReqLoadFinish(); } else { Debug.Log(string.Format("3.1.2 断线重连成功, 最后的地图与重连返回的服务器地图不同, mapModleId={0} my saved mapId={1}", result.mapModelId, GameCenter.ReconnectSystem.LastMapId)); //GameCenter.GameSceneSystem.StartChangeToMap(result.mapModelId, result.lineId, new Vector2(LastPlayerPos.x, LastPlayerPos.z)); } GameCenter.PushFixEvent(Global.LogicEventDefine.EID_EVENT_RECONNECT_SUCCESS); } else { _state = ReconnectStateCode.ReconnectFail; Debug.LogError("3.2 接受到服务器的断线重连失败! reason:" + result.reason.ToString()); } } #endregion #endregion #region//保护类型的方法 //心跳处理 protected override bool OnUpdate(float deltaTime) { if (!_enable) return true; switch (_state) { case ReconnectStateCode.StartReconnect: { //等待判断是否可以进行重连 _state = ReconnectStateCode.WaitCheckReconnect; StartupReconnect(); } break; case ReconnectStateCode.ReconnectSocketCD: { _waitTime -= deltaTime; if (_waitTime <= 0) { _state = ReconnectStateCode.StartConnectSocket; } } break; case ReconnectStateCode.StartConnectSocket: { StartConnectSocket(); } break; case ReconnectStateCode.SocketConnectSuccess: { //等待网络消息,或者直接退出到登陆 _state = ReconnectStateCode.WaitNetMessage; ReconnectSocketSuccess(); _waitTime = CN_NET_MESSAGE_WAIT_TIME; } break; case ReconnectStateCode.WaitNetMessage: {//等待网络消息,如果超时,表示连接失败 _waitTime -= deltaTime; if (_waitTime <= 0) { _state = ReconnectStateCode.WaitNetMessageFail; } } break; case ReconnectStateCode.WaitNetMessageFail: case ReconnectStateCode.SocketConnectFail: case ReconnectStateCode.ReconnectFail: { ProcessFail(_state); GameCenter.PushFixEvent(UIEventDefine.UI_RECONNECTFORM_OPEN); } break; } return true; } #endregion #region //私有函数 //0.监控网络状态 private void OnMonitorSocketState(int code) { //Socket断开,只有在空闲的情况下,才会去重新开始连,其他情况表示正在进行重连操作.所以不做开始处理重连处理. if (_enable && (_state == ReconnectStateCode.Idle || _state == ReconnectStateCode.ReconnectSuccess)) { LastMapId = -1; LastPlayerPos = Vector3.zero; _state = ReconnectStateCode.StartReconnect; GameGlobalData.IsReconnecting = true; } else if (_state == ReconnectStateCode.WaitNetMessage) { //如果当前是等待网络消息,那么直接重连失败. _state = ReconnectStateCode.ReconnectFail; } else { Debug.LogError("0.0.不能进行重连,因为当前重连状态:" + _state.ToString()+";;;enable:"+ _enable); //如果是创建角色界面,直接打开退出界面 if (GameCenter.FormStateSystem.FormIsOpenByEventID((int)UIEventDefine.UICREATEPLAYERFORM_OPEN)) { _state = ReconnectStateCode.WaitExitReconnect; _remainCount = 0; GameCenter.EventManager.PushFixEvent((int)UIEventDefine.UI_RECONNECTFORM_OPEN, null, null, null, false, 0); } } } //1开启断线重连 private void StartupReconnect() { //1.1.判断是否开启重连 if (CheckReconnectCondition()) {//打开重连界面 //初始化尝试次数 _remainCount = CN_RECONNECT_TRY_COUNT; //1.1.1 记录当前场景ID if (GameCenter.GameSceneSystem.ActivedScene != null) LastMapId = GameCenter.GameSceneSystem.ActivedScene.MapId; //1.1.2 记录角色的位置 if (GameCenter.GameSceneSystem.GetLocalPlayer() != null) LastPlayerPos = GameCenter.GameSceneSystem.GetLocalPlayer().Position; Debug.Log("1.1 启动断线重连"); _state = ReconnectStateCode.ReconnectSocketCD; _waitTime = CN_SOCKET_CONNECT_WAIT_TIME; _remainCount = CN_RECONNECT_TRY_COUNT; //GameCenter.EventManager.PushFixEvent((int)UIEventDefine.UI_RECONNECTFORM_OPEN); } else {//重连条件不足,弹出返回登陆的对话框 Debug.Log("1.2 断线重连启动失败,打开返回登陆对话框!"); _remainCount = 0; _state = ReconnectStateCode.WaitExitReconnect; GameCenter.PushFixEvent(UIEventDefine.UI_RECONNECTFORM_OPEN); } } //1.1判断重连条件 private bool CheckReconnectCondition() { if (string.IsNullOrEmpty(_sign)) { Debug.LogError("1.0.当前Sign值为空,不能进行重连"); return false; } if (GameCenter.GameStateSystem == null || GameCenter.GameStateSystem.GetCurState() == null) { Debug.LogError("1.0.游戏状态还没有开启,不能进行重连"); return false; } if (GameCenter.GameStateSystem.GetCurState().GetStateId() != (int)GameStateId.World) { Debug.LogError("1.0.游戏状态还没有在World中,不能进行重连."); return false; } if (GameCenter.GameSceneSystem.GetLocalPlayer() == null) { Debug.LogError("1.0.主角信息没有加载,不能进行重连."); return false; } return true; } //2.0 进行Socket重连 private void StartConnectSocket() { //socket连接成功的状态,直接跳过 if (GameCenter.Networker.IsConnected) { //如果当前网络是连接状态,那么就直接发送重连消息 Debug.Log("2.1.2 当前网络状态是连接状态,直接判断连接socket成功!"); _state = ReconnectStateCode.SocketConnectSuccess; return; } else { Debug.Log("2.0 重连Socket"); _state = ReconnectStateCode.WaitSocketConnecting; //断线重连第一步,把Socket先连上,后面才能发送消息 GameCenter.Networker.Connect( _result => { if (_result) { UnityEngine.Debug.Log("2.1 重新连接Socket成功!"); _state = ReconnectStateCode.SocketConnectSuccess; } else { UnityEngine.Debug.Log("2.2.重新连接Socket失败!"); _state = ReconnectStateCode.SocketConnectFail; } }); } } //3. 重连Socket尝试完成,发送断线消息 private void ReconnectSocketSuccess() { GameCenter.GameSceneSystem.ActivedScene.Entities.RemoveAllRemoteObjects(); GameCenter.GameSceneSystem.GetLocalPlayer().ClearStrikeBackCharacter(); Debug.LogError("3.0 往服务器发送断线重连请求."); GameCenter.Networker.StartThread(); //发送断线重连消息 SendReqReconnect(); } //4.socket连接失败或者 private void ProcessFail(ReconnectStateCode failCode) { Debug.LogErrorFormat("4.0上次重连失败,失败原因:{0},重连剩余次数:{1}", failCode.ToString(), _remainCount); if (_remainCount > 0) { //如果失败,就继续进行连接 _state = ReconnectStateCode.ReconnectSocketCD; _waitTime = CN_SOCKET_CONNECT_WAIT_TIME; _remainCount--; GameCenter.PushFixEvent(UIEventDefine.UI_RECONNECTFORM_OPEN); } else { Debug.LogError("4.0重连次数使用完毕,返回登陆"); _state = ReconnectStateCode.WaitExitReconnect; Networker.Instance.Disconnect(false); GameCenter.PushFixEvent(UIEventDefine.UI_RECONNECTFORM_OPEN); } } #endregion #region//私有枚举 //重连状态 private enum ReconnectStateCode { //空闲,没有进行重连过 Idle, //开始重连 StartReconnect, //等待判断是否可以重连 WaitCheckReconnect, //等待Socket的连接的CD ReconnectSocketCD, //开始Socket的连接 StartConnectSocket, //等待Socket正在连接 WaitSocketConnecting, //Socket连接成功 SocketConnectSuccess, //连接失败 SocketConnectFail, //等待网络消息 WaitNetMessage, //等待网络消息失败 WaitNetMessageFail, //重连成功 ReconnectSuccess, //重连失败 ReconnectFail, //等待退出连接 WaitExitReconnect, } #endregion } }