Пример #1
0
        public void Run()
        {
            //ByteRecycler must be allowed to allocate the size of the biggest message
            ByteRecycler.AddPoolSize(128 * 1024 * 1024);
            NetworkHandler <StateObject> handler = new NetworkHandler <StateObject>(false);

            handler.RegisterConnectCallback(Connected);
            handler.RegisterDisconnectCallback(Disconnected);
            handler.RegisterCallback(0, GotMessage);
            handler.RegisterCallback(1, RelayReliable);
            DarkNetwork <StateObject> dn = new DarkNetwork <StateObject>();

            dn.SetupServer(new IPEndPoint(IPAddress.IPv6Any, 12345), handler);
            int messageID = 0;

            while (true)
            {
                NetworkMessage nm        = NetworkMessage.Create(0, 2048, NetworkMessageType.UNORDERED_UNRELIABLE);
                byte[]         sendBytes = Encoding.UTF8.GetBytes("Message " + messageID++);
                Array.Copy(sendBytes, 0, nm.data.data, 0, sendBytes.Length);
                nm.data.size = sendBytes.Length;
                handler.SendMessageToAll(nm);
                //Recycler<NetworkMessage>.GarbageCollect(500, 1000);
                //ByteRecycler.GarbageCollect(2048, 500, 1000);
                //ByteRecycler.GarbageCollect(128 * 1024 * 1024, 2, 4);
                //PrintRecyclerStats();
                Thread.Sleep(1000);
            }
        }
Пример #2
0
 public void LoadScenarioDataIntoGame()
 {
     lock (scenarioQueue)
     {
         while (scenarioQueue.Count > 0)
         {
             ScenarioEntry scenarioEntry = scenarioQueue.Dequeue();
             if (scenarioEntry.scenarioName == "ProgressTracking")
             {
                 CreateMissingKerbalsInProgressTrackingSoTheGameDoesntBugOut(scenarioEntry.scenarioNode);
             }
             CheckForBlankSceneSoTheGameDoesntBugOut(scenarioEntry);
             ProtoScenarioModule psm = new ProtoScenarioModule(scenarioEntry.scenarioNode);
             if (psm != null)
             {
                 if (IsScenarioModuleAllowed(psm.moduleName))
                 {
                     DarkLog.Debug("Loading " + psm.moduleName + " scenario data");
                     HighLogic.CurrentGame.scenarios.Add(psm);
                     ByteArray scenarioHashBytes = configNodeSerializer.Serialize(scenarioEntry.scenarioNode);
                     checkData[scenarioEntry.scenarioName] = Common.CalculateSHA256Hash(scenarioHashBytes);
                     ByteRecycler.ReleaseObject(scenarioHashBytes);
                 }
                 else
                 {
                     DarkLog.Debug("Skipping " + psm.moduleName + " scenario data in " + dmpGame.gameMode + " mode");
                 }
             }
         }
     }
 }
Пример #3
0
 public void QueueWarpMessage(ByteArray messageData)
 {
     lock (newWarpMessages)
     {
         ByteArray queueByteArray = ByteRecycler.GetObject(messageData.Length);
         Array.Copy(messageData.data, 0, queueByteArray.data, 0, messageData.Length);
         newWarpMessages.Enqueue(queueByteArray);
     }
 }
Пример #4
0
 public void QueueMessage(ByteArray data)
 {
     lock (messageQueue)
     {
         ByteArray queueByteArray = ByteRecycler.GetObject(data.Length);
         Array.Copy(data.data, 0, queueByteArray.data, 0, data.Length);
         messageQueue.Enqueue(queueByteArray);
     }
 }
Пример #5
0
 public void HandleModpackMessage(ByteArray messageData)
 {
     lock (messageQueue)
     {
         ByteArray queueByteArray = ByteRecycler.GetObject(messageData.Length);
         Array.Copy(messageData.data, 0, queueByteArray.data, 0, messageData.Length);
         messageQueue.Enqueue(queueByteArray);
     }
 }
 /// <summary>
 /// Queues to cache. This method is non-blocking, using SaveToCache for a blocking method.
 /// </summary>
 /// <param name="fileData">File data.</param>
 public void QueueToCache(ByteArray fileData)
 {
     lock (incomingQueue)
     {
         ByteArray incomingBytes = ByteRecycler.GetObject(fileData.Length);
         Array.Copy(fileData.data, 0, incomingBytes.data, 0, fileData.Length);
         incomingQueue.Enqueue(incomingBytes);
     }
     incomingEvent.Set();
 }
Пример #7
0
        public object ReadByteArrayFromStream(Stream inputStream)
        {
            inputStream.Read(intReverser, 0, 4);
            ReverseIfLittleEndian(intReverser);
            int       length      = BitConverter.ToInt32(intReverser, 0);
            ByteArray returnBytes = ByteRecycler.GetObject(length);

            inputStream.Read(returnBytes.data, 0, length);
            return(returnBytes);
        }
Пример #8
0
 public void ProcessWarpMessages()
 {
     lock (newWarpMessages)
     {
         while (newWarpMessages.Count > 0)
         {
             ByteArray queueByteArray = newWarpMessages.Dequeue();
             HandleWarpMessage(queueByteArray.data);
             ByteRecycler.ReleaseObject(queueByteArray);
         }
     }
 }
Пример #9
0
 private void ProcessMessages()
 {
     lock (messageQueue)
     {
         while (messageQueue.Count > 0)
         {
             ByteArray queueByteArray = messageQueue.Dequeue();
             HandleMessage(queueByteArray.data);
             ByteRecycler.ReleaseObject(queueByteArray);
         }
     }
 }
Пример #10
0
        private bool DidScenarioChange(ScenarioEntry scenarioEntry)
        {
            string    previousScenarioHash = null;
            ByteArray scenarioBytes        = configNodeSerializer.Serialize(scenarioEntry.scenarioNode);
            string    currentScenarioHash  = Common.CalculateSHA256Hash(scenarioBytes);

            ByteRecycler.ReleaseObject(scenarioBytes);
            if (checkData.TryGetValue(scenarioEntry.scenarioName, out previousScenarioHash))
            {
                return(previousScenarioHash != currentScenarioHash);
            }
            return(true);
        }
Пример #11
0
        private void PrintRecyclerStats()
        {
            Console.WriteLine();
            Console.WriteLine("Recycler statistics: ");
            int rFree = Recycler <NetworkMessage> .GetPoolFreeCount();

            int rTotal = Recycler <NetworkMessage> .GetPoolCount();

            Console.WriteLine("NetworkMessage: " + rFree + "/" + rTotal);
            rFree  = ByteRecycler.GetPoolFreeCount(2048);
            rTotal = ByteRecycler.GetPoolCount(2048);
            Console.WriteLine("ByteArray 2048: " + rFree + "/" + rTotal);
            rFree  = ByteRecycler.GetPoolFreeCount(128 * 1024 * 1024);
            rTotal = ByteRecycler.GetPoolCount(128 * 1024 * 1024);
            Console.WriteLine("ByteArray 128M: " + rFree + "/" + rTotal);
            Console.WriteLine("Total memory: " + GC.GetTotalMemory(false) / 1024);
        }
 private void ProcessingThreadMain()
 {
     while (true)
     {
         if (incomingQueue.Count == 0)
         {
             incomingEvent.WaitOne(500);
         }
         else
         {
             ByteArray incomingBytes;
             lock (incomingQueue)
             {
                 incomingBytes = incomingQueue.Dequeue();
             }
             SaveToCache(incomingBytes);
             ByteRecycler.ReleaseObject(incomingBytes);
         }
     }
 }
Пример #13
0
        public void Run()
        {
            r.NextBytes(randomBytes);
            //ByteRecycler must be allowed to allocate the size of the biggest message
            ByteRecycler.AddPoolSize(128 * 1024 * 1024);
            NetworkHandler <StateObject> handler = new NetworkHandler <StateObject>(false);

            handler.RegisterConnectCallback(Connected);
            handler.RegisterDisconnectCallback(Disconnected);
            handler.RegisterCallback(0, GotMessage);
            handler.RegisterCallback(1, ReliableReceive);
            DarkNetwork <StateObject> dn = new DarkNetwork <StateObject>();
            IPAddress netAddr            = IPAddress.Parse("2403:5800:9100:5b00:76da:38ff:fea3:9dbe");

            dn.SetupClient(new IPEndPoint(netAddr, 12345), handler);
            Thread.Sleep(1000);
            NetworkMessage nmbig = NetworkMessage.Create(1, randomBytes.Length, NetworkMessageType.ORDERED_RELIABLE);

            Array.Copy(randomBytes, 0, nmbig.data.data, 0, randomBytes.Length);
            handler.SendMessage(nmbig);
            int messageID = 0;

            while (running)
            {
                NetworkMessage nm        = NetworkMessage.Create(0, 2048, NetworkMessageType.ORDERED_UNRELIABLE);
                byte[]         sendBytes = Encoding.UTF8.GetBytes("Message " + messageID++);
                Array.Copy(sendBytes, 0, nm.data.data, 0, sendBytes.Length);
                nm.data.size = sendBytes.Length;
                handler.SendMessage(nm);
                //Recycler<NetworkMessage>.GarbageCollect(500, 1000);
                //ByteRecycler.GarbageCollect(2048, 500, 1000);
                //ByteRecycler.GarbageCollect(128 * 1024 * 1024, 2, 4);
                //PrintRecyclerStats();
                Thread.Sleep(1000);
            }
            dn.Shutdown();
        }
Пример #14
0
        public void Update()
        {
            if (playback)
            {
                DisplayUpdateVesselOffset();
                if (Planetarium.GetUniversalTime() > (lastTime))
                {
                    playback = false;
                    ScreenMessages.RemoveMessage(screenMessage);
                    screenMessage = null;
                }
                else
                {
                    int timeLeft = (int)(lastTime - Planetarium.GetUniversalTime());
                    ScreenMessages.RemoveMessage(screenMessage);
                    screenMessage = ScreenMessages.PostScreenMessage("Playback time left: " + timeLeft + " / " + (int)(lastTime - firstTime) + " seconds", float.MaxValue, ScreenMessageStyle.UPPER_CENTER);
                }
            }

            if (active)
            {
                VesselUpdate vu = Recycler <VesselUpdate> .GetObject();

                vu.SetVesselWorker(vesselWorker);
                vu.CopyFromVessel(FlightGlobals.fetch.activeVessel);
                ClientMessage updateBytes = networkWorker.GetVesselUpdateMessage(vu);
                byte[]        lengthBytes = BitConverter.GetBytes(updateBytes.data.Length);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(lengthBytes);
                }
                recordingVector.Write(lengthBytes, 0, lengthBytes.Length);
                recordingVector.Write(updateBytes.data.data, 0, updateBytes.data.Length);
                ByteRecycler.ReleaseObject(updateBytes.data);
                Recycler <VesselUpdate> .ReleaseObject(vu);
            }
        }
        public ByteArray Serialize(ConfigNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            ByteArray retVal;
            int       retValSize = 0;

            //Call the insides of what ConfigNode would have called if we said Save(filename)
            using (MemoryStream stream = new MemoryStream(configNodeBuffer))
            {
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    //we late bind to the instance by passing the instance as the first argument
                    WriteNodeThunk(node, writer);
                    retValSize = (int)stream.Position;
                }
            }
            retVal = ByteRecycler.GetObject(retValSize);
            Array.Copy(configNodeBuffer, 0, retVal.data, 0, retValSize);
            return(retVal);
        }
Пример #16
0
        public void LoadScenarioData(ScenarioEntry entry)
        {
            if (!IsScenarioModuleAllowed(entry.scenarioName))
            {
                DarkLog.Debug("Skipped '" + entry.scenarioName + "' scenario data  in " + dmpGame.gameMode + " mode");
                return;
            }
            //Load data from DMP
            if (entry.scenarioNode == null)
            {
                DarkLog.Debug(entry.scenarioName + " scenario data failed to create a ConfigNode!");
                ScreenMessages.PostScreenMessage("Scenario " + entry.scenarioName + " failed to load, blocking scenario uploads.", 10f, ScreenMessageStyle.UPPER_CENTER);
                blockScenarioDataSends = true;
                return;
            }

            //Load data into game
            if (DidScenarioChange(entry))
            {
                bool      loaded        = false;
                ByteArray scenarioBytes = configNodeSerializer.Serialize(entry.scenarioNode);
                checkData[entry.scenarioName] = Common.CalculateSHA256Hash(scenarioBytes);
                ByteRecycler.ReleaseObject(scenarioBytes);
                foreach (ProtoScenarioModule psm in HighLogic.CurrentGame.scenarios)
                {
                    if (psm.moduleName == entry.scenarioName)
                    {
                        DarkLog.Debug("Loading existing " + entry.scenarioName + " scenario module");
                        try
                        {
                            if (psm.moduleRef == null)
                            {
                                DarkLog.Debug("Fixing null scenario module!");
                                psm.moduleRef = new ScenarioModule();
                            }
                            bool skipLoad = false;
                            if (beforeCallback.ContainsKey(psm.moduleName))
                            {
                                skipLoad = beforeCallback[psm.moduleName](entry.scenarioNode);
                            }
                            if (!skipLoad)
                            {
                                psm.moduleRef.Load(entry.scenarioNode);
                            }
                            if (afterCallback.ContainsKey(psm.moduleName))
                            {
                                afterCallback[psm.moduleName](entry.scenarioNode);
                            }
                        }
                        catch (Exception e)
                        {
                            DarkLog.Debug("Error loading " + entry.scenarioName + " scenario module, Exception: " + e);
                            blockScenarioDataSends = true;
                        }
                        loaded = true;
                    }
                }
                if (!loaded)
                {
                    DarkLog.Debug("Loading new " + entry.scenarioName + " scenario module");
                    LoadNewScenarioData(entry.scenarioNode);
                }
            }
        }
Пример #17
0
        public void Update()
        {
            profiler.Report("KSP", kspTime, kspMemory);
            DarkLog.Update();
            ByteRecycler.GarbageCollect(50, 100);
            Recycler <VesselUpdate> .GarbageCollect(50, 100);

            long profilerStartTime   = profiler.GetCurrentTime;
            long profilerStartMemory = profiler.GetCurrentMemory;

            lastClockTicks           = DateTime.UtcNow.Ticks;
            lastRealTimeSinceStartup = Time.realtimeSinceStartup;
            if (warnDuplicateInstall && HighLogic.LoadedScene == GameScenes.MAINMENU)
            {
                warnDuplicateInstall = false;
                string message = "Please remove the duplicate install of DarkMultiPlayer.";
                PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "InstallChecker", "Incorrect Install Detected", message, "OK", true, HighLogic.UISkin);
            }
            if (modDisabled)
            {
                return;
            }
            try
            {
                if (HighLogic.LoadedScene == GameScenes.MAINMENU)
                {
                    if (!dmpSaveChecked)
                    {
                        dmpSaveChecked = true;
                        SetupBlankGameIfNeeded();
                    }
                }

                if (HighLogic.LoadedScene == GameScenes.SPACECENTER && PSystemSetup.Instance != null && Time.timeSinceLevelLoad > 1f)
                {
                    if (PSystemSetup.Instance.SpaceCenterFacilities.Length != facilitiesAdded)
                    {
                        facilitiesAdded = PSystemSetup.Instance.SpaceCenterFacilities.Length;
                        foreach (PSystemSetup.SpaceCenterFacility spaceCenterFacility in PSystemSetup.Instance.SpaceCenterFacilities)
                        {
                            foreach (PSystemSetup.SpaceCenterFacility.SpawnPoint spawnPoint in spaceCenterFacility.spawnPoints)
                            {
                                if (spawnPoint.latitude != 0 && spawnPoint.longitude != 0 && spawnPoint.altitude != 0)
                                {
                                    DarkLog.Debug("Adding facility spawn point: " + spaceCenterFacility.name + ":" + spawnPoint.name);
                                    SafetyBubble.RegisterLocation(spawnPoint.latitude, spawnPoint.longitude, spawnPoint.altitude, spaceCenterFacility.hostBody.name);
                                    DarkLog.Debug("LLA: [" + spawnPoint.latitude + ", " + spawnPoint.longitude + ", " + spawnPoint.altitude + "]");
                                }
                            }
                        }
                    }
                    if (PSystemSetup.Instance.LaunchSites.Count != modSitesAdded)
                    {
                        modSitesAdded = PSystemSetup.Instance.LaunchSites.Count;
                        foreach (LaunchSite launchSite in PSystemSetup.Instance.LaunchSites)
                        {
                            foreach (LaunchSite.SpawnPoint spawnPoint in launchSite.spawnPoints)
                            {
                                if (spawnPoint.latitude != 0 && spawnPoint.longitude != 0 && spawnPoint.altitude != 0)
                                {
                                    DarkLog.Debug("Adding mod spawn point: " + launchSite.name + ":" + spawnPoint.name);
                                    SafetyBubble.RegisterLocation(spawnPoint.latitude, spawnPoint.longitude, spawnPoint.altitude, launchSite.Body.name);
                                    DarkLog.Debug("LLA: [" + spawnPoint.latitude + ", " + spawnPoint.longitude + ", " + spawnPoint.altitude + "]");
                                }
                            }
                        }
                    }
                    if (PSystemSetup.Instance.StockLaunchSites.Length != stockSitesAdded)
                    {
                        stockSitesAdded = PSystemSetup.Instance.StockLaunchSites.Length;
                        foreach (LaunchSite launchSite in PSystemSetup.Instance.StockLaunchSites)
                        {
                            foreach (LaunchSite.SpawnPoint spawnPoint in launchSite.spawnPoints)
                            {
                                if (spawnPoint.latitude != 0 && spawnPoint.longitude != 0 && spawnPoint.altitude != 0)
                                {
                                    DarkLog.Debug("Adding stock spawn point: " + launchSite.name + ":" + spawnPoint.name);
                                    SafetyBubble.RegisterLocation(spawnPoint.latitude, spawnPoint.longitude, spawnPoint.altitude, launchSite.Body.name);
                                    DarkLog.Debug("LLA: [" + spawnPoint.latitude + ", " + spawnPoint.longitude + ", " + spawnPoint.altitude + "]");
                                }
                            }
                        }
                    }
                }



                //Handle GUI events

                if (!connectionWindow.renameEventHandled)
                {
                    dmpSettings.SaveSettings();
                    connectionWindow.renameEventHandled = true;
                }
                if (!connectionWindow.addEventHandled)
                {
                    dmpSettings.servers.Add(connectionWindow.addEntry);
                    connectionWindow.addEntry = null;
                    dmpSettings.SaveSettings();
                    connectionWindow.addingServer    = false;
                    connectionWindow.addEventHandled = true;
                }
                if (!connectionWindow.editEventHandled)
                {
                    dmpSettings.servers[connectionWindow.selected].name    = connectionWindow.editEntry.name;
                    dmpSettings.servers[connectionWindow.selected].address = connectionWindow.editEntry.address;
                    dmpSettings.servers[connectionWindow.selected].port    = connectionWindow.editEntry.port;
                    connectionWindow.editEntry = null;
                    dmpSettings.SaveSettings();
                    connectionWindow.addingServer     = false;
                    connectionWindow.editEventHandled = true;
                }
                if (!connectionWindow.removeEventHandled)
                {
                    dmpSettings.servers.RemoveAt(connectionWindow.selected);
                    connectionWindow.selected = -1;
                    dmpSettings.SaveSettings();
                    connectionWindow.removeEventHandled = true;
                }
                if (!connectionWindow.connectEventHandled)
                {
                    connectionWindow.connectEventHandled = true;
                    ConnectToServer(dmpSettings.servers[connectionWindow.selected].address, dmpSettings.servers[connectionWindow.selected].port);
                }
                if (commandLineConnect != null && HighLogic.LoadedScene == GameScenes.MAINMENU && Time.timeSinceLevelLoad > 1f)
                {
                    ConnectToServer(commandLineConnect.address, commandLineConnect.port);
                    commandLineConnect = null;
                }

                if (!connectionWindow.disconnectEventHandled)
                {
                    connectionWindow.disconnectEventHandled = true;
                    if (dmpGame != null)
                    {
                        if (dmpGame.networkWorker.state == ClientState.CONNECTING)
                        {
                            dmpGame.networkWorker.Disconnect("Cancelled connection to server");
                        }
                        else
                        {
                            dmpGame.networkWorker.SendDisconnect("Quit during initial sync");
                        }
                        dmpGame.Stop();
                        dmpGame = null;
                    }
                }

                connectionWindow.Update();
                serverListConnection.Update();
                serversWindow.Update();
                modWindow.Update();
                optionsWindow.Update();
                universeConverterWindow.Update();
                profiler.Update();
                dmpModInterface.Update();

                if (dmpGame != null)
                {
                    foreach (NamedAction updateAction in dmpGame.updateEvent)
                    {
#if !DEBUG
                        try
                        {
#endif
                        long profilerUpdateStartTime   = profiler.GetCurrentTime;
                        long profilerUpdateStartMemory = profiler.GetCurrentMemory;
                        updateAction.action();
                        profiler.Report(updateAction.name, profilerUpdateStartTime, profilerUpdateStartMemory);
#if !DEBUG
                    }
                    catch (Exception e)
                    {
                        DarkLog.Debug("Threw in UpdateEvent, exception: " + e);
                        if (dmpGame.networkWorker.state != ClientState.RUNNING)
                        {
                            if (dmpGame.networkWorker.state != ClientState.DISCONNECTED)
                            {
                                dmpGame.networkWorker.SendDisconnect("Unhandled error while syncing!");
                            }
                            else
                            {
                                dmpGame.networkWorker.Disconnect("Unhandled error while syncing!");
                            }
                        }
                    }
#endif
                    }
                }
                //Force quit
                if (dmpGame != null && dmpGame.forceQuit)
                {
                    dmpGame.forceQuit = false;
                    dmpGame.Stop();
                    dmpGame = null;
                    StopGame();
                }


                if (displayDisconnectMessage)
                {
                    if (HighLogic.LoadedScene != GameScenes.MAINMENU)
                    {
                        if ((Client.realtimeSinceStartup - lastDisconnectMessageCheck) > 1f)
                        {
                            lastDisconnectMessageCheck = Client.realtimeSinceStartup;
                            if (disconnectMessage != null)
                            {
                                disconnectMessage.duration = 0;
                            }
                            disconnectMessage = ScreenMessages.PostScreenMessage("You have been disconnected!", 2f, ScreenMessageStyle.UPPER_CENTER);
                        }
                    }
                    else
                    {
                        displayDisconnectMessage = false;
                    }
                }

                //Normal quit
                if (dmpGame != null && dmpGame.running)
                {
                    if (!dmpGame.playerStatusWindow.disconnectEventHandled)
                    {
                        dmpGame.playerStatusWindow.disconnectEventHandled = true;
                        dmpGame.forceQuit = true;
                        dmpGame.scenarioWorker.SendScenarioModules(true); // Send scenario modules before disconnecting
                        dmpGame.networkWorker.SendDisconnect("Quit");
                    }

                    if (dmpGame.screenshotWorker.uploadScreenshot)
                    {
                        dmpGame.screenshotWorker.uploadScreenshot = false;
                        StartCoroutine(UploadScreenshot());
                    }

                    if (HighLogic.CurrentGame.flagURL != dmpSettings.selectedFlag)
                    {
                        DarkLog.Debug("Saving selected flag");
                        dmpSettings.selectedFlag = HighLogic.CurrentGame.flagURL;
                        dmpSettings.SaveSettings();
                        dmpGame.flagSyncer.flagChangeEvent = true;
                    }

                    // save every GeeASL from each body in FlightGlobals
                    if (HighLogic.LoadedScene == GameScenes.FLIGHT && bodiesGees.Count == 0)
                    {
                        foreach (CelestialBody body in FlightGlobals.fetch.bodies)
                        {
                            bodiesGees.Add(body, body.GeeASL);
                        }
                    }

                    //handle use of cheats
                    if (!dmpGame.serverAllowCheats)
                    {
                        CheatOptions.InfinitePropellant             = false;
                        CheatOptions.NoCrashDamage                  = false;
                        CheatOptions.IgnoreAgencyMindsetOnContracts = false;
                        CheatOptions.IgnoreMaxTemperature           = false;
                        CheatOptions.InfiniteElectricity            = false;
                        CheatOptions.NoCrashDamage                  = false;
                        CheatOptions.UnbreakableJoints              = false;

                        foreach (KeyValuePair <CelestialBody, double> gravityEntry in bodiesGees)
                        {
                            gravityEntry.Key.GeeASL = gravityEntry.Value;
                        }
                    }

                    if (HighLogic.LoadedScene == GameScenes.FLIGHT && FlightGlobals.ready)
                    {
                        HighLogic.CurrentGame.Parameters.Flight.CanLeaveToSpaceCenter = !dmpGame.vesselWorker.isSpectating && dmpSettings.revertEnabled || (PauseMenu.canSaveAndExit == ClearToSaveStatus.CLEAR);
                    }
                    else
                    {
                        HighLogic.CurrentGame.Parameters.Flight.CanLeaveToSpaceCenter = true;
                    }

                    if (HighLogic.LoadedScene == GameScenes.MAINMENU)
                    {
                        dmpGame.networkWorker.SendDisconnect("Quit to main menu");
                        dmpGame.Stop();
                        dmpGame = null;
                    }
                }

                if (dmpGame != null && dmpGame.startGame)
                {
                    dmpGame.startGame = false;
                    StartGame();
                }
            }
            catch (Exception e)
            {
                if (dmpGame != null)
                {
                    DarkLog.Debug("Threw in Update, state " + dmpGame.networkWorker.state.ToString() + ", exception: " + e);
                    if (dmpGame.networkWorker.state != ClientState.RUNNING)
                    {
                        if (dmpGame.networkWorker.state != ClientState.DISCONNECTED)
                        {
                            dmpGame.networkWorker.SendDisconnect("Unhandled error while syncing!");
                        }
                        else
                        {
                            dmpGame.networkWorker.Disconnect("Unhandled error while syncing!");
                        }
                    }
                }
                else
                {
                    DarkLog.Debug("Threw in Update, state NO_NETWORKWORKER, exception: " + e);
                }
            }
            DarkLog.Update();
            profiler.Report("Update", profilerStartTime, profilerStartMemory);
            kspTime   = profiler.GetCurrentTime;
            kspMemory = profiler.GetCurrentMemory;
        }
Пример #18
0
        public void Start()
        {
            //Set buffered UDPMesh
            UDPMeshLib.UdpMeshCommon.USE_BUFFERS = true;
            //Set pool sizes for ByteRecycler
            ByteRecycler.AddPoolSize(SMALL_MESSAGE_SIZE);
            ByteRecycler.AddPoolSize(MEDIUM_MESSAGE_SIZE);
            ByteRecycler.AddPoolSize(LARGE_MESSAGE_SIZE);
            MessageWriter.RegisterType <ByteArray>(WriteByteArrayToStream);
            MessageReader.RegisterType <ByteArray>(ReadByteArrayFromStream);

            //Prevent loads if multiple copies of DMP are installed. KSP will instantate us twice.
            if (dmpClient != null)
            {
                warnDuplicateInstall = true;
                return;
            }

            if (!CompatibilityChecker.IsCompatible() || !InstallChecker.IsCorrectlyInstalled())
            {
                modDisabled = true;
                enabled     = false;
                return;
            }

            TimingManager.FixedUpdateAdd(TimingManager.TimingStage.BetterLateThanNever, TimingManagerFixedUpdate);
            dmpDir      = Path.Combine(Path.Combine(Path.Combine(KSPUtil.ApplicationRootPath, "GameData"), "DarkMultiPlayer"), "Plugins");
            dmpDataDir  = Path.Combine(dmpDir, "Data");
            gameDataDir = Path.Combine(KSPUtil.ApplicationRootPath, "GameData");
            kspRootPath = KSPUtil.ApplicationRootPath;

            //Fix DarkLog time/thread marker in the log during init.
            DarkLog.SetMainThread();
            lastClockTicks           = DateTime.UtcNow.Ticks;
            lastRealTimeSinceStartup = 0f;

            dmpClient = this;
            profiler  = new Profiler();
            kspTime   = profiler.GetCurrentTime;
            kspMemory = profiler.GetCurrentMemory;

            dmpSettings       = new Settings();
            toolbarSupport    = new ToolbarSupport(dmpSettings);
            universeSyncCache = new UniverseSyncCache(dmpSettings);
            modWindow         = new ModWindow();
            modWorker         = new ModWorker(modWindow);
            modWindow.SetDependenices(modWorker);
            universeConverter          = new UniverseConverter(dmpSettings);
            universeConverterWindow    = new UniverseConverterWindow(universeConverter);
            serverListDisclaimerWindow = new ServerListDisclaimerWindow(dmpSettings);
            optionsWindow        = new OptionsWindow(dmpSettings, universeSyncCache, modWorker, universeConverterWindow, toolbarSupport, serverListDisclaimerWindow);
            serverListConnection = new ServerListConnection(dmpSettings);
            serversWindow        = new ServersWindow(dmpSettings, optionsWindow, serverListConnection);
            serverListConnection.SetDependancy(serversWindow);
            connectionWindow = new ConnectionWindow(dmpSettings, optionsWindow, serversWindow, serverListDisclaimerWindow);
            disclaimerWindow = new DisclaimerWindow(dmpSettings);
            dmpModInterface  = new DMPModInterface();
            //SafetyBubble.RegisterDefaultLocations();


            if (dmpSettings.disclaimerAccepted != 1)
            {
                modDisabled = true;
                disclaimerWindow.SpawnDialog();
            }

            Application.wantsToQuit += WantsToQuit;
            DontDestroyOnLoad(this);

            // Prevents symlink warning for development.
            SetupDirectoriesIfNeeded();

            // UniverseSyncCache needs to run expiry here
            universeSyncCache.ExpireCache();

            GameEvents.onHideUI.Add(() =>
            {
                showGUI = false;
            });
            GameEvents.onShowUI.Add(() =>
            {
                showGUI = true;
            });

            HandleCommandLineArgs();
            DarkLog.Debug("DarkMultiPlayer " + Common.PROGRAM_VERSION + ", protocol " + Common.PROTOCOL_VERSION + " Initialized!");
        }
Пример #19
0
        public void SendScenarioModules(bool highPriority)
        {
            lastScenarioSendTime = Client.realtimeSinceStartup;
            List <string>    scenarioName = new List <string>();
            List <ByteArray> scenarioData = new List <ByteArray>();

            foreach (ScenarioModule sm in ScenarioRunner.GetLoadedModules())
            {
                string scenarioType = sm.GetType().Name;
                if (!IsScenarioModuleAllowed(scenarioType))
                {
                    continue;
                }
                try
                {
                    ConfigNode scenarioNode = new ConfigNode();
                    sm.Save(scenarioNode);

                    ByteArray scenarioBytes = configNodeSerializer.Serialize(scenarioNode);
                    string    scenarioHash  = Common.CalculateSHA256Hash(scenarioBytes);
                    if (scenarioBytes.Length == 0)
                    {
                        DarkLog.Debug("Error writing scenario data for " + scenarioType);
                        ByteRecycler.ReleaseObject(scenarioBytes);
                        continue;
                    }
                    if (checkData.ContainsKey(scenarioType) ? (checkData[scenarioType] == scenarioHash) : false)
                    {
                        //Data is the same since last time - Skip it.
                        ByteRecycler.ReleaseObject(scenarioBytes);
                        continue;
                    }
                    else
                    {
                        checkData[scenarioType] = scenarioHash;
                    }
                    scenarioName.Add(scenarioType);
                    scenarioData.Add(scenarioBytes);
                }
                catch (Exception e)
                {
                    string fullName = sm.GetType().FullName;
                    if (!warnedModules.Contains(fullName))
                    {
                        DarkLog.Debug("Unable to save module data from " + fullName + ", skipping upload of this module. Exception: " + e);
                        warnedModules.Add(fullName);
                        if (!fullName.Contains("Expansions.Serenity.DeployedScience"))
                        {
                            ScreenMessages.PostScreenMessage("DMP was unable to save " + fullName + ", this module data will be lost.", 30f, ScreenMessageStyle.UPPER_CENTER);
                        }
                    }
                }
            }

            if (scenarioName.Count > 0)
            {
                if (highPriority)
                {
                    networkWorker.SendScenarioModuleDataHighPriority(scenarioName.ToArray(), scenarioData.ToArray());
                }
                else
                {
                    networkWorker.SendScenarioModuleData(scenarioName.ToArray(), scenarioData.ToArray());
                }
            }
        }
Пример #20
0
        private void Update()
        {
            safeDisplay = optionsWindow.showDebugWindow;
            if (safeDisplay)
            {
                if (((Client.realtimeSinceStartup - lastUpdateTime) > DISPLAY_UPDATE_INTERVAL) || displayFast)
                {
                    lastUpdateTime = Client.realtimeSinceStartup;
                    //Vector text
                    if (displayVectors)
                    {
                        if (HighLogic.LoadedScene == GameScenes.FLIGHT && FlightGlobals.ready && FlightGlobals.fetch.activeVessel != null)
                        {
                            Vessel ourVessel = FlightGlobals.fetch.activeVessel;
                            vectorText  = "Forward vector: " + ourVessel.GetFwdVector() + "\n";
                            vectorText += "Up vector: " + (Vector3)ourVessel.upAxis + "\n";
                            vectorText += "Srf Rotation: " + ourVessel.srfRelRotation + "\n";
                            vectorText += "Vessel Rotation: " + ourVessel.transform.rotation + "\n";
                            vectorText += "Vessel Local Rotation: " + ourVessel.transform.localRotation + "\n";
                            vectorText += "mainBody Rotation: " + (Quaternion)ourVessel.mainBody.rotation + "\n";
                            vectorText += "mainBody Transform Rotation: " + (Quaternion)ourVessel.mainBody.bodyTransform.rotation + "\n";
                            vectorText += "Surface Velocity: " + ourVessel.GetSrfVelocity() + ", |v|: " + ourVessel.GetSrfVelocity().magnitude + "\n";
                            vectorText += "Orbital Velocity: " + ourVessel.GetObtVelocity() + ", |v|: " + ourVessel.GetObtVelocity().magnitude + "\n";
                            if (ourVessel.orbitDriver != null && ourVessel.orbitDriver.orbit != null)
                            {
                                vectorText += "Frame Velocity: " + (Vector3)ourVessel.orbitDriver.orbit.GetFrameVel() + ", |v|: " + ourVessel.orbitDriver.orbit.GetFrameVel().magnitude + "\n";
                            }
                            vectorText += "CoM offset vector: " + ourVessel.CoM.ToString() + "\n";
                            vectorText += "Angular Velocity: " + ourVessel.angularVelocity + ", |v|: " + ourVessel.angularVelocity.magnitude + "\n";
                            vectorText += "World Pos: " + (Vector3)ourVessel.GetWorldPos3D() + ", |pos|: " + ourVessel.GetWorldPos3D().magnitude + "\n";
                        }
                        else
                        {
                            vectorText = "You have to be in flight";
                        }
                    }

                    //NTP text
                    if (displayNTP)
                    {
                        ntpText  = "Warp rate: " + Math.Round(Time.timeScale, 3) + "x.\n";
                        ntpText += "Current subspace: " + timeSyncer.currentSubspace + ".\n";
                        if (timeSyncer.locked)
                        {
                            ntpText += "Current subspace rate: " + Math.Round(timeSyncer.lockedSubspace.subspaceSpeed, 3) + "x.\n";
                        }
                        else
                        {
                            ntpText += "Current subspace rate: " + Math.Round(timeSyncer.requestedRate, 3) + "x.\n";
                        }
                        ntpText += "Current Error: " + Math.Round((timeSyncer.GetCurrentError() * 1000), 0) + " ms.\n";
                        ntpText += "Current universe time: " + Math.Round(Planetarium.GetUniversalTime(), 3) + " UT\n";
                        ntpText += "Network latency: " + Math.Round((timeSyncer.networkLatencyAverage / 10000f), 3) + " ms\n";
                        ntpText += "Server clock difference: " + Math.Round((timeSyncer.clockOffsetAverage / 10000f), 3) + " ms\n";
                        ntpText += "Server lag: " + Math.Round((timeSyncer.serverLag / 10000f), 3) + " ms\n";
                    }
                    //Connection queue text
                    if (displayConnectionQueue)
                    {
                        connectionText  = "Last send time: " + networkWorker.GetStatistics("LastSendTime") + "ms.\n";
                        connectionText += "Last receive time: " + networkWorker.GetStatistics("LastReceiveTime") + "ms.\n";
                        connectionText += "Queued outgoing messages (High): " + networkWorker.GetStatistics("HighPriorityQueueLength") + ".\n";
                        connectionText += "Queued outgoing messages (Split): " + networkWorker.GetStatistics("SplitPriorityQueueLength") + ".\n";
                        connectionText += "Queued outgoing messages (Low): " + networkWorker.GetStatistics("LowPriorityQueueLength") + ".\n";
                        connectionText += "Queued out bytes: " + networkWorker.GetStatistics("QueuedOutBytes") + ".\n";
                        connectionText += "Sent bytes: " + networkWorker.GetStatistics("SentBytes") + ".\n";
                        connectionText += "Received bytes: " + networkWorker.GetStatistics("ReceivedBytes") + ".\n";
                        connectionText += "Stored future updates: " + vesselWorker.GetStatistics("StoredFutureUpdates") + "\n";
                        connectionText += "Stored future proto updates: " + vesselWorker.GetStatistics("StoredFutureProtoUpdates") + ".\n";
                    }

                    //Dynamic tick text
                    if (displayDynamicTickStats)
                    {
                        dynamicTickText  = "Current tick rate: " + DynamicTickWorker.SEND_TICK_RATE + "hz.\n";
                        dynamicTickText += "Current max secondry vessels: " + dynamicTickWorker.maxSecondryVesselsPerTick + ".\n";
                    }

                    //Requested rates text
                    if (displayRequestedRates)
                    {
                        requestedRateText = dmpSettings.playerName + ": " + Math.Round(timeSyncer.requestedRate, 3) + "x.\n";
                        foreach (KeyValuePair <string, float> playerEntry in warpWorker.clientSkewList)
                        {
                            requestedRateText += playerEntry.Key + ": " + Math.Round(playerEntry.Value, 3) + "x.\n";
                        }
                    }

                    //Requested rates text
                    if (displayRecycler)
                    {
                        recyclerText  = "16kB: " + ByteRecycler.GetPoolCount(Client.SMALL_MESSAGE_SIZE) + ", free: " + ByteRecycler.GetPoolFreeCount(Client.SMALL_MESSAGE_SIZE) + "\n";
                        recyclerText += "512kB: " + ByteRecycler.GetPoolCount(Client.MEDIUM_MESSAGE_SIZE) + ", free: " + ByteRecycler.GetPoolFreeCount(Client.MEDIUM_MESSAGE_SIZE) + "\n";
                        recyclerText += "6MB: " + ByteRecycler.GetPoolCount(Client.LARGE_MESSAGE_SIZE) + ", free: " + ByteRecycler.GetPoolFreeCount(Client.LARGE_MESSAGE_SIZE) + "\n";
                        recyclerText += "VesselUpdate: " + Recycler <VesselUpdate> .GetPoolCount() + ", free: " + Recycler <VesselUpdate> .GetPoolFreeCount() + "\n";
                    }

                    if (dumpRecycler)
                    {
                        dumpRecycler = false;
                        string dumpPath = Path.Combine(KSPUtil.ApplicationRootPath, "DarkMultiPlayer-Recycler");
                        ByteRecycler.DumpNonFree(dumpPath);
                    }
                }
            }
        }
Пример #21
0
        public void StartPlayback()
        {
            int       messagesLoaded = 0;
            bool      firstMessage   = true;
            ByteArray headerBytes    = ByteRecycler.GetObject(8);

            using (FileStream fs = new FileStream(recordPath, FileMode.Open))
            {
                while (fs.Position < fs.Length)
                {
                    messagesLoaded++;
                    fs.Read(headerBytes.data, 0, 8);
                    using (MessageReader mr = new MessageReader(headerBytes.data))
                    {
                        ClientMessageType messageType = (ClientMessageType)mr.Read <int>();
                        int       length    = mr.Read <int>();
                        ByteArray dataBytes = ByteRecycler.GetObject(length);
                        fs.Read(dataBytes.data, 0, length);
                        using (MessageReader timeReader = new MessageReader(dataBytes.data))
                        {
                            //Planet time is the first part of the message for the three types we care about here
                            double planetTime = timeReader.Read <double>();
                            lastTime = planetTime;
                            if (firstMessage)
                            {
                                firstTime    = planetTime;
                                firstMessage = false;
                                Planetarium.SetUniversalTime(planetTime - 5d);
                                warpWorker.SendNewSubspace();
                            }
                        }
                        using (MessageReader mrignore = new MessageReader(dataBytes.data))
                        {
                            //Planet time, don't care here
                            mrignore.Read <double>();
                            string vesselID = mrignore.Read <string>();
                            vesselWorker.IgnoreVessel(new Guid(vesselID));
                        }
                        switch (messageType)
                        {
                        case ClientMessageType.VESSEL_PROTO:
                            HandleProtoUpdate(dataBytes);
                            break;

                        case ClientMessageType.VESSEL_UPDATE:
                            HandleVesselUpdate(dataBytes, false);
                            break;

                        case ClientMessageType.VESSEL_REMOVE:
                            HandleVesselRemove(dataBytes);
                            break;

                        default:
                            break;
                        }
                        ByteRecycler.ReleaseObject(dataBytes);
                    }
                }
                ByteRecycler.ReleaseObject(headerBytes);
            }

            playbackQueue = new Queue <VesselUpdate>();
            using (FileStream fs = new FileStream(recordVectorPath, FileMode.Open))
            {
                while (fs.Position < fs.Length)
                {
                    fs.Read(headerBytesInt, 0, 4);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(headerBytesInt);
                    }
                    int       updateLength = BitConverter.ToInt32(headerBytesInt, 0);
                    ByteArray updateBytes  = ByteRecycler.GetObject(updateLength);
                    fs.Read(updateBytes.data, 0, updateLength);
                    VesselUpdate vu = networkWorker.VeselUpdateFromBytes(updateBytes.data, false);
                    playbackQueue.Enqueue(vu);
                    ByteRecycler.ReleaseObject(updateBytes);
                }
            }

            ScreenMessages.PostScreenMessage("Loaded " + messagesLoaded + " saved updates.", 5f, ScreenMessageStyle.UPPER_CENTER);
            screenMessage = ScreenMessages.PostScreenMessage("Playback 0 / " + (int)(lastTime - firstTime) + " seconds.", float.MaxValue, ScreenMessageStyle.UPPER_CENTER);
            playback      = true;
        }
Пример #22
0
 private void Update()
 {
     //Don't process incoming files or MOD_COMPLETE if we are hashing our gamedata folder
     if (hashingThreads == null)
     {
         lock (messageQueue)
         {
             while (messageQueue.Count > 0)
             {
                 ByteArray queueByteArray = messageQueue.Dequeue();
                 RealHandleMessage(queueByteArray);
                 ByteRecycler.ReleaseObject(queueByteArray);
                 //Don't process incoming files or MOD_COMPLETE if we are hashing our gamedata folder
                 if (hashingThreads != null)
                 {
                     syncString = "Hashing 0/" + modFilesToHash.Length + " files";
                     break;
                 }
             }
             if (networkWorker.state == ClientState.RUNNING)
             {
                 while (modFilesToUpload != null && networkWorker.GetStatistics("QueuedOutBytes") < 1000000)
                 {
                     RealSendToServer();
                     if (modFilesToUpload != null)
                     {
                         syncString = "Uploading " + modFilesToUploadPos + "/" + modFilesToUpload.Length + " files";
                         DarkLog.Debug(syncString);
                         if (screenMessage != null && DateTime.UtcNow.Ticks > nextScreenMessageUpdate)
                         {
                             nextScreenMessageUpdate = DateTime.UtcNow.Ticks + (TimeSpan.TicksPerMillisecond * 100);
                             screenMessage.duration  = 0f;
                             screenMessage           = ScreenMessages.PostScreenMessage(syncString);
                         }
                     }
                 }
             }
         }
     }
     else
     {
         long stopTime = DateTime.UtcNow.Ticks + (TimeSpan.TicksPerMillisecond * 100);
         CheckHashingThreads();
         if (hashingThreads == null)
         {
             using (StreamWriter sw = new StreamWriter(gameDataClientCachePath))
             {
                 foreach (KeyValuePair <string, string> kvp in clientPathCache)
                 {
                     sw.WriteLine("{0}={1}", kvp.Key, kvp.Value);
                 }
             }
             syncString = "Hashed " + clientPathCache.Count + " files";
             DarkLog.Debug("Hashed " + clientPathCache.Count + " files");
             if (screenMessage != null && DateTime.UtcNow.Ticks > nextScreenMessageUpdate)
             {
                 nextScreenMessageUpdate = DateTime.UtcNow.Ticks + (TimeSpan.TicksPerMillisecond * 100);
                 screenMessage.duration  = 0f;
                 screenMessage           = ScreenMessages.PostScreenMessage(syncString);
             }
             if (uploadAfterHashing)
             {
                 uploadAfterHashing = false;
                 using (MessageWriter mw = new MessageWriter())
                 {
                     List <string> uploadfiles = new List <string>(clientPathCache.Keys);
                     List <string> uploadsha   = new List <string>(clientPathCache.Values);
                     mw.Write <int>((int)ModpackDataMessageType.MOD_LIST);
                     mw.Write <string[]>(uploadfiles.ToArray());
                     mw.Write <string[]>(uploadsha.ToArray());
                     networkWorker.SendModpackMessage(mw.GetMessageBytes());
                 }
             }
         }
         else
         {
             syncString = "Hashing " + modFilesToHashPos + "/" + modFilesToHash.Length + " files";
             if (screenMessage != null && DateTime.UtcNow.Ticks > nextScreenMessageUpdate)
             {
                 nextScreenMessageUpdate = DateTime.UtcNow.Ticks + (TimeSpan.TicksPerMillisecond * 100);
                 screenMessage.duration  = 0f;
                 screenMessage           = ScreenMessages.PostScreenMessage(syncString);
             }
             DarkLog.Debug("Hashing " + modFilesToHashPos + "/" + modFilesToHash.Length + " files");
         }
     }
 }
Пример #23
0
        private void RealHandleMessage(ByteArray messageData)
        {
            using (MessageReader mr = new MessageReader(messageData.data))
            {
                ModpackDataMessageType type = (ModpackDataMessageType)mr.Read <int>();
                switch (type)
                {
                case ModpackDataMessageType.CKAN:
                {
                    modpackMode = ModpackMode.CKAN;
                    ByteArray receiveData = mr.Read <ByteArray>();
                    ByteArray oldData     = null;
                    if (File.Exists(ckanDataPath))
                    {
                        using (FileStream fs = new FileStream(ckanDataPath, FileMode.Open))
                        {
                            oldData = ByteRecycler.GetObject((int)fs.Length);
                            fs.Read(oldData.data, 0, oldData.Length);
                        }
                    }
                    if (!BytesMatch(oldData, receiveData))
                    {
                        missingWarnFile = true;
                        DarkLog.Debug("Ckan file changed");
                        File.Delete(ckanDataPath);
                        using (FileStream fs = new FileStream(ckanDataPath, FileMode.OpenOrCreate))
                        {
                            fs.Write(receiveData.data, 0, receiveData.Length);
                        }
                    }
                    if (!registeredChatCommand)
                    {
                        registeredChatCommand = true;
                        chatWorker.RegisterChatCommand("upload", UploadCKANToServer, "Upload DarkMultiPlayer.ckan to the server");
                    }
                    if (oldData != null)
                    {
                        ByteRecycler.ReleaseObject(oldData);
                    }
                    ByteRecycler.ReleaseObject(receiveData);
                }
                break;

                case ModpackDataMessageType.MOD_LIST:
                {
                    modFilesToHash    = null;
                    modFilesToHashPos = 0;
                    serverPathCache.Clear();
                    noWarnSha.Clear();
                    modpackMode = ModpackMode.GAMEDATA;
                    string[] files = mr.Read <string[]>();
                    string[] sha   = mr.Read <string[]>();
                    if (File.Exists(gameDataServerCachePath))
                    {
                        File.Delete(gameDataServerCachePath);
                    }
                    using (StreamWriter sw = new StreamWriter(gameDataServerCachePath))
                    {
                        for (int i = 0; i < files.Length; i++)
                        {
                            bool skipFile = false;
                            foreach (string ignoreString in ignoreList)
                            {
                                if (files[i].ToLower().StartsWith(ignoreString, StringComparison.Ordinal))
                                {
                                    skipFile = true;
                                }
                            }
                            foreach (string ignoreString in containsIgnoreList)
                            {
                                if (files[i].ToLower().Contains(ignoreString))
                                {
                                    skipFile = true;
                                }
                            }
                            if (skipFile)
                            {
                                continue;
                            }
                            sw.WriteLine("{0}={1}", files[i], sha[i]);
                            serverPathCache.Add(files[i], sha[i]);
                        }
                    }
                    LoadAuto();
                    if (!registeredChatCommand)
                    {
                        registeredChatCommand = true;
                        chatWorker.RegisterChatCommand("upload", UploadToServer, "Upload GameData to the server");
                    }
                }
                break;

                case ModpackDataMessageType.REQUEST_OBJECT:
                {
                    modFilesToUpload    = mr.Read <string[]>();
                    modFilesToUploadPos = 0;
                    DarkLog.Debug("Server requested " + modFilesToUpload.Length + " files");
                }
                break;

                case ModpackDataMessageType.RESPONSE_OBJECT:
                {
                    string sha256sum = mr.Read <string>();
                    filesDownloaded++;
                    if (mr.Read <bool>())
                    {
                        syncString = "Syncing files " + filesDownloaded + "/" + requestList.Count + " (" + (serverPathCache.Count - requestList.Count) + " cached)";
                        ByteArray fileBytes = mr.Read <ByteArray>();
                        string    filePath  = Path.Combine(cacheDataPath, sha256sum + ".bin");
                        if (!File.Exists(filePath))
                        {
                            using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate))
                            {
                                fs.Write(fileBytes.data, 0, fileBytes.Length);
                            }
                        }
                        ByteRecycler.ReleaseObject(fileBytes);
                    }
                    else
                    {
                        ScreenMessages.PostScreenMessage("DMP Server has an out of date hash list. Tell the admin to run /reloadmods", float.PositiveInfinity, ScreenMessageStyle.UPPER_CENTER);
                        networkWorker.Disconnect("Syncing files error");
                    }
                    if (filesDownloaded == requestList.Count)
                    {
                        if (missingWarnFile)
                        {
                            networkWorker.Disconnect("Syncing files " + filesDownloaded + "/" + requestList.Count + " (" + (serverPathCache.Count - requestList.Count) + " cached)");
                            ScreenMessages.PostScreenMessage("Please run DMPModpackUpdater or reconnect to ignore", float.PositiveInfinity, ScreenMessageStyle.UPPER_CENTER);
                        }
                        else
                        {
                            synced = true;
                        }
                    }
                }
                break;

                case ModpackDataMessageType.MOD_DONE:
                {
                    if ((!missingWarnFile && requestList.Count == 0) || secondModSync)
                    {
                        synced = true;
                    }
                    else
                    {
                        if (modpackMode == ModpackMode.CKAN)
                        {
                            ScreenMessages.PostScreenMessage("Please install CKAN update at KSP/DarkMultiPlayer.ckan or reconnect to ignore", float.PositiveInfinity, ScreenMessageStyle.UPPER_CENTER);
                            networkWorker.Disconnect("Synced DarkMultiPlayer.ckan");
                        }
                        if (modpackMode == ModpackMode.GAMEDATA && requestList.Count == 0)
                        {
                            ScreenMessages.PostScreenMessage("Please run DMPModpackUpdater or reconnect to ignore", float.PositiveInfinity, ScreenMessageStyle.UPPER_CENTER);
                            syncString = "Synced files (" + serverPathCache.Count + " cached)";
                            networkWorker.Disconnect(syncString);
                        }
                    }
                    secondModSync = true;
                }
                break;
                }
            }
        }