using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.Net; namespace BF { public class NetManager : ManagerBase { private class ClientInfo { public string Name; public NetConnectStatus LastConnectStatus; } public const string MAIN_SOCKET_NAME = "0"; public const string CHAT_SOCKET_NAME = "1"; public const int MAIN_SOCKET_NAME_INT = 0; public const int CHAT_SOCKET_NAME_INT = 1; static NetManager instance; private NetClient netClient; private List clients = new List(); private event Action OnReceiveMsgLuaCallback; private event Action OnConnectedLuaCallback; private event Action OnDisconnectedLuaCallback; private event Action OnReconnectSuccessLuaCallback; private event Action OnReconnectLuaCallback; private event Action OnErrorLuaCallback; public event Action luaAuthCallback; private event Action OnDecodePbCallback; public byte [] loginReqData = null; public byte [] authReqData = null; public byte [] ChatAuthReqData = null; public string decodePbStr = null; public string decodeChatPbStr = null; public uint rspGroup = 0; public uint rspChatGroup = 0; public bool decodeFinish = false; public bool decodeChatFinish = false; public static NetManager Create() { BFLog.LogAssert(instance == null, "This method only allows BFMain to call once"); instance = new NetManager(); instance.Init(); return instance; } public override void Init() { netClient = NetClient.Instance; netClient.Init(); NetConfiguration configuration = new NetConfiguration { ServiceType = NetServiceType.TCPService, ThreadName = "NetTCP" }; netClient.SetupService(configuration); netClient.Start(); } public override void Update() { var count = clients.Count; for (int i = 0; i < count; ++i) { var clientInfo = clients[i]; if(!ReferenceEquals(clientInfo, null)) { INetIncomingMessage incomingMessage = null; while ((incomingMessage = netClient.ReadMessage(clientInfo.Name)) != null) { HandleIncomingMessage(i, incomingMessage); netClient.RecycleMessage(clientInfo.Name, incomingMessage); } } } } public void InitNetClientCount(int count) { if (clients.Count < count) { for (int i = clients.Count; i < count; i++) { clients.Add(null); } } } /// /// 根据消息类型,处理消息; /// DebugMessage 内部调试信息,release版本不会有任何此类消息; /// WarningMessage 警告信息,release版本会包含,有警告需要注意,但不会影响正常运行; /// ErrorMessage 用于所有错误异常信息,包含socket异常;特别注意消息内的 ErrorCode,在 HandleIncomingMessageError 中,有详细说明; /// Data 数据消息,代表从服务器接收到的所有PB消息(密钥交换、心跳,重连三种除外),可以添加消息处理回调; /// StatusChange : 当GetConnectStatus(string) 获取到的状态改变时,就收到这个消息,可以用来监听连接成功断开事件 /// /// /// private void HandleIncomingMessage(int clientId, INetIncomingMessage message) { // BFLog.Log("HandleIncomingMessage message.MessageType = " + message.MessageType.ToString()); switch (message.MessageType) { case NetIncomingMessageType.DebugMessage: case NetIncomingMessageType.WarningMessage: BFLog.Log("Debug Info {0} : {1} : {2}", clientId, message.ErrorCode, message.ErrorMsg); break; case NetIncomingMessageType.ErrorMessage: HandleIncomingMessageError(clientId, message); break; case NetIncomingMessageType.Data: HandleIncomingMessageData(clientId, message.Group, message.Seq, message.Data); break; case NetIncomingMessageType.StatusChange: HandleConnectStatusChange(clientId, message); break; case NetIncomingMessageType.HeartBeatMessage: break; default: BFLog.Log("Not Implemented Message"); break; } } /// /// 根据ErrorCode进行对应处理:SocketError 为 -1 ~ 11004,自定义错误码开始于20000 /// !!!特别注意 !!! /// 如果 ErrorCode 是 NetErrorCode.PeerDisconnect,代表当前连接已经被彻底断掉(重连也失败了),游戏应该关闭当前连接,重新创建新的连接; /// /// private void HandleIncomingMessageError(int clientId, INetIncomingMessage message) { OnErrorLuaCallback?.Invoke(clientId, message.ErrorCode, message.ErrorMsg); } /// /// 处理接收到的服务器消息 /// /// /// /// PB 消息 private void HandleIncomingMessageData(int clientId, uint group, uint seq, byte[] data) { OnReceiveMsgLuaCallback?.Invoke(clientId, group, seq, data); } private void HandleConnectStatusChange(int clientId, INetIncomingMessage message) { var clientInfo = clients[clientId]; // BFLog.Log("===== HandleConnectStatusChange lastConnectStatus = " + clientInfo.LastConnectStatus.ToString()); if(ReferenceEquals(clientInfo, null)) { return; } NetConnectStatus status = message.ConnectStatus; NetConnectStatus lastConnectStatus = clientInfo.LastConnectStatus; // BFLog.Log("===== HandleConnectStatusChange status = " + status.ToString()); if (status == lastConnectStatus) { return; } clientInfo.LastConnectStatus = status; if (lastConnectStatus == NetConnectStatus.Authing && status == NetConnectStatus.Decoding) { HandleDecodePbChange(clientId, message.Group, message.Seq, message.Data); } else if (lastConnectStatus == NetConnectStatus.Reconnecting && status == NetConnectStatus.Decoding) { HandleDecodePbChange(clientId, message.Group, message.Seq, message.Data); } else if (lastConnectStatus == NetConnectStatus.Reconnecting && status == NetConnectStatus.Decoding2) { HandleDecodePbChange(clientId, message.Group, message.Seq, message.Data); } else if (lastConnectStatus == NetConnectStatus.Authing && status == NetConnectStatus.Unauthorized) { luaAuthCallback?.Invoke(false); } else if (lastConnectStatus == NetConnectStatus.Reconnecting && status == NetConnectStatus.Unauthorized) { luaAuthCallback?.Invoke(false); } else if (lastConnectStatus == NetConnectStatus.Decoding2 && status == NetConnectStatus.Connected) { OnReconnectSuccessLuaCallback?.Invoke(clientId); } else if (lastConnectStatus != NetConnectStatus.Connected && status == NetConnectStatus.Connected) { OnConnectedLuaCallback?.Invoke(clientId); } else if (LastConnectStatusIsTryOrConnect(lastConnectStatus) && status == NetConnectStatus.Disconnected) { OnDisconnectedLuaCallback?.Invoke(clientId); } else if (lastConnectStatus != NetConnectStatus.Reconnecting && status == NetConnectStatus.Reconnecting) { OnReconnectLuaCallback?.Invoke(clientId); } } public void HandleDecodePbChange(int clientId, uint group, uint seq, byte[] data) { if (clientId == MAIN_SOCKET_NAME_INT) { decodeFinish = false; } else if (clientId == CHAT_SOCKET_NAME_INT) { decodeChatFinish = false; } OnDecodePbCallback?.Invoke(clientId, group, seq, data); } /// /// 如果上一次是在Connecting,VerifyConnecting,Connected任何一种状态,当断开时,都应该调用DisconnectEvent事件 /// /// private bool LastConnectStatusIsTryOrConnect(NetConnectStatus lastConnectStatus) { return lastConnectStatus == NetConnectStatus.Connected || lastConnectStatus == NetConnectStatus.Connecting || lastConnectStatus == NetConnectStatus.VerifyConnecting || lastConnectStatus == NetConnectStatus.Reconnecting; } public string GetConnectIP(int clientId) { var clientInfo = clients[clientId]; if (ReferenceEquals(clientInfo, null)) { return ""; } return netClient.GetConnectIP(clientInfo.Name); } public bool IsConnected(int clientId) { var clientInfo = clients[clientId]; if (ReferenceEquals(clientInfo, null)) { return false; } return netClient.GetConnectStatus(clientInfo.Name) == NetConnectStatus.Connected; } public bool IsDisconnected(int clientId) { var clientInfo = clients[clientId]; if (ReferenceEquals(clientInfo, null)) { return true; } var currStatus = netClient.GetConnectStatus(clientInfo.Name); return currStatus == NetConnectStatus.Disconnecting || currStatus == NetConnectStatus.Disconnected; } public bool IsAvailable(int clientId) { var clientInfo = clients[clientId]; if (ReferenceEquals(clientInfo, null)) { return false; } var currStatus = netClient.GetConnectStatus(clientInfo.Name); return currStatus == NetConnectStatus.Connected || currStatus == NetConnectStatus.Connecting || currStatus == NetConnectStatus.Reconnecting || currStatus == NetConnectStatus.VerifyConnecting; } public bool IsClosed(int clientId) { var clientInfo = clients[clientId]; if (ReferenceEquals(clientInfo, null)) { return true; } var currStatus = netClient.GetConnectStatus(clientInfo.Name); return currStatus == NetConnectStatus.Disconnected; } public void Reconnect(int clientId) { var clientInfo = clients[clientId]; if (ReferenceEquals(clientInfo, null)) { return; } netClient.Reconnect(clientInfo.Name); } public long GetServerTimestamp(int clientId) { var clientInfo = clients[clientId]; if (ReferenceEquals(clientInfo, null)) { return 0; } return netClient.GetServerTimestamp(clientInfo.Name); } /// /// 使用configuration创建连接 /// public void ConnectWithDomainName(int clientId, string clientName, string domainName, int port) { NetConnectConfiguration configuration = new NetConnectConfiguration(NetServiceType.TCPService, clientName); /** * 启用的消息类型 * DebugMessage : release版本中不会收到此类消息; * WarningMessage :不需要处理,但要注意; * ErrorMessage :必须启用,用以接受异常消息; * Data : 应用消息,默认启用; * * 其他消息暂未使用 */ configuration.EnableMessageType(NetIncomingMessageType.DebugMessage); configuration.EnableMessageType(NetIncomingMessageType.WarningMessage); configuration.EnableMessageType(NetIncomingMessageType.ErrorMessage); ConnectWithConfiguration(clientId, configuration, domainName, port); } public void ConnectWithConfiguration(int clientId, NetConnectConfiguration configuration, string domainName, int port) { ClientInfo clientInfo = new ClientInfo(); clientInfo.Name = clientId.ToString(); clientInfo.LastConnectStatus = NetConnectStatus.InvalidConnect; clients[clientId] = clientInfo; netClient.Connect(configuration, domainName, port); } public void Send(int clientId, uint group, byte cmd, byte[] data) { /** * 直接发送数据 */ var clientInfo = clients[clientId]; if(ReferenceEquals(clientInfo, null)) { return; } netClient.Send(clientInfo.Name, group, cmd, data); } /// /// 关闭目标连接 /// public void Close(int clientId) { var clientInfo = clients[clientId]; if(ReferenceEquals(clientInfo, null)) { return; } clients[clientId] = null; netClient.Close(clientInfo.Name); } public byte[] GetAuthReqData() { return authReqData; } public byte[] GetChatAuthReqData() { return ChatAuthReqData; } public byte[] GetLoginReqData() { return loginReqData; } public bool GetDecodeStataus() { return decodeFinish; } public bool GetDecodeChatStataus() { return decodeChatFinish; } public string GetDecodePbStr() { return decodePbStr; } public string GetDecodeChatPbStr() { return decodeChatPbStr; } public uint GetDecodeGroup() { return rspGroup; } public uint GetDecodeChatGroup() { return rspChatGroup; } public void AddLuaOnReceiveMessage(Action luaFunc) { OnReceiveMsgLuaCallback = luaFunc; } public void RemoveLuaOnReceiveMessage() { OnReceiveMsgLuaCallback = null; } public void AddLuaOnConnected(Action luaFunc) { OnConnectedLuaCallback = luaFunc; } public void RemoveLuaOnConnected() { OnConnectedLuaCallback = null; } public void AddLuaOnDisconnected(Action luaFunc) { OnDisconnectedLuaCallback = luaFunc; } public void RemoveLuaOnDisconnected() { OnDisconnectedLuaCallback = null; } public void AddLuaOnReconnectSuccess(Action luaFunc) { OnReconnectSuccessLuaCallback = luaFunc; } public void RemoveLuaOnReconnectSuccess() { OnReconnectSuccessLuaCallback = null; } public void AddLuaOnReconnect(Action luaFunc) { OnReconnectLuaCallback = luaFunc; } public void RemoveLuaOnReconnect() { OnReconnectLuaCallback = null; } public void SetLuaAuthCallback(Action callback) { luaAuthCallback = callback; } public void SetLuaOnDecodePbCallback(Action luaFunc) { OnDecodePbCallback = luaFunc; } public void RemoveLuaOnDecodePbCallback() { OnDecodePbCallback = null; } public void AddLuaOnError(Action luaFunc) { OnErrorLuaCallback = luaFunc; } public void RemoveLuaOnError() { OnErrorLuaCallback = null; } public void RemoveAllLuaCallback() { OnReceiveMsgLuaCallback = null; OnConnectedLuaCallback = null; OnDisconnectedLuaCallback = null; OnReconnectSuccessLuaCallback = null; OnReconnectLuaCallback = null; OnErrorLuaCallback = null; OnDecodePbCallback = null; } public override void Destroy() { RemoveAllLuaCallback(); netClient.Shutdown(); netClient = null; } } }