Files
Main/Assets/Code/Logic/_Required/Reconnect/ReconnectSystem_New.cs
2025-01-25 04:38:09 +08:00

447 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//**********************************************//
//作者:#AUTHOR#
//日期:#DATE#
//简述:#DESCRIPTION#
//*********************************************//
using Thousandto.Code.Center;
using Thousandto.Core.Base;
using Thousandto.Plugins.Common;
using UnityEngine;
namespace Thousandto.Code.Logic
{
/// <summary>
/// 断线重连
/// </summary>
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
}
}