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); } }
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"); } } } } }
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); } }
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); } }
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(); }
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); }
public void ProcessWarpMessages() { lock (newWarpMessages) { while (newWarpMessages.Count > 0) { ByteArray queueByteArray = newWarpMessages.Dequeue(); HandleWarpMessage(queueByteArray.data); ByteRecycler.ReleaseObject(queueByteArray); } } }
private void ProcessMessages() { lock (messageQueue) { while (messageQueue.Count > 0) { ByteArray queueByteArray = messageQueue.Dequeue(); HandleMessage(queueByteArray.data); ByteRecycler.ReleaseObject(queueByteArray); } } }
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); }
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); } } }
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(); }
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); }
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); } } }
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; }
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!"); }
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()); } } }
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); } } } }
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; }
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"); } } }
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; } } }