/// <summary> /// Disconnects the network system. You should kill threads ONLY from main thread /// </summary> /// <param name="reason">Reason</param> public static void Disconnect(string reason = "unknown") { lock (DisconnectLock) { if (MainSystem.NetworkState > ClientState.Disconnected) { LunaLog.Log($"[LMP]: Disconnected, reason: {reason}"); if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) { SystemsContainer.Get <MainSystem>().ForceQuit = true; } else { //User is in flight so just display a message but don't force him to main menu... NetworkSystem.DisplayDisconnectMessage = true; } SystemsContainer.Get <MainSystem>().Status = $"Disconnected: {reason}"; //DO NOT set networkstate as disconnected as we are in another thread! MainSystem.NetworkState = ClientState.DisconnectRequested; NetworkMain.ClientConnection.Disconnect(reason); NetworkMain.ClientConnection.Shutdown(reason); NetworkMain.ResetConnectionStaticsAndQueues(); } } }
/// <summary> /// Disconnects the network system. You should kill threads ONLY from main thread /// </summary> /// <param name="reason">Reason</param> public static void Disconnect(string reason = "unknown") { lock (DisconnectLock) { if (MainSystem.Singleton.NetworkState != ClientState.DISCONNECTED) { Debug.Log("[LMP]: Disconnected, reason: " + reason); if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) { MainSystem.Singleton.ForceQuit = true; } else { //User is in flight so just display a message but don't force him to main menu... MainSystem.Singleton.DisplayDisconnectMessage = true; } MainSystem.Singleton.GameRunning = false; MainSystem.Singleton.Status = "Disconnected: " + reason; MainSystem.Singleton.NetworkState = ClientState.DISCONNECTED; NetworkMain.ClientConnection.Disconnect(reason); NetworkMain.ClientConnection.Shutdown(reason); NetworkMain.ResetConnectionStaticsAndQueues(); } } }
/// <summary> /// Sends the network message. It will skip client messages to send when we are not connected /// </summary> /// <param name="message"></param> private static void SendNetworkMessage(IMessageBase message) { if (NetworkMain.ClientConnection.Status == NetPeerStatus.NotRunning) { NetworkMain.ClientConnection.Start(); } var clientMessage = message as IClientMessageBase; var masterSrvMessage = message as IMasterServerMessageBase; if (clientMessage?.MessageType == ClientMessageType.SyncTime) { SystemsContainer.Get <TimeSyncerSystem>().RewriteMessage(message.Data); } message.Data.SentTime = DateTime.UtcNow.Ticks; var bytes = message.Serialize(SettingsSystem.CurrentSettings.CompressionEnabled); if (bytes != null) { try { NetworkStatistics.LastSendTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; if (masterSrvMessage != null && clientMessage == null) { foreach (var masterServer in NetworkServerList.MasterServers) { //Create a new message for every main server otherwise lidgren complains when you reuse the msg var lidgrenMsg = NetworkMain.ClientConnection.CreateMessage(bytes.Length); lidgrenMsg.Write(message.Serialize(SettingsSystem.CurrentSettings.CompressionEnabled)); NetworkMain.ClientConnection.SendUnconnectedMessage(lidgrenMsg, masterServer); NetworkMain.ClientConnection.FlushSendQueue(); } } else { if (SystemsContainer.Get <MainSystem>().NetworkState >= ClientState.Connected) { var lidgrenMsg = NetworkMain.ClientConnection.CreateMessage(bytes.Length); lidgrenMsg.Write(message.Serialize(SettingsSystem.CurrentSettings.CompressionEnabled)); NetworkMain.ClientConnection.SendMessage(lidgrenMsg, message.NetDeliveryMethod, message.Channel); } } NetworkMain.ClientConnection.FlushSendQueue(); } catch (Exception e) { NetworkMain.HandleDisconnectException(e); } } }
/// <summary> /// Sends the network message. It will skip client messages to send when we are not connected /// </summary> /// <param name="message"></param> private static void SendNetworkMessage(IMessageBase message) { if (NetworkMain.ClientConnection.Status == NetPeerStatus.NotRunning) { NetworkMain.ClientConnection.Start(); } message.Data.SentTime = LunaNetworkTime.UtcNow.Ticks; try { NetworkStatistics.LastSendTime = LunaNetworkTime.UtcNow; if (message is IMasterServerMessageBase) { foreach (var masterServer in NetworkServerList.MasterServers) { //Don't reuse lidgren messages, he does that on it's own var lidgrenMsg = NetworkMain.ClientConnection.CreateMessage(message.GetMessageSize()); message.Serialize(lidgrenMsg); NetworkMain.ClientConnection.SendUnconnectedMessage(lidgrenMsg, masterServer); //Force send of packets NetworkMain.ClientConnection.FlushSendQueue(); } } else { if (MainSystem.NetworkState >= ClientState.Connected) { var lidgrenMsg = NetworkMain.ClientConnection.CreateMessage(message.GetMessageSize()); message.Serialize(lidgrenMsg); NetworkMain.ClientConnection.SendMessage(lidgrenMsg, message.NetDeliveryMethod, message.Channel); } } //Force send of packets NetworkMain.ClientConnection.FlushSendQueue(); message.Recycle(); } catch (Exception e) { NetworkMain.HandleDisconnectException(e); } }
private static void ConnectToServerAddress(IPEndPoint destination) { try { var outmsg = NetworkMain.ClientConnection.CreateMessage(1); outmsg.Write((byte)NetIncomingMessageType.ConnectionApproval); NetworkMain.ClientConnection.Start(); NetworkMain.ClientConnection.Connect(destination); NetworkMain.ClientConnection.FlushSendQueue(); var connectionTrials = 0; while (MainSystem.NetworkState == ClientState.Connecting && NetworkMain.ClientConnection.ConnectionStatus == NetConnectionStatus.Disconnected && connectionTrials <= SettingsSystem.CurrentSettings.ConnectionTries) { connectionTrials++; Thread.Sleep(SettingsSystem.CurrentSettings.MsBetweenConnectionTries); } if (NetworkMain.ClientConnection.ConnectionStatus != NetConnectionStatus.Disconnected) { LunaLog.Log($"[LMP]: Connected to {destination.Address} port {destination.Port}"); SystemsContainer.Get <MainSystem>().Status = "Connected"; MainSystem.NetworkState = ClientState.Connected; NetworkSender.OutgoingMessages.Enqueue(NetworkMain.CliMsgFactory.CreateNew <HandshakeCliMsg>(new HandshakeRequestMsgData())); } else if (MainSystem.NetworkState == ClientState.Connecting) { LunaLog.LogError("[LMP]: Failed to connect within the timeout!"); Disconnect("Initial connection timeout"); } } catch (Exception e) { NetworkMain.HandleDisconnectException(e); } }
/// <summary> /// Main receiveing thread /// </summary> public static void ReceiveMain() { try { while (!NetworkConnection.ResetRequested) { if (NetworkMain.ClientConnection.ReadMessage(out var msg)) { NetworkStatistics.LastReceiveTime = LunaNetworkTime.UtcNow; switch (msg.MessageType) { case NetIncomingMessageType.DebugMessage: LunaLog.Log("[Lidgen DEBUG] " + msg.ReadString()); break; case NetIncomingMessageType.VerboseDebugMessage: LunaLog.Log("[Lidgen VERBOSE] " + msg.ReadString()); break; case NetIncomingMessageType.NatIntroductionSuccess: NetworkServerList.HandleNatIntroduction(msg); break; case NetIncomingMessageType.ConnectionLatencyUpdated: NetworkStatistics.PingMs = (float)TimeSpan.FromSeconds(msg.ReadFloat()).TotalMilliseconds; break; case NetIncomingMessageType.UnconnectedData: NetworkServerList.HandleServersList(msg); break; case NetIncomingMessageType.Data: try { var deserializedMsg = NetworkMain.SrvMsgFactory.Deserialize(msg, LunaNetworkTime.UtcNow.Ticks); if (deserializedMsg != null) { EnqueueMessageToSystem(deserializedMsg as IServerMessageBase); } } catch (Exception e) { LunaLog.LogError($"[LMP]: Error deserializing message! {e}"); } break; case NetIncomingMessageType.StatusChanged: switch ((NetConnectionStatus)msg.ReadByte()) { case NetConnectionStatus.Disconnected: var reason = msg.ReadString(); NetworkConnection.Disconnect(reason); break; } break; default: LunaLog.Log($"[LMP]: LIDGREN: {msg.MessageType} -- {msg.PeekString()}"); break; } NetworkMain.ClientConnection.Recycle(msg); } else { Thread.Sleep(SettingsSystem.CurrentSettings.SendReceiveMsInterval); } } } catch (Exception e) { LunaLog.LogError($"[LMP]: Receive message thread error: {e}"); NetworkMain.HandleDisconnectException(e); } }
/// <summary> /// Main receiveing thread /// </summary> public static void ReceiveMain() { try { while (!MainSystem.Singleton.Quit) { NetIncomingMessage msg; while (NetworkMain.ClientConnection.ReadMessage(out msg)) { NetworkStatistics.LastReceiveTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; switch (msg.MessageType) { case NetIncomingMessageType.NatIntroductionSuccess: NetworkServerList.HandleNatIntroduction(msg); break; case NetIncomingMessageType.ConnectionLatencyUpdated: NetworkStatistics.PingMs = (float)TimeSpan.FromSeconds(msg.ReadFloat()).TotalMilliseconds; break; case NetIncomingMessageType.UnconnectedData: NetworkServerList.HandleServersList(msg); break; case NetIncomingMessageType.Data: try { var deserializedMsg = NetworkMain.SrvMsgFactory.Deserialize(msg.ReadBytes(msg.LengthBytes), DateTime.UtcNow.Ticks); EnqueueMessageToSystem(deserializedMsg as IServerMessageBase); } catch (Exception e) { Debug.LogError("[LMP]: Error deserializing message!"); NetworkMain.HandleDisconnectException(e); } break; case NetIncomingMessageType.StatusChanged: switch ((NetConnectionStatus)msg.ReadByte()) { case NetConnectionStatus.Disconnected: var reason = msg.ReadString(); NetworkConnection.Disconnect(reason); break; } break; default: Debug.Log("[LMP]: LIDGREN: " + msg.MessageType + "-- " + msg.PeekString()); break; } } Thread.Sleep(SettingsSystem.CurrentSettings.SendReceiveMsInterval); } } catch (Exception e) { Debug.LogError("[LMP]: Receive message thread error: " + e); NetworkMain.HandleDisconnectException(e); } }
private static void ConnectToServer(string endpointString, string serverPassword) { if (NetworkMain.ClientConnection.Status == NetPeerStatus.NotRunning) { NetworkMain.ClientConnection.Start(); } if (MainSystem.NetworkState <= ClientState.Disconnected) { var endpoint = CreateEndpoint(endpointString); if (endpoint == null) { return; } MainSystem.Singleton.Status = $"Connecting to {endpoint.Address}:{endpoint.Port}"; LunaLog.Log($"[LMP]: Connecting to {endpoint.Address} port {endpoint.Port}"); MainSystem.NetworkState = ClientState.Connecting; try { var outmsg = NetworkMain.ClientConnection.CreateMessage(serverPassword.GetByteCount()); outmsg.Write(serverPassword); NetworkMain.ClientConnection.Connect(endpoint, outmsg); NetworkMain.ClientConnection.FlushSendQueue(); var connectionTrials = 0; while (MainSystem.NetworkState >= ClientState.Connecting && NetworkMain.ClientConnection.ConnectionStatus != NetConnectionStatus.Connected && connectionTrials < SettingsSystem.CurrentSettings.ConnectionTries) { connectionTrials++; Thread.Sleep(SettingsSystem.CurrentSettings.MsBetweenConnectionTries); } if (NetworkMain.ClientConnection.ConnectionStatus == NetConnectionStatus.Connected) { LunaLog.Log($"[LMP]: Connected to {endpoint.Address}:{endpoint.Port}"); MainSystem.NetworkState = ClientState.Connected; } else { if (MainSystem.NetworkState == ClientState.Connecting) { Disconnect("Initial connection timeout"); } else { Disconnect("Cancelled connection"); } } } catch (Exception e) { NetworkMain.HandleDisconnectException(e); } } else { LunaLog.LogError("[LMP]: Cannot connect when we are already trying to connect"); } }