#if ENABLE_UNET using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using UnityEngine.Networking.NetworkSystem; namespace UnityEngine.Networking { public class NetworkClient { Type m_NetworkConnectionClass = typeof(NetworkConnection); static List s_Clients = new List(); static bool s_IsActive; public static List allClients { get { return s_Clients; } } public static bool active { get { return s_IsActive; } } HostTopology m_HostTopology; int m_HostPort; string m_ServerIp = ""; int m_ServerPort; int m_ClientId = -1; int m_ClientConnectionId = -1; Dictionary m_MessageHandlers = new Dictionary(); protected NetworkConnection m_Connection; protected enum ConnectState { None, Connecting, Connected, Disconnected, } protected ConnectState connectState = ConnectState.None; internal void SetHandlers(NetworkConnection conn) { conn.SetHandlers(m_MessageHandlers); } public string serverIp { get { return m_ServerIp; } } public int serverPort { get { return m_ServerPort; } } public NetworkConnection connection { get { return m_Connection; } } public Dictionary handlers { get { return m_MessageHandlers; } } public int numChannels { get { return m_HostTopology.DefaultConfig.ChannelCount; } } public HostTopology hostTopology { get { return m_HostTopology; }} public int hostPort { get { return m_HostPort; } set { if (value < 0) throw new ArgumentException("Port must not be a negative number."); if (value > 65535) throw new ArgumentException("Port must not be greater than 65535."); m_HostPort = value; } } public bool isConnected { get { return connectState == ConnectState.Connected; } } public Type networkConnectionClass { get { return m_NetworkConnectionClass; } } public void SetNetworkConnectionClass() where T : NetworkConnection { m_NetworkConnectionClass = typeof(T); } public NetworkClient() { if (LogFilter.logDev) { Debug.Log("Client created version " + Version.Current); } AddClient(this); } public NetworkClient(NetworkConnection conn) { if (LogFilter.logDev) { Debug.Log("Client created version " + Version.Current); } AddClient(this); SetActive(true); m_Connection = conn; connectState = ConnectState.Connected; conn.SetHandlers(m_MessageHandlers); RegisterSystemHandlers(false); } public bool Configure(ConnectionConfig config, int maxConnections) { HostTopology top = new HostTopology(config, maxConnections); return Configure(top); } public bool Configure(HostTopology topology) { //NOTE: this maxConnections is across all clients that use this tuner, so it is // effectively the number of _clients_. m_HostTopology = topology; return true; } static bool IsValidIpV6(string address) { // use C# built-in method IPAddress temp; return IPAddress.TryParse(address, out temp) && temp.AddressFamily == AddressFamily.InterNetworkV6; } public void Connect(string serverIp, int serverPort) { PrepareForConnect(false); if (LogFilter.logDebug) { Debug.Log("Client Connect: " + serverIp + ":" + serverPort); } string hostnameOrIp = serverIp; m_ServerPort = serverPort; m_ServerIp = hostnameOrIp; connectState = ConnectState.Connecting; Transport.client.Connect(serverIp, serverPort); // setup all the handlers m_ClientConnectionId = 0; m_Connection = (NetworkConnection)Activator.CreateInstance(m_NetworkConnectionClass); m_Connection.SetHandlers(m_MessageHandlers); m_Connection.Initialize(m_ServerIp, m_ClientId, m_ClientConnectionId, m_HostTopology); } void PrepareForConnect(bool usePlatformSpecificProtocols) { SetActive(true); RegisterSystemHandlers(false); if (m_HostTopology == null) { var config = new ConnectionConfig(); config.AddChannel(QosType.ReliableSequenced); config.AddChannel(QosType.Unreliable); config.UsePlatformSpecificProtocols = usePlatformSpecificProtocols; m_HostTopology = new HostTopology(config, 8); } m_ClientId = 0; // NetworkTransport.AddHost 'Returns the ID of the host that was created.' } public virtual void Disconnect() { connectState = ConnectState.Disconnected; ClientScene.HandleClientDisconnect(m_Connection); if (m_Connection != null) { m_Connection.Disconnect(); m_Connection.Dispose(); m_Connection = null; m_ClientId = -1; } } public bool SendByChannel(short msgType, MessageBase msg, int channelId) { if (m_Connection != null) { if (connectState != ConnectState.Connected) { if (LogFilter.logError) { Debug.LogError("NetworkClient SendByChannel when not connected to a server"); } return false; } return m_Connection.SendByChannel(msgType, msg, channelId); } if (LogFilter.logError) { Debug.LogError("NetworkClient SendByChannel with no connection"); } return false; } public bool Send(short msgType, MessageBase msg) { return SendByChannel(msgType, msg, Channels.DefaultReliable); } public bool SendUnreliable(short msgType, MessageBase msg) { return SendByChannel(msgType, msg, Channels.DefaultUnreliable); } public void Shutdown() { if (LogFilter.logDebug) Debug.Log("Shutting down client " + m_ClientId); m_ClientId = -1; RemoveClient(this); if (s_Clients.Count == 0) { SetActive(false); } } internal virtual void Update() { //Debug.Log("NetworkClient.Update" + m_ClientId + " connectstate=" + connectState); if (m_ClientId == -1) { return; } // don't do anything if we aren't fully connected // -> we don't check Client.Connected because then we wouldn't // process the last disconnect message. if (connectState != ConnectState.Connecting && connectState != ConnectState.Connected) { return; } //Debug.Log("+++NetworkClient.Update calls NetworkTransport.ReceiveFromHost"); // any new message? // -> calling it once per frame is okay, but really why not just // process all messages and make it empty.. Telepathy.Message msg; while (Transport.client.GetNextMessage(out msg)) { switch (msg.eventType) { case Telepathy.EventType.Connected: Debug.Log("NetworkClient loop: Connected"); m_Connection.InvokeHandlerNoData((short)MsgType.Connect); connectState = ConnectState.Connected; break; case Telepathy.EventType.Data: Debug.Log("NetworkClient loop: Data: " + BitConverter.ToString(msg.data)); m_Connection.TransportReceive(msg.data, 0); break; case Telepathy.EventType.Disconnected: Debug.Log("NetworkClient loop: Disconnected"); connectState = ConnectState.Disconnected; //GenerateDisconnectError(error); TODO which one? ClientScene.HandleClientDisconnect(m_Connection); if (m_Connection != null) { m_Connection.InvokeHandlerNoData((short)MsgType.Disconnect); } break; } } } void GenerateConnectError(byte error) { if (LogFilter.logError) { Debug.LogError("UNet Client Error Connect Error: " + error); } GenerateError(error); } void GenerateDataError(byte error) { NetworkError dataError = (NetworkError)error; if (LogFilter.logError) { Debug.LogError("UNet Client Data Error: " + dataError); } GenerateError(error); } void GenerateDisconnectError(byte error) { NetworkError disconnectError = (NetworkError)error; if (LogFilter.logError) { Debug.LogError("UNet Client Disconnect Error: " + disconnectError); } GenerateError(error); } void GenerateError(byte error) { NetworkMessageDelegate msgDelegate; if (m_MessageHandlers.TryGetValue((short)MsgType.Error, out msgDelegate)) { ErrorMessage msg = new ErrorMessage(); msg.errorCode = error; // write the message to a local buffer NetworkWriter writer = new NetworkWriter(); msg.Serialize(writer); NetworkMessage netMsg = new NetworkMessage(); netMsg.msgType = (short)MsgType.Error; netMsg.reader = new NetworkReader(writer.ToArray()); netMsg.conn = m_Connection; netMsg.channelId = 0; msgDelegate(netMsg); } } public int GetRTT() { if (m_ClientId == -1) return 0; // TODO //return NetworkTransport.GetCurrentRTT(m_ClientId, m_ClientConnectionId, out err); Debug.Log("NetworkClient.GetRTT calls NetworkTransport.GetCurrentRTT"); return 0; } internal void RegisterSystemHandlers(bool localClient) { ClientScene.RegisterSystemHandlers(this, localClient); } public void RegisterHandler(short msgType, NetworkMessageDelegate handler) { if (m_MessageHandlers.ContainsKey(msgType)) { if (LogFilter.logDebug) { Debug.Log("NetworkClient.RegisterHandler replacing " + msgType); } } m_MessageHandlers[msgType] = handler; } public void UnregisterHandler(short msgType) { m_MessageHandlers.Remove(msgType); } internal static void AddClient(NetworkClient client) { s_Clients.Add(client); } internal static bool RemoveClient(NetworkClient client) { return s_Clients.Remove(client); } static internal void UpdateClients() { // remove null clients first s_Clients.RemoveAll(cl => cl == null); // now updating valid clients for (int i = 0; i < s_Clients.Count; ++i) { s_Clients[i].Update(); } } static public void ShutdownAll() { while (s_Clients.Count != 0) { s_Clients[0].Shutdown(); } s_Clients = new List(); s_IsActive = false; ClientScene.Shutdown(); } internal static void SetActive(bool state) { s_IsActive = state; } }; } #endif //ENABLE_UNET