private static void SetupClient(TcpClient newClientConnection)
        {
            ClientObject newClientObject = new ClientObject();

            newClientObject.subspace         = Messages.WarpControl.GetLatestSubspace();
            newClientObject.playerStatus     = new PlayerStatus();
            newClientObject.connectionStatus = ConnectionStatus.CONNECTED;
            newClientObject.endpoint         = newClientConnection.Client.RemoteEndPoint.ToString();
            newClientObject.ipAddress        = (newClientConnection.Client.RemoteEndPoint as IPEndPoint).Address;
            //Keep the connection reference
            newClientObject.connection         = newClientConnection;
            newClientObject.connection.NoDelay = true;
            StartReceivingIncomingMessages(newClientObject);
            StartSendingOutgoingMessages(newClientObject);
            DMPPluginHandler.FireOnClientConnect(newClientObject);
            Messages.Handshake.SendHandshakeChallange(newClientObject);
            lock (clients)
            {
                List <ClientObject> newList = new List <ClientObject>(clients);
                newList.Add(newClientObject);
                clients            = newList.AsReadOnly();
                Server.playerCount = GetActiveClientCount();
                Server.players     = GetActivePlayerNames();
                DarkLog.Debug("Online players is now: " + Server.playerCount + ", connected: " + clients.Count);
            }
        }
 internal static void DisconnectClient(ClientObject client)
 {
     lock (client.disconnectLock)
     {
         //Remove clients from list
         if (clients.Contains(client))
         {
             List<ClientObject> newList = new List<ClientObject>(clients);
             newList.Remove(client);
             clients = newList.AsReadOnly();
             Server.playerCount = GetActiveClientCount();
             Server.players = GetActivePlayerNames();
             DarkLog.Debug("Online players is now: " + Server.playerCount + ", connected: " + clients.Count);
             if (!Settings.settingsStore.keepTickingWhileOffline && clients.Count == 0)
             {
                 Messages.WarpControl.HoldSubspace();
             }
             Messages.WarpControl.DisconnectPlayer(client.playerName);
         }
         //Disconnect
         if (client.connectionStatus != ConnectionStatus.DISCONNECTED)
         {
             DMPPluginHandler.FireOnClientDisconnect(client);
             if (client.playerName != null)
             {
                 Messages.Chat.RemovePlayer(client.playerName);
             }
             client.connectionStatus = ConnectionStatus.DISCONNECTED;
             if (client.authenticated)
             {
                 ServerMessage newMessage = new ServerMessage();
                 newMessage.type = ServerMessageType.PLAYER_DISCONNECT;
                 using (MessageWriter mw = new MessageWriter())
                 {
                     mw.Write<string>(client.playerName);
                     newMessage.data = mw.GetMessageBytes();
                 }
                 SendToAll(client, newMessage, true);
                 LockSystem.fetch.ReleasePlayerLocks(client.playerName);
             }
             try
             {
                 if (client.connection != null)
                 {
                     client.connection.GetStream().Close();
                     client.connection.Close();
                 }
             }
             catch (Exception e)
             {
                 DarkLog.Debug("Error closing client connection: " + e.Message);
             }
             Server.lastPlayerActivity = Server.serverClock.ElapsedMilliseconds;
         }
     }
 }
        private void DisconnectClient(ClientObject client, string aReason)
        {
            if (client.connectionStatus != ConnectionStatus.DISCONNECTED)
            {
                DMPPluginHandler.FireOnClientDisconnect(client);
                if (client.playerName != null)
                {
                    if (playerChatChannels.ContainsKey(client.playerName))
                    {
                        playerChatChannels.Remove(client.playerName);
                    }
                    if (playerDownloadedScreenshotIndex.ContainsKey(client.playerName))
                    {
                        playerDownloadedScreenshotIndex.Remove(client.playerName);
                    }
                    if (playerUploadedScreenshotIndex.ContainsKey(client.playerName))
                    {
                        playerUploadedScreenshotIndex.Remove(client.playerName);
                    }
                    if (playerWatchScreenshot.ContainsKey(client.playerName))
                    {
                        playerWatchScreenshot.Remove(client.playerName);
                    }
                }
                client.connectionStatus = ConnectionStatus.DISCONNECTED;
                if (client.authenticated)
                {
                    Messages.ServerClient_PlayerLeaveSend msg = new Messages.ServerClient_PlayerLeaveSend();
                    msg.name = client.playerName;
                    BroadcastBut(client, msg);

                    lockSystem.ReleasePlayerLocks(client.playerName);
                }

                m_clients.Remove(client);

                try
                {
                    m_server.Kick(client.Id, aReason);
                }
                catch (Exception e)
                {
                    DarkLog.Debug("Error closing client connection: " + e.Message);
                }
                Server.lastPlayerActivity = Server.serverClock.ElapsedMilliseconds;
            }
        }
        private void HandleMessage(IMessage aMessage)
        {
            if (DMPPluginHandler.FireOnMessageReceived(aMessage))
            {
                return;
            }

            try
            {
                Trigger(aMessage);
            }
            catch
            {
                //DarkLog.Debug("Error handling " + typeof(aMessage).ToString() + " from " + client.playerName + ", exception: " + e);
                m_server.Kick(aMessage.ConnectionId, "Server failed to process " + aMessage.GetType().ToString() + " message");
            }
        }
        public void Update()
        {
            try
            {
                m_clients.Flush();
                // TODO: Save subspace if player leaves and count == 0
                m_server.Run();

                // Dispatch events
                Run();
                //Check timers
                NukeKSC.CheckTimer();
                Dekessler.CheckTimer();
                //Run plugin update
                DMPPluginHandler.FireOnUpdate();
            }
            catch (Exception e)
            {
                DarkLog.Error("Fatal error thrown, exception: " + e);
                Server.ShutDown("Crashed!");
            }
        }
Exemple #6
0
        public static void Main()
        {
            #if !DEBUG
            try
            {
            #endif
            //Start the server clock
            serverClock = new Stopwatch();
            serverClock.Start();

            Settings.Reset();

            //Set the last player activity time to server start
            lastPlayerActivity = serverClock.ElapsedMilliseconds;

            //Periodic garbage collection
            long lastGarbageCollect = 0;

            //Periodic screenshot check
            long lastScreenshotExpiredCheck = 0;

            //Periodic log check
            long lastLogExpiredCheck = 0;

            //Periodic day check
            long lastDayCheck = 0;

            //Set universe directory and modfile path
            universeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Universe");
            modFile           = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DMPModControl.txt");

            if (!Directory.Exists(configDirectory))
            {
                Directory.CreateDirectory(configDirectory);
            }

            string oldSettingsFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DMPServerSettings.txt");
            string newSettingsFile = Path.Combine(Server.configDirectory, "Settings.txt");
            string oldGameplayFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DMPGameplaySettings.txt");
            string newGameplayFile = Path.Combine(Server.configDirectory, "GameplaySettings.txt");

            // Run the conversion
            BackwardsCompatibility.ConvertSettings(oldSettingsFile, newSettingsFile);
            if (File.Exists(oldGameplayFile))
            {
                if (!File.Exists(newGameplayFile))
                {
                    File.Move(oldGameplayFile, newGameplayFile);
                }
                File.Delete(oldGameplayFile);
            }

            //Register the server commands
            CommandHandler.RegisterCommand("exit", Server.ShutDown, "Shuts down the server");
            CommandHandler.RegisterCommand("quit", Server.ShutDown, "Shuts down the server");
            CommandHandler.RegisterCommand("shutdown", Server.ShutDown, "Shuts down the server");
            CommandHandler.RegisterCommand("restart", Server.Restart, "Restarts the server");
            CommandHandler.RegisterCommand("kick", KickCommand.KickPlayer, "Kicks a player from the server");
            CommandHandler.RegisterCommand("ban", BanSystem.fetch.BanPlayer, "Bans a player from the server");
            CommandHandler.RegisterCommand("banip", BanSystem.fetch.BanIP, "Bans an IP Address from the server");
            CommandHandler.RegisterCommand("bankey", BanSystem.fetch.BanPublicKey, "Bans a Guid from the server");
            CommandHandler.RegisterCommand("pm", PMCommand.HandleCommand, "Sends a message to a player");
            CommandHandler.RegisterCommand("admin", AdminCommand.HandleCommand, "Sets a player as admin/removes admin from the player");
            CommandHandler.RegisterCommand("whitelist", WhitelistCommand.HandleCommand, "Change the server whitelist");
            //Register the ctrl+c event
            Console.CancelKeyPress += new ConsoleCancelEventHandler(CatchExit);
            serverStarting          = true;

            //Fix kerbals from 0.23.5 to 0.24 (Now indexed by string, thanks Squad!
            BackwardsCompatibility.FixKerbals();

            //Remove player tokens
            BackwardsCompatibility.RemoveOldPlayerTokens();

            //Add new stock parts
            BackwardsCompatibility.UpdateModcontrolPartList();

            if (System.Net.Sockets.Socket.OSSupportsIPv6)
            {
                Settings.settingsStore.address = "::";
            }

            DarkLog.Debug("Loading settings...");
            Settings.Load();
            if (Settings.settingsStore.gameDifficulty == GameDifficulty.CUSTOM)
            {
                GameplaySettings.Reset();
                GameplaySettings.Load();
            }

            //Test compression
            if (Settings.settingsStore.compressionEnabled)
            {
                long testTime = Compression.TestSysIOCompression();
                Compression.compressionEnabled = true;
                DarkLog.Debug("System.IO compression works: " + Compression.sysIOCompressionWorks + ", test time: " + testTime + " ms.");
            }

            //Set day for log change
            day = DateTime.Now.Day;

            //Load plugins
            DMPPluginHandler.LoadPlugins();

            Console.Title = "DMPServer " + Common.PROGRAM_VERSION + ", protocol " + Common.PROTOCOL_VERSION;

            while (serverStarting || serverRestarting)
            {
                if (serverRestarting)
                {
                    DarkLog.Debug("Reloading settings...");
                    Settings.Reset();
                    Settings.Load();
                    if (Settings.settingsStore.gameDifficulty == GameDifficulty.CUSTOM)
                    {
                        DarkLog.Debug("Reloading gameplay settings...");
                        GameplaySettings.Reset();
                        GameplaySettings.Load();
                    }
                }

                serverRestarting = false;
                DarkLog.Normal("Starting DMPServer " + Common.PROGRAM_VERSION + ", protocol " + Common.PROTOCOL_VERSION);

                if (Settings.settingsStore.gameDifficulty == GameDifficulty.CUSTOM)
                {
                    //Generate the config file by accessing the object.
                    DarkLog.Debug("Loading gameplay settings...");
                    GameplaySettings.Load();
                }

                //Load universe
                DarkLog.Normal("Loading universe... ");
                CheckUniverse();

                DarkLog.Normal("Starting " + Settings.settingsStore.warpMode + " server on port " + Settings.settingsStore.port + "... ");

                serverRunning = true;
                Thread commandThread = new Thread(new ThreadStart(CommandHandler.ThreadMain));
                Thread clientThread  = new Thread(new ThreadStart(ClientHandler.ThreadMain));
                commandThread.Start();
                clientThread.Start();
                while (serverStarting)
                {
                    Thread.Sleep(500);
                }

                StartHTTPServer();
                DarkLog.Normal("Ready!");
                DMPPluginHandler.FireOnServerStart();
                while (serverRunning)
                {
                    //Run a garbage collection every 30 seconds.
                    if ((serverClock.ElapsedMilliseconds - lastGarbageCollect) > 30000)
                    {
                        lastGarbageCollect = serverClock.ElapsedMilliseconds;
                        GC.Collect();
                    }
                    //Run the screenshot expire function every 10 minutes
                    if ((serverClock.ElapsedMilliseconds - lastScreenshotExpiredCheck) > 600000)
                    {
                        lastScreenshotExpiredCheck = serverClock.ElapsedMilliseconds;
                        ScreenshotExpire.ExpireScreenshots();
                    }
                    //Run the log expire function every 10 minutes
                    if ((serverClock.ElapsedMilliseconds - lastLogExpiredCheck) > 600000)
                    {
                        lastLogExpiredCheck = serverClock.ElapsedMilliseconds;
                        LogExpire.ExpireLogs();
                    }
                    // Check if the day has changed, every minute
                    if ((serverClock.ElapsedMilliseconds - lastDayCheck) > 60000)
                    {
                        lastDayCheck = serverClock.ElapsedMilliseconds;
                        if (day != DateTime.Now.Day)
                        {
                            DarkLog.LogFilename = Path.Combine(DarkLog.LogFolder, "dmpserver " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".log");
                            DarkLog.WriteToLog("Continued from logfile " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".log");
                            day = DateTime.Now.Day;
                        }
                    }

                    Thread.Sleep(500);
                }
                DMPPluginHandler.FireOnServerStop();
                commandThread.Abort();
                clientThread.Join();
            }
            DarkLog.Normal("Goodbye!");
            Environment.Exit(0);
            #if !DEBUG
        }

        catch (Exception e)
        {
            DarkLog.Fatal("Error in main server thread, Exception: " + e);
            throw;
        }
            #endif
        }
        internal static void HandleMessage(ClientObject client, ClientMessage message)
        {
            //Prevent plugins from dodging SPLIT_MESSAGE. If they are modified, every split message will be broken.
            if (message.type != ClientMessageType.SPLIT_MESSAGE)
            {
                DMPPluginHandler.FireOnMessageReceived(client, message);

                if (message.handled)
                {
                    //a plugin has handled this message and requested suppression of the default DMP behavior
                    return;
                }
            }

            //Clients can only send HEARTBEATS, HANDSHAKE_REQUEST or CONNECTION_END's until they are authenticated.
            if (!client.authenticated && !(message.type == ClientMessageType.HEARTBEAT || message.type == ClientMessageType.HANDSHAKE_RESPONSE || message.type == ClientMessageType.CONNECTION_END))
            {
                Messages.ConnectionEnd.SendConnectionEnd(client, "You must authenticate before attempting to send a " + message.type.ToString() + " message");
                return;
            }

#if !DEBUG
            try
            {
#endif
            switch (message.type)
            {
            case ClientMessageType.HEARTBEAT:
                //Don't do anything for heartbeats, they just keep the connection alive
                break;

            case ClientMessageType.HANDSHAKE_RESPONSE:
                Messages.Handshake.HandleHandshakeResponse(client, message.data);
                break;

            case ClientMessageType.CHAT_MESSAGE:
                Messages.Chat.HandleChatMessage(client, message.data);
                break;

            case ClientMessageType.PLAYER_STATUS:
                Messages.PlayerStatus.HandlePlayerStatus(client, message.data);
                break;

            case ClientMessageType.PLAYER_COLOR:
                Messages.PlayerColor.HandlePlayerColor(client, message.data);
                break;

            case ClientMessageType.GROUP:
                Messages.GroupMessage.HandleMessage(client, message.data);
                break;

            case ClientMessageType.SCENARIO_DATA:
                Messages.ScenarioData.HandleScenarioModuleData(client, message.data);
                break;

            case ClientMessageType.SYNC_TIME_REQUEST:
                Messages.SyncTimeRequest.HandleSyncTimeRequest(client, message.data);
                break;

            case ClientMessageType.KERBALS_REQUEST:
                Messages.KerbalsRequest.HandleKerbalsRequest(client);
                break;

            case ClientMessageType.KERBAL_PROTO:
                Messages.KerbalProto.HandleKerbalProto(client, message.data);
                break;

            case ClientMessageType.VESSELS_REQUEST:
                Messages.VesselRequest.HandleVesselsRequest(client, message.data);
                break;

            case ClientMessageType.VESSEL_PROTO:
                Messages.VesselProto.HandleVesselProto(client, message.data);
                break;

            case ClientMessageType.VESSEL_UPDATE:
                Messages.VesselUpdate.HandleVesselUpdate(client, message.data);
                break;

            case ClientMessageType.VESSEL_REMOVE:
                Messages.VesselRemove.HandleVesselRemoval(client, message.data);
                break;

            case ClientMessageType.PERMISSION:
                Messages.PermissionMessage.HandleMessage(client, message.data);
                break;

            case ClientMessageType.CRAFT_LIBRARY:
                Messages.CraftLibrary.HandleCraftLibrary(client, message.data);
                break;

            case ClientMessageType.SCREENSHOT_LIBRARY:
                Messages.ScreenshotLibrary.HandleScreenshotLibrary(client, message.data);
                break;

            case ClientMessageType.FLAG_SYNC:
                Messages.FlagSync.HandleFlagSync(client, message.data);
                break;

            case ClientMessageType.PING_REQUEST:
                Messages.PingRequest.HandlePingRequest(client, message.data);
                break;

            case ClientMessageType.MOTD_REQUEST:
                Messages.MotdRequest.HandleMotdRequest(client);
                break;

            case ClientMessageType.WARP_CONTROL:
                Messages.WarpControl.HandleWarpControl(client, message.data);
                break;

            case ClientMessageType.LOCK_SYSTEM:
                Messages.LockSystem.HandleLockSystemMessage(client, message.data);
                break;

            case ClientMessageType.MOD_DATA:
                Messages.ModData.HandleModDataMessage(client, message.data);
                break;

            case ClientMessageType.KERBAL_REMOVE:
                Messages.VesselRemove.HandleKerbalRemoval(client, message.data);
                break;

            case ClientMessageType.SPLIT_MESSAGE:
                Messages.SplitMessage.HandleSplitMessage(client, message.data);
                break;

            case ClientMessageType.CONNECTION_END:
                Messages.ConnectionEnd.HandleConnectionEnd(client, message.data);
                break;

            case ClientMessageType.MODPACK_DATA:
                Messages.Modpack.HandleModpackMessage(client, message.data);
                break;

            default:
                DarkLog.Debug("Unhandled message type " + message.type);
                Messages.ConnectionEnd.SendConnectionEnd(client, "Unhandled message type " + message.type);
#if DEBUG
                throw new NotImplementedException("Message type not implemented");
#else
                break;
#endif
            }
#if !DEBUG
        }

        catch (Exception e)
        {
            DarkLog.Debug("Error handling " + message.type + " from " + client.playerName + ", exception: " + e);
            Messages.ConnectionEnd.SendConnectionEnd(client, "Server failed to process " + message.type + " message");
        }
#endif
        }
 private static void SendNetworkMessage(ClientObject client, ServerMessage message)
 {
     //Write the send times down in SYNC_TIME_REPLY packets
     if (message.type == ServerMessageType.SYNC_TIME_REPLY)
     {
         try
         {
             using (MessageWriter mw = new MessageWriter())
             {
                 using (MessageReader mr = new MessageReader(message.data))
                 {
                     client.bytesQueuedOut += 8;
                     //Client send time
                     mw.Write <long>(mr.Read <long>());
                     //Server receive time
                     mw.Write <long>(mr.Read <long>());
                     //Server send time
                     mw.Write <long>(DateTime.UtcNow.Ticks);
                     message.data = mw.GetMessageBytes();
                 }
             }
         }
         catch (Exception e)
         {
             DarkLog.Debug("Error rewriting SYNC_TIME packet, Exception " + e);
         }
     }
     //Continue sending
     byte[] messageBytes = Common.PrependNetworkFrame((int)message.type, message.data);
     client.lastSendTime    = Server.serverClock.ElapsedMilliseconds;
     client.bytesQueuedOut -= messageBytes.Length;
     client.bytesSent      += messageBytes.Length;
     if (client.connectionStatus == ConnectionStatus.CONNECTED)
     {
         try
         {
             client.connection.GetStream().Write(messageBytes, 0, messageBytes.Length);
         }
         catch (Exception e)
         {
             HandleDisconnectException("Send Network Message", client, e);
             return;
         }
     }
     DMPPluginHandler.FireOnMessageSent(client, message);
     if (message.type == ServerMessageType.CONNECTION_END)
     {
         using (MessageReader mr = new MessageReader(message.data))
         {
             string reason = mr.Read <string>();
             DarkLog.Normal("Disconnecting client " + client.playerName + ", sent CONNECTION_END (" + reason + ") to endpoint " + client.endpoint);
             client.disconnectClient = true;
             DisconnectClient(client);
         }
     }
     if (message.type == ServerMessageType.HANDSHAKE_REPLY)
     {
         using (MessageReader mr = new MessageReader(message.data))
         {
             int    response = mr.Read <int>();
             string reason   = mr.Read <string>();
             if (response != 0)
             {
                 DarkLog.Normal("Disconnecting client " + client.playerName + ", sent HANDSHAKE_REPLY (" + reason + ") to endpoint " + client.endpoint);
                 client.disconnectClient = true;
                 DisconnectClient(client);
             }
         }
     }
 }
        public static void ThreadMain()
        {
            try
            {
                clients = new List <ClientObject>().AsReadOnly();

                Messages.WarpControl.Reset();
                Messages.Chat.Reset();
                Messages.ScreenshotLibrary.Reset();

                SetupTCPServer();

                while (Server.serverRunning)
                {
                    //Process current clients
                    foreach (ClientObject client in clients)
                    {
                        Messages.Heartbeat.CheckHeartBeat(client);
                    }
                    ModpackSystem.fetch.SendFilesToClients();
                    //Check timers
                    NukeKSC.CheckTimer();
                    Dekessler.CheckTimer();
                    Messages.WarpControl.CheckTimer();
                    //Run plugin update
                    DMPPluginHandler.FireOnUpdate();
                    Thread.Sleep(10);
                }
            }
            catch (Exception e)
            {
                DarkLog.Error("Fatal error thrown, exception: " + e);
                Server.ShutDown("Crashed!");
            }
            try
            {
                long disconnectTime = DateTime.UtcNow.Ticks;
                bool sendingHighPriotityMessages = true;
                while (sendingHighPriotityMessages)
                {
                    if ((DateTime.UtcNow.Ticks - disconnectTime) > 50000000)
                    {
                        DarkLog.Debug("Shutting down with " + Server.playerCount + " players, " + clients.Count + " connected clients");
                        break;
                    }
                    sendingHighPriotityMessages = false;
                    foreach (ClientObject client in clients)
                    {
                        if (client.authenticated && (client.sendMessageQueueHigh.Count > 0))
                        {
                            sendingHighPriotityMessages = true;
                        }
                    }
                    Thread.Sleep(10);
                }
                ShutdownTCPServer();
            }
            catch (Exception e)
            {
                DarkLog.Fatal("Fatal error thrown during shutdown, exception: " + e);
                throw;
            }
        }
Exemple #10
0
        public static void Main()
        {
            try
            {
                //Start the server clock
                serverClock = new Stopwatch();
                serverClock.Start();

                //Set the last player activity time to server start
                lastPlayerActivity = serverClock.ElapsedMilliseconds;

                //Periodic garbage collection
                long lastGarbageCollect = 0;

                //Periodic screenshot check
                long lastScreenshotExpiredCheck = 0;

                //Set universe directory and modfile path
                universeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Universe");
                modFile           = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DMPModControl.txt");

                CommandHandler commandHandler = new CommandHandler();

                //Register the server commands
                commandHandler.RegisterCommand("exit", Server.ShutDown, "Shuts down the server");
                commandHandler.RegisterCommand("quit", Server.ShutDown, "Shuts down the server");
                commandHandler.RegisterCommand("shutdown", Server.ShutDown, "Shuts down the server");
                commandHandler.RegisterCommand("restart", Server.Restart, "Restarts the server");
                commandHandler.RegisterCommand("kick", x => WorldManager.Instance.KickPlayer(x), "Kicks a player from the server");
                commandHandler.RegisterCommand("ban", x => WorldManager.Instance.BanPlayer(x), "Bans a player from the server");
                commandHandler.RegisterCommand("banip", x => WorldManager.Instance.BanIP(x), "Bans an IP Address from the server");
                commandHandler.RegisterCommand("bankey", x => WorldManager.Instance.BanPublicKey(x), "Bans a Guid from the server");
                commandHandler.RegisterCommand("pm", x => WorldManager.Instance.PMCommand(x), "Sends a message to a player");
                commandHandler.RegisterCommand("admin", x => WorldManager.Instance.AdminCommand(x), "Sets a player as admin/removes admin from the player");
                commandHandler.RegisterCommand("whitelist", x => WorldManager.Instance.WhitelistCommand(x), "Change the server whitelist");
                //Register the ctrl+c event
                Console.CancelKeyPress += new ConsoleCancelEventHandler(CatchExit);
                serverStarting          = true;

                //Fix kerbals from 0.23.5 to 0.24 (Now indexed by string, thanks Squad!
                BackwardsCompatibility.FixKerbals();

                //Remove player tokens
                BackwardsCompatibility.RemoveOldPlayerTokens();

                //Load plugins
                DMPPluginHandler.LoadPlugins();

                Console.Title = "DMPServer " + Common.PROGRAM_VERSION + ", protocol " + Common.PROTOCOL_VERSION;

                while (serverStarting || serverRestarting)
                {
                    serverRestarting = false;
                    DarkLog.Normal("Starting DMPServer " + Common.PROGRAM_VERSION + ", protocol " + Common.PROTOCOL_VERSION);

                    //Load settings
                    DarkLog.Normal("Loading universe... ");
                    CheckUniverse();
                    DarkLog.Normal("Done!");

                    DarkLog.Normal("Loading settings... ");
                    Settings.Load();
                    DarkLog.Normal("Done!");

                    DarkLog.Normal("Starting " + Settings.settingsStore.warpMode + " server on port " + Settings.settingsStore.port + "... ");



                    serverRunning = true;
                    DarkLog.Normal("Done!");

                    StartHTTPServer();
                    DarkLog.Normal("Done!");
                    DMPPluginHandler.FireOnServerStart();
                    while (serverRunning)
                    {
                        WorldManager.Instance.Update();
                        commandHandler.Run();

                        //Run a garbage collection every 2 minutes.
                        if ((serverClock.ElapsedMilliseconds - lastGarbageCollect) > 12000)
                        {
                            lastGarbageCollect = serverClock.ElapsedMilliseconds;
                            GC.Collect();
                        }
                        //Run the screenshot expire function every 10 minutes
                        if ((serverClock.ElapsedMilliseconds - lastScreenshotExpiredCheck) > 600000)
                        {
                            lastScreenshotExpiredCheck = serverClock.ElapsedMilliseconds;
                            ScreenshotExpire.ExpireCache();
                        }
                        Thread.Sleep(10);
                    }
                    DMPPluginHandler.FireOnServerStop();
                }
                DarkLog.Normal("Goodbye!");
                Environment.Exit(0);
            }
            catch (Exception e)
            {
                DarkLog.Fatal("Error in main server thread, Exception: " + e);
                throw;
            }
        }