public void TimingManagerFixedUpdate() { long startClock = Profiler.DMPReferenceTime.ElapsedTicks; if (modDisabled) { return; } dmpModInterface.FixedUpdate(); if (dmpGame != null) { foreach (Action fixedUpdateAction in dmpGame.fixedUpdateEvent) { try { fixedUpdateAction(); } catch (Exception e) { DarkLog.Debug("Threw in FixedUpdate event, exception: " + e); if (dmpGame.networkWorker != null) { 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!"); } } } } } } Profiler.fixedUpdateData.ReportTime(startClock); }
public Client() { //Fix DarkLog time/thread marker in the log during init. DarkLog.SetMainThread(); lastClockTicks = DateTime.UtcNow.Ticks; lastRealTimeSinceStartup = Time.realtimeSinceStartup; dmpClient = this; 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); optionsWindow = new OptionsWindow(dmpSettings, universeSyncCache, modWorker, universeConverterWindow, toolbarSupport); connectionWindow = new ConnectionWindow(dmpSettings, optionsWindow); disclaimerWindow = new DisclaimerWindow(dmpSettings); dmpModInterface = new DMPModInterface(); }
public void BuildDllFileList() { dllList = new Dictionary <string, string>(); string[] checkList = Directory.GetFiles(Path.Combine(KSPUtil.ApplicationRootPath, "GameData"), "*", SearchOption.AllDirectories); foreach (string checkFile in checkList) { //Only check DLL's if (checkFile.ToLower().EndsWith(".dll")) { //We want the relative path to check against, example: DarkMultiPlayer/Plugins/DarkMultiPlayer.dll //Strip off everything from GameData //Replace windows backslashes with mac/linux forward slashes. //Make it lowercase so we don't worry about case sensitivity. string relativeFilePath = checkFile.ToLowerInvariant().Substring(checkFile.ToLowerInvariant().IndexOf("gamedata") + 9).Replace('\\', '/'); string fileHash = Common.CalculateSHA256Hash(checkFile); dllList.Add(relativeFilePath, fileHash); DarkLog.Debug("Hashed file: " + relativeFilePath + ", hash: " + fileHash); } } }
public void SetVesselRanges(Vessel v) { if (!workerEnabled) { return; } ReportVesselUpdate(v.id); if (v != null) { DarkLog.Debug("Setting vessel " + v.id + " to bumped ranges"); bumpedVessels[v.id] = Client.realtimeSinceStartup; v.vesselRanges.flying.unpack = BUMP_FLYING_LOAD_DISTANCE; v.vesselRanges.flying.load = BUMP_FLYING_LOAD_DISTANCE + 1000f; v.vesselRanges.flying.pack = BUMP_FLYING_LOAD_DISTANCE + 2000f; v.vesselRanges.flying.unload = BUMP_FLYING_LOAD_DISTANCE + 3000f; v.vesselRanges.landed.unpack = BUMP_LANDED_LOAD_DISTANCE; v.vesselRanges.landed.load = BUMP_LANDED_LOAD_DISTANCE + 1000f; v.vesselRanges.landed.pack = BUMP_LANDED_LOAD_DISTANCE + 2000f; v.vesselRanges.landed.unload = BUMP_LANDED_LOAD_DISTANCE + 3000f; } }
private void JoinChannel(string commandArgs) { if (commandArgs != "" && commandArgs != "Global" && commandArgs != consoleIdentifier) { DarkLog.Debug("Joining channel " + commandArgs); joinedChannels.Add(commandArgs); selectedChannel = commandArgs; selectedPMChannel = null; using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)ChatMessageType.JOIN); mw.Write <string>(Settings.fetch.playerName); mw.Write <string>(commandArgs); NetworkWorker.fetch.SendChatMessage(mw.GetMessageBytes()); } } else { ScreenMessages.PostScreenMessage("Couln't join '" + commandArgs + "', channel name not valid!"); } }
/// <summary> /// Sends a DMP mod message. /// </summary> /// <param name="modName">Mod name</param> /// <param name="messageData">The message payload (MessageWriter can make this easier)</param> /// <param name="relay">If set to <c>true</c>, The server will relay the message to all other authenticated clients</param> /// <param name="highPriority">If set to <c>true</c>, DMP will send this in the high priority queue (Which will send before all vessel updates and screenshots)</param> public void SendDMPModMessage(string modName, byte[] messageData, bool relay, bool highPriority) { if (modName == null) { //Now that's just being silly :) return; } if (messageData == null) { DarkLog.Debug(modName + " attemped to send a null message"); return; } using (MessageWriter mw = new MessageWriter()) { mw.Write <string>(modName); mw.Write <bool>(relay); mw.Write <bool>(highPriority); mw.Write <byte[]>(messageData); networkWorker.SendModMessage(mw.GetMessageBytes(), highPriority); } }
private void StartGame() { //Create new game object for our DMP session. HighLogic.CurrentGame = CreateBlankGame(); //Set the game mode SetGameMode(); // //Found in KSP's files. Makes a crapton of sense :) // if (HighLogic.CurrentGame.Mode != Game.Modes.SANDBOX) // { // HighLogic.CurrentGame.Parameters.Difficulty.AllowStockVessels = false; // } // HighLogic.CurrentGame.flightState.universalTime = TimeSyncer.Instance.GetUniverseTime(); // // //Load DMP stuff // VesselWorker.Instance.LoadKerbalsIntoGame(); // VesselWorker.Instance.LoadVesselsIntoGame(); // // //Load the scenarios from the server // ScenarioWorker.Instance.LoadScenarioDataIntoGame(); // // //Load the missing scenarios as well (Eg, Contracts and stuff for career mode // ScenarioWorker.Instance.LoadMissingScenarioDataIntoGame(); // // //This only makes KSP complain // HighLogic.CurrentGame.CrewRoster.ValidateAssignments(HighLogic.CurrentGame); // DarkLog.Debug("Starting " + gameMode + " game..."); // // //Control locks will bug out the space centre sceen, so remove them before starting. // DeleteAllTheControlLocksSoTheSpaceCentreBugGoesAway(); // // //.Start() seems to stupidly .Load() somewhere - Let's overwrite it so it loads correctly. // GamePersistence.SaveGame(HighLogic.CurrentGame, "persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE); // HighLogic.CurrentGame.Start(); // ChatWorker.Instance.display = true; throw new NotImplementedException(); DarkLog.Debug("Started!"); }
private void DeleteCraftEntry(string playerName, CraftType craftType, string craftName) { if (playerList.ContainsKey(playerName)) { if (playerList[playerName].ContainsKey(craftType)) { if (playerList[playerName][craftType].Contains(craftName)) { playerList[playerName][craftType].Remove(craftName); if (playerList[playerName][craftType].Count == 0) { playerList[playerName].Remove(craftType); } if (playerList[playerName].Count == 0) { if (playerName != dmpSettings.playerName) { playerList.Remove(playerName); if (playersWithCrafts.Contains(playerName)) { playersWithCrafts.Remove(playerName); } } } } else { DarkLog.Debug("Cannot remove craft entry " + craftName + " for player " + playerName + ", craft does not exist"); } } else { DarkLog.Debug("Cannot remove craft entry " + craftName + " for player " + playerName + ", player does not have any " + craftType + " entries"); } } else { DarkLog.Debug("Cannot remove craft entry " + craftName + " for player " + playerName + ", no player entry"); } }
public void HandlePlayerColorMessage(byte[] messageData) { using (MessageReader mr = new MessageReader(messageData)) { PlayerColorMessageType messageType = (PlayerColorMessageType)mr.Read <int>(); switch (messageType) { case PlayerColorMessageType.LIST: { int numOfEntries = mr.Read <int>(); lock (playerColorLock) { playerColors = new Dictionary <string, Color>(); for (int i = 0; i < numOfEntries; i++) { string playerName = mr.Read <string>(); Color playerColor = ConvertFloatArrayToColor(mr.Read <float[]>()); playerColors.Add(playerName, playerColor); playerStatusWindow.colorEventHandled = false; } } } break; case PlayerColorMessageType.SET: { lock (playerColorLock) { string playerName = mr.Read <string>(); Color playerColor = ConvertFloatArrayToColor(mr.Read <float[]>()); DarkLog.Debug("Color message, name: " + playerName + " , color: " + playerColor.ToString()); playerColors[playerName] = playerColor; UpdateAllVesselColors(); playerStatusWindow.colorEventHandled = false; } } break; } } }
private void UploadCraftFile(CraftType type, string name) { string uploadPath = ""; switch (uploadCraftType) { case CraftType.VAB: uploadPath = vabPath; break; case CraftType.SPH: uploadPath = sphPath; break; case CraftType.SUBASSEMBLY: uploadPath = subassemblyPath; break; } string filePath = Path.Combine(uploadPath, name + ".craft"); if (File.Exists(filePath)) { byte[] fileData = File.ReadAllBytes(filePath); using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)CraftMessageType.UPLOAD_FILE); mw.Write <string>(dmpSettings.playerName); mw.Write <int>((int)type); mw.Write <string>(name); mw.Write <byte[]>(fileData); networkWorker.SendCraftLibraryMessage(mw.GetMessageBytes()); AddCraftEntry(dmpSettings.playerName, uploadCraftType, uploadCraftName); displayCraftUploadingMessage = true; } } else { DarkLog.Debug("Cannot upload file, " + filePath + " does not exist!"); } }
private void OnVesselCreate(Vessel vessel) { //Kerbals are put in the vessel *after* OnVesselCreate. Thanks squad!. if (vesselToKerbal.ContainsKey(vessel.id)) { OnVesselDestroyed(vessel); } if (vessel.GetCrewCount() > 0) { vesselToKerbal.Add(vessel.id, new List <string>()); foreach (ProtoCrewMember pcm in vessel.GetVesselCrew()) { vesselToKerbal[vessel.id].Add(pcm.name); if (kerbalToVessel.ContainsKey(pcm.name) && kerbalToVessel[pcm.name] != vessel.id) { DarkLog.Debug("Warning, kerbal double take on " + vessel.id + " ( " + vessel.name + " )"); } kerbalToVessel[pcm.name] = vessel.id; DarkLog.Debug("OVC " + pcm.name + " belongs to " + vessel.id); } } }
//Defends against bug #172 private void RemoveKerbalRescueMissionsSoTheGameDoesntBugOut(ConfigNode contractSystemNode) { ConfigNode contractsNode = contractSystemNode.GetNode("CONTRACTS"); List <ConfigNode> filteredContracts = new List <ConfigNode>(); foreach (ConfigNode contractNode in contractsNode.GetNodes("CONTRACT")) { if (contractNode.GetValue("type") != "RescueKerbal") { filteredContracts.Add(contractNode); } else { DarkLog.Debug("Skipped RescueKerbal contract - Causes bug #172"); } } contractsNode.ClearNodes(); foreach (ConfigNode contractNode in filteredContracts) { contractsNode.AddNode(contractNode); } }
private void OnVesselCreate(Vessel checkVessel) { if (workerEnabled) { if (VesselIsAsteroid(checkVessel)) { lock (serverAsteroidListLock) { if (LockSystem.fetch.LockIsOurs("asteroid-spawning")) { if (!serverAsteroids.Contains(checkVessel.id.ToString())) { if (GetAsteroidCount() <= maxNumberOfUntrackedAsteroids) { DarkLog.Debug("Spawned in new server asteroid!"); serverAsteroids.Add(checkVessel.id.ToString()); VesselWorker.fetch.RegisterServerVessel(checkVessel.id); NetworkWorker.fetch.SendVesselProtoMessage(checkVessel.protoVessel, false, false); NetworkWorker.fetch.SendVesselPermissions(PermissionsManager.GenerateAsteroidPermissions(checkVessel.protoVessel)); } else { DarkLog.Debug("Killing non-server asteroid " + checkVessel.id); checkVessel.Die(); } } } else { if (!serverAsteroids.Contains(checkVessel.id.ToString())) { DarkLog.Debug("Killing non-server asteroid " + checkVessel.id + ", we don't own the asteroid-spawning lock"); checkVessel.Die(); } } } } } }
//Defends against bug #172 private void CreateMissingKerbalsInProgressTrackingSoTheGameDoesntBugOut(ConfigNode progressTrackingNode) { foreach (ConfigNode possibleNode in progressTrackingNode.nodes) { //Recursion (noun): See Recursion. CreateMissingKerbalsInProgressTrackingSoTheGameDoesntBugOut(possibleNode); } //The kerbals are kept in a ConfigNode named 'crew', with 'crews' as a comma space delimited array of names. if (progressTrackingNode.name == "crew") { string kerbalNames = progressTrackingNode.GetValue("crews"); if (!String.IsNullOrEmpty(kerbalNames)) { string[] kerbalNamesSplit = kerbalNames.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries); foreach (string kerbalName in kerbalNamesSplit) { if (!HighLogic.CurrentGame.CrewRoster.Exists(kerbalName)) { if (AddCrewMemberToRoster == null) { MethodInfo addMemberToCrewRosterMethod = typeof(KerbalRoster).GetMethod("AddCrewMember", BindingFlags.NonPublic | BindingFlags.Instance); AddCrewMemberToRoster = (AddCrewMemberToRosterDelegate)Delegate.CreateDelegate(typeof(AddCrewMemberToRosterDelegate), HighLogic.CurrentGame.CrewRoster, addMemberToCrewRosterMethod); } if (AddCrewMemberToRoster == null) { throw new Exception("Failed to initialize AddCrewMemberToRoster for #172 ProgressTracking fix."); } DarkLog.Debug("Generating missing kerbal from ProgressTracking: " + kerbalName); ProtoCrewMember pcm = CrewGenerator.RandomCrewMemberPrototype(ProtoCrewMember.KerbalType.Crew); pcm.name = kerbalName; AddCrewMemberToRoster(pcm); //Also send it off to the server NetworkWorker.fetch.SendKerbalProtoMessage(pcm); } } } } }
private void ReleaseWarpMaster() { if (warpMaster == dmpSettings.playerName) { SendNewSubspace(); } warpMaster = ""; voteSent = false; voteMaster = ""; voteYesCount = 0; voteNoCount = 0; controllerExpireTime = double.NegativeInfinity; using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)WarpMessageType.RELEASE_CONTROLLER); networkWorker.SendWarpMessage(mw.GetMessageBytes()); } if (TimeWarp.CurrentRateIndex > 0) { DarkLog.Debug("Resetting warp rate back to 0"); TimeWarp.SetRate(0, true); } }
public void LoadScenarioDataIntoGame() { while (scenarioQueue.Count > 0) { LoadScenarioData(scenarioQueue.Dequeue()); } if (!loadedScience && Client.fetch.gameMode == GameMode.CAREER) { DarkLog.Debug("Creating new science data"); ConfigNode newNode = GetBlankResearchAndDevelopmentNode(); ProtoScenarioModule newModule = new ProtoScenarioModule(newNode); try { HighLogic.CurrentGame.scenarios.Add(newModule); newModule.Load(ScenarioRunner.fetch); } catch { DarkLog.Debug("Error loading new science data!"); blockScenarioDataSends = true; } } }
private void HandleCommandLineArgs() { bool nextLineIsAddress = false; bool valid = false; string address = null; int port = 0; foreach (string commandLineArg in Environment.GetCommandLineArgs()) { //Supporting IPv6 is FUN! if (nextLineIsAddress) { valid = CommandLineParser.ParseIp(commandLineArg, out address, out port); if (port == 0) { port = 6702; } nextLineIsAddress = false; } if (commandLineArg == "-dmp") { nextLineIsAddress = true; } } if (valid) { commandLineConnect = new ServerEntry(); commandLineConnect.address = address; commandLineConnect.port = port; DarkLog.Debug("Connecting via command line to: " + address + ", port: " + port); } else { DarkLog.Debug("Command line address is invalid: " + address + ", port: " + port); } }
public void EnableToolbar() { buttonTexture = GameDatabase.Instance.GetTexture("DarkMultiPlayer/Button/DMPButton", false); if (registered) { DarkLog.Debug("Cannot re-register toolbar"); return; } registered = true; if (dmpSettings.toolbarType == DMPToolbarType.DISABLED) { //Nothing! } if (dmpSettings.toolbarType == DMPToolbarType.FORCE_STOCK) { EnableStockToolbar(); } if (dmpSettings.toolbarType == DMPToolbarType.BLIZZY_IF_INSTALLED) { if (ToolbarManager.ToolbarAvailable) { EnableBlizzyToolbar(); } else { EnableStockToolbar(); } } if (dmpSettings.toolbarType == DMPToolbarType.BOTH_IF_INSTALLED) { if (ToolbarManager.ToolbarAvailable) { EnableBlizzyToolbar(); } EnableStockToolbar(); } }
private void StartGame() { //Create new game object for our DMP session. HighLogic.CurrentGame = CreateBlankGame(); //Set the game mode HighLogic.CurrentGame.Mode = ConvertGameMode(gameMode); //Set difficulty HighLogic.CurrentGame.Parameters = serverParameters; //Set universe time HighLogic.CurrentGame.flightState.universalTime = TimeSyncer.fetch.GetUniverseTime(); //Load DMP stuff VesselWorker.fetch.LoadKerbalsIntoGame(); VesselWorker.fetch.LoadVesselsIntoGame(); //Load the scenarios from the server ScenarioWorker.fetch.LoadScenarioDataIntoGame(); //Load the missing scenarios as well (Eg, Contracts and stuff for career mode ScenarioWorker.fetch.LoadMissingScenarioDataIntoGame(); //This only makes KSP complain HighLogic.CurrentGame.CrewRoster.ValidateAssignments(HighLogic.CurrentGame); DarkLog.Debug("Starting " + gameMode + " game..."); //Control locks will bug out the space centre sceen, so remove them before starting. DeleteAllTheControlLocksSoTheSpaceCentreBugGoesAway(); //.Start() seems to stupidly .Load() somewhere - Let's overwrite it so it loads correctly. GamePersistence.SaveGame(HighLogic.CurrentGame, "persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE); HighLogic.CurrentGame.Start(); ChatWorker.fetch.display = true; DarkLog.Debug("Started!"); }
public void Start() { if (!CompatibilityChecker.IsCompatible() || !InstallChecker.IsCorrectlyInstalled()) { modDisabled = true; } if (dmpSettings.disclaimerAccepted != 1) { modDisabled = true; disclaimerWindow.SpawnDialog(); } Profiler.DMPReferenceTime.Start(); 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(); long testTime = Compression.TestSysIOCompression(); DarkLog.Debug("System.IO compression works: " + Compression.sysIOCompressionWorks + ", test time: " + testTime + " ms."); DarkLog.Debug("DarkMultiPlayer " + Common.PROGRAM_VERSION + ", protocol " + Common.PROTOCOL_VERSION + " Initialized!"); }
private void CheckWarp() { bool resetWarp = true; if ((warpMode == WarpMode.MCW_FORCE) || (warpMode == WarpMode.MCW_VOTE) || (warpMode == WarpMode.MCW_LOWEST)) { if (warpMaster != "") { //It could be us or another player. If it's another player it will be controlled from Update() instead. resetWarp = false; } } if (warpMode == WarpMode.SUBSPACE) { //Never reset warp in SUBSPACE mode. resetWarp = false; } if (warpMode == WarpMode.SUBSPACE_SIMPLE && canSubspaceSimpleWarp) { resetWarp = false; } if ((TimeWarp.CurrentRateIndex > 0) && resetWarp) { //DarkLog.Debug("Resetting warp rate back to 0"); TimeWarp.SetRate(0, true); } if ((TimeWarp.CurrentRateIndex > 0) && (TimeWarp.CurrentRate > 1.1f) && !resetWarp && timeSyncer.locked) { DarkLog.Debug("Unlocking from subspace"); timeSyncer.UnlockSubspace(); } if ((TimeWarp.CurrentRateIndex == 0) && (TimeWarp.CurrentRate < 1.1f) && !timeSyncer.locked && ((warpMode == WarpMode.SUBSPACE) || (warpMode == WarpMode.SUBSPACE_SIMPLE)) && (timeSyncer.currentSubspace == -1)) { SendNewSubspace(); } }
private void OnVesselWillDestroy(Vessel vessel) { bool pilotedByAnotherPlayer = lockSystem.LockExists("control-" + vessel.id) && !lockSystem.LockIsOurs("control-" + vessel.id); bool updatedByAnotherPlayer = lockSystem.LockExists("update-" + vessel.id) && !lockSystem.LockIsOurs("update-" + vessel.id); bool updatedInTheFuture = vesselWorker.VesselUpdatedInFuture(vessel.id); //Vessel was packed within the last 5 seconds if (lastPackTime.ContainsKey(vessel.id) && (Client.realtimeSinceStartup - lastPackTime[vessel.id]) < 5f) { lastPackTime.Remove(vessel.id); if (vessel.situation == Vessel.Situations.FLYING && (pilotedByAnotherPlayer || updatedByAnotherPlayer || updatedInTheFuture)) { DarkLog.Debug("Hacky load: Saving player vessel getting packed in atmosphere"); ProtoVessel pv = vessel.BackupVessel(); ConfigNode savedNode = new ConfigNode(); pv.Save(savedNode); vesselWorker.LoadVessel(savedNode, vessel.id, true); } } if (lastPackTime.ContainsKey(vessel.id)) { lastPackTime.Remove(vessel.id); } }
//WARNING: Called from NetworkWorker. public void StartGame() { HighLogic.CurrentGame = new Game(); HighLogic.CurrentGame.flightState = new FlightState(); HighLogic.CurrentGame.CrewRoster = new CrewRoster(); HighLogic.CurrentGame.scenarios = new List <ProtoScenarioModule>(); HighLogic.CurrentGame.startScene = GameScenes.SPACECENTER; HighLogic.CurrentGame.flagURL = Settings.fetch.selectedFlag; HighLogic.CurrentGame.Title = "DarkMultiPlayer"; HighLogic.CurrentGame.Parameters.Flight.CanQuickLoad = false; HighLogic.SaveFolder = "DarkMultiPlayer"; HighLogic.CurrentGame.flightState.universalTime = TimeSyncer.fetch.GetUniverseTime(); SetGameMode(); ScenarioWorker.fetch.LoadScenarioDataIntoGame(); AsteroidWorker.fetch.LoadAsteroidScenario(); VesselWorker.fetch.LoadKerbalsIntoGame(); VesselWorker.fetch.LoadVesselsIntoGame(); DarkLog.Debug("Starting " + gameMode + " game..."); HighLogic.CurrentGame.Start(); DarkLog.Debug("Started!"); Planetarium.SetUniversalTime(TimeSyncer.fetch.GetUniverseTime()); GamePersistence.SaveGame("persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE); ChatWorker.fetch.display = true; }
public void OnGUI() { //Window ID's - Doesn't include "random" offset. //Connection window: 6702 //Status window: 6703 //Chat window: 6704 //Debug window: 6705 //Mod windw: 6706 //Craft library window: 6707 //Craft upload window: 6708 //Screenshot window: 6710 //Options window: 6711 //Converter window: 6712 //Disclaimer window: 6713 long startClock = Profiler.DMPReferenceTime.ElapsedTicks; if (showGUI) { foreach (Action drawAction in drawEvent) { try { // Don't hide the ConnectionWindow if we disabled DMP GUI if (toolbarShowGUI || (!toolbarShowGUI && drawAction.Target.ToString() == "DarkMultiPlayer.ConnectionWindow")) { drawAction(); } } catch (Exception e) { DarkLog.Debug("Threw in OnGUI event, exception: " + e); } } } Profiler.guiData.ReportTime(startClock); }
private void Update() { if (workerEnabled) { if ((Client.realtimeSinceStartup - lastPlayerStatusCheck) > PLAYER_STATUS_CHECK_INTERVAL) { lastPlayerStatusCheck = Client.realtimeSinceStartup; myPlayerStatus.vesselText = ""; myPlayerStatus.statusText = ""; if (HighLogic.LoadedSceneIsFlight) { //Send vessel+status update if (FlightGlobals.ActiveVessel != null) { if (!vesselWorker.isSpectating) { myPlayerStatus.vesselText = FlightGlobals.ActiveVessel.vesselName; string bodyName = FlightGlobals.ActiveVessel.mainBody.bodyName; switch (FlightGlobals.ActiveVessel.situation) { case (Vessel.Situations.DOCKED): myPlayerStatus.statusText = "Docked above " + bodyName; break; case (Vessel.Situations.ESCAPING): if (FlightGlobals.ActiveVessel.orbit.timeToPe < 0) { myPlayerStatus.statusText = "Escaping " + bodyName; } else { myPlayerStatus.statusText = "Encountering " + bodyName; } break; case (Vessel.Situations.FLYING): if (!SafetyBubble.isInSafetyBubble(FlightGlobals.fetch.activeVessel.GetWorldPos3D(), FlightGlobals.fetch.activeVessel.mainBody, vesselWorker.safetyBubbleDistance)) { myPlayerStatus.statusText = "Flying above " + bodyName; } else { myPlayerStatus.statusText = "Flying in safety bubble"; } break; case (Vessel.Situations.LANDED): if (!SafetyBubble.isInSafetyBubble(FlightGlobals.fetch.activeVessel.GetWorldPos3D(), FlightGlobals.fetch.activeVessel.mainBody, vesselWorker.safetyBubbleDistance)) { myPlayerStatus.statusText = "Landed on " + bodyName; } else { myPlayerStatus.statusText = "Landed in safety bubble"; } break; case (Vessel.Situations.ORBITING): myPlayerStatus.statusText = "Orbiting " + bodyName; break; case (Vessel.Situations.PRELAUNCH): if (!SafetyBubble.isInSafetyBubble(FlightGlobals.fetch.activeVessel.GetWorldPos3D(), FlightGlobals.fetch.activeVessel.mainBody, vesselWorker.safetyBubbleDistance)) { myPlayerStatus.statusText = "Launching from " + bodyName; } else { myPlayerStatus.statusText = "Launching from safety bubble"; } break; case (Vessel.Situations.SPLASHED): myPlayerStatus.statusText = "Splashed on " + bodyName; break; case (Vessel.Situations.SUB_ORBITAL): if (FlightGlobals.ActiveVessel.verticalSpeed > 0) { myPlayerStatus.statusText = "Ascending from " + bodyName; } else { myPlayerStatus.statusText = "Descending to " + bodyName; } break; default: break; } } else { if (lockSystem.LockExists("control-" + FlightGlobals.ActiveVessel.id.ToString())) { if (lockSystem.LockIsOurs("control-" + FlightGlobals.ActiveVessel.id.ToString())) { myPlayerStatus.statusText = "Waiting for vessel control"; } else { myPlayerStatus.statusText = "Spectating " + lockSystem.LockOwner("control-" + FlightGlobals.ActiveVessel.id.ToString()); } } else { if (permissions.PlayerHasVesselPermission(myPlayerStatus.playerName, FlightGlobals.ActiveVessel.id)) { myPlayerStatus.statusText = "Spectating future updates"; } else { myPlayerStatus.statusText = "Spectating protected vessel"; } } } } else { myPlayerStatus.statusText = "Loading"; } } else { //Send status update switch (HighLogic.LoadedScene) { case (GameScenes.EDITOR): myPlayerStatus.statusText = "Building"; if (EditorDriver.editorFacility == EditorFacility.VAB) { myPlayerStatus.statusText = "Building in VAB"; } if (EditorDriver.editorFacility == EditorFacility.SPH) { myPlayerStatus.statusText = "Building in SPH"; } break; case (GameScenes.SPACECENTER): myPlayerStatus.statusText = "At Space Center"; break; case (GameScenes.TRACKSTATION): myPlayerStatus.statusText = "At Tracking Station"; break; case (GameScenes.LOADING): myPlayerStatus.statusText = "Loading"; break; default: break; } } } bool statusDifferent = false; statusDifferent = statusDifferent || (myPlayerStatus.vesselText != lastPlayerStatus.vesselText); statusDifferent = statusDifferent || (myPlayerStatus.statusText != lastPlayerStatus.statusText); if (statusDifferent && ((Client.realtimeSinceStartup - lastPlayerStatusSend) > PLAYER_STATUS_SEND_THROTTLE)) { lastPlayerStatusSend = Client.realtimeSinceStartup; lastPlayerStatus.vesselText = myPlayerStatus.vesselText; lastPlayerStatus.statusText = myPlayerStatus.statusText; networkWorker.SendPlayerStatus(myPlayerStatus); } while (addStatusQueue.Count > 0) { PlayerStatus newStatusEntry = addStatusQueue.Dequeue(); bool found = false; foreach (PlayerStatus playerStatusEntry in playerStatusList) { if (playerStatusEntry.playerName == newStatusEntry.playerName) { found = true; playerStatusEntry.vesselText = newStatusEntry.vesselText; playerStatusEntry.statusText = newStatusEntry.statusText; } } if (!found) { playerStatusList.Add(newStatusEntry); DarkLog.Debug("Added " + newStatusEntry.playerName + " to status list"); } } while (removeStatusQueue.Count > 0) { string removeStatusString = removeStatusQueue.Dequeue(); PlayerStatus removeStatus = null; foreach (PlayerStatus currentStatus in playerStatusList) { if (currentStatus.playerName == removeStatusString) { removeStatus = currentStatus; } } if (removeStatus != null) { playerStatusList.Remove(removeStatus); DarkLog.Debug("Removed " + removeStatusString + " from status list"); } else { DarkLog.Debug("Cannot remove non-existant player " + removeStatusString); } } } }
private void Update() { //Switch to new subspace if told to - this needs to be before the workerEnabled check as it fires during the initial sync if (newSetSubspace != -1) { DarkLog.Debug("Sent to subspace: " + newSetSubspace); timeSyncer.LockSubspace(newSetSubspace); newSetSubspace = -1; } if (!workerEnabled) { return; } //Reset warp if we need to CheckWarp(); //Process new warp messages ProcessWarpMessages(); //Write the screen message if needed if ((Client.realtimeSinceStartup - lastScreenMessageCheck) > SCREEN_MESSAGE_UPDATE_INTERVAL) { lastScreenMessageCheck = Client.realtimeSinceStartup; UpdateScreenMessage(); } //Send a CHANGE_WARP message if needed if ((warpMode == WarpMode.MCW_FORCE) || (warpMode == WarpMode.MCW_VOTE) || (warpMode == WarpMode.SUBSPACE) || warpMode == WarpMode.SUBSPACE_SIMPLE) { if (!clientWarpList.ContainsKey(dmpSettings.playerName)) { clientWarpList[dmpSettings.playerName] = new PlayerWarpRate(); } PlayerWarpRate ourRate = clientWarpList[dmpSettings.playerName]; if ((ourRate.rateIndex != TimeWarp.CurrentRateIndex) || (ourRate.isPhysWarp != (TimeWarp.WarpMode == TimeWarp.Modes.LOW))) { ourRate.isPhysWarp = (TimeWarp.WarpMode == TimeWarp.Modes.LOW); ourRate.rateIndex = TimeWarp.CurrentRateIndex; ourRate.serverClock = timeSyncer.GetServerClock(); ourRate.planetTime = Planetarium.GetUniversalTime(); using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)WarpMessageType.CHANGE_WARP); mw.Write <bool>(ourRate.isPhysWarp); mw.Write <int>(ourRate.rateIndex); mw.Write <long>(ourRate.serverClock); mw.Write <double>(ourRate.planetTime); networkWorker.SendWarpMessage(mw.GetMessageBytes()); } } } if ((Client.realtimeSinceStartup - lastWarpSet) > WARP_SET_THROTTLE) { //Follow the warp master into warp if needed (MCW_FORCE/MCW_VOTE) if (warpMode == WarpMode.MCW_FORCE || warpMode == WarpMode.MCW_VOTE) { if ((warpMaster != "") && (warpMaster != dmpSettings.playerName)) { if (clientWarpList.ContainsKey(warpMaster)) { //Get master warp rate PlayerWarpRate masterWarpRate = clientWarpList[warpMaster]; SetTimeFromWarpEntry(masterWarpRate); lastWarpSet = Client.realtimeSinceStartup; } else { TimeWarp.SetRate(0, true); } } } if (warpMode == WarpMode.MCW_LOWEST) { if ((warpMaster != "") && clientWarpList.ContainsKey(warpMaster)) { //Get master warp rate PlayerWarpRate masterWarpRate = clientWarpList[warpMaster]; SetTimeFromWarpEntry(masterWarpRate); lastWarpSet = Client.realtimeSinceStartup; } } } //Report our timeSyncer skew if ((Client.realtimeSinceStartup - lastReportRate) > REPORT_SKEW_RATE_INTERVAL && timeSyncer.locked) { lastReportRate = Client.realtimeSinceStartup; using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)WarpMessageType.REPORT_RATE); mw.Write <float>(timeSyncer.requestedRate); networkWorker.SendWarpMessage(mw.GetMessageBytes()); } } //Handle warp keys HandleInput(); }
private void HandleWarpMessage(byte[] messageData) { using (MessageReader mr = new MessageReader(messageData)) { WarpMessageType messageType = (WarpMessageType)mr.Read <int>(); switch (messageType) { case WarpMessageType.REQUEST_VOTE: { voteMaster = mr.Read <string>(); long expireTime = mr.Read <long>(); voteExpireTime = Client.realtimeSinceStartup + ((expireTime - timeSyncer.GetServerClock()) / 10000000d); } break; case WarpMessageType.REPLY_VOTE: { int incomingVoteYesCount = mr.Read <int>(); int incomingVoteNoCount = mr.Read <int>(); HandleReplyVote(incomingVoteYesCount, incomingVoteNoCount); } break; case WarpMessageType.SET_CONTROLLER: { string newController = mr.Read <string>(); long expireTime = mr.Read <long>(); HandleSetController(newController, expireTime); } break; case WarpMessageType.CHANGE_WARP: { string fromPlayer = mr.Read <string>(); bool isPhysWarp = mr.Read <bool>(); int rateIndex = mr.Read <int>(); long serverClock = mr.Read <long>(); double planetTime = mr.Read <double>(); HandleChangeWarp(fromPlayer, isPhysWarp, rateIndex, serverClock, planetTime); } break; case WarpMessageType.NEW_SUBSPACE: { int newSubspaceID = mr.Read <int>(); long serverTime = mr.Read <long>(); double planetariumTime = mr.Read <double>(); float gameSpeed = mr.Read <float>(); timeSyncer.AddNewSubspace(newSubspaceID, serverTime, planetariumTime, gameSpeed); } break; case WarpMessageType.CHANGE_SUBSPACE: { string fromPlayer = mr.Read <string>(); if (fromPlayer != dmpSettings.playerName) { int changeSubspaceID = mr.Read <int>(); clientSubspaceList[fromPlayer] = changeSubspaceID; if (changeSubspaceID != -1) { if (clientWarpList.ContainsKey(fromPlayer)) { clientWarpList.Remove(fromPlayer); } } } } break; case WarpMessageType.RELOCK_SUBSPACE: { int subspaceID = mr.Read <int>(); long serverTime = mr.Read <long>(); double planetariumTime = mr.Read <double>(); float gameSpeed = mr.Read <float>(); timeSyncer.RelockSubspace(subspaceID, serverTime, planetariumTime, gameSpeed); } break; case WarpMessageType.REPORT_RATE: { string fromPlayer = mr.Read <string>(); clientSkewList[fromPlayer] = mr.Read <float>(); } break; default: { DarkLog.Debug("Unhandled WARP_MESSAGE type: " + messageType); break; } } } }
public static VesselUpdate CopyFromVessel(VesselWorker vesselWorker, Vessel updateVessel) { VesselUpdate returnUpdate = new VesselUpdate(vesselWorker); try { returnUpdate.vesselID = updateVessel.id; returnUpdate.planetTime = Planetarium.GetUniversalTime(); returnUpdate.bodyName = updateVessel.mainBody.bodyName; returnUpdate.rotation = new float[4]; returnUpdate.rotation[0] = updateVessel.srfRelRotation.x; returnUpdate.rotation[1] = updateVessel.srfRelRotation.y; returnUpdate.rotation[2] = updateVessel.srfRelRotation.z; returnUpdate.rotation[3] = updateVessel.srfRelRotation.w; returnUpdate.angularVelocity = new float[3]; returnUpdate.angularVelocity[0] = updateVessel.angularVelocity.x; returnUpdate.angularVelocity[1] = updateVessel.angularVelocity.y; returnUpdate.angularVelocity[2] = updateVessel.angularVelocity.z; //Flight state returnUpdate.flightState = new FlightCtrlState(); returnUpdate.flightState.CopyFrom(updateVessel.ctrlState); returnUpdate.actiongroupControls = new bool[5]; returnUpdate.actiongroupControls[0] = updateVessel.ActionGroups[KSPActionGroup.Gear]; returnUpdate.actiongroupControls[1] = updateVessel.ActionGroups[KSPActionGroup.Light]; returnUpdate.actiongroupControls[2] = updateVessel.ActionGroups[KSPActionGroup.Brakes]; returnUpdate.actiongroupControls[3] = updateVessel.ActionGroups[KSPActionGroup.SAS]; returnUpdate.actiongroupControls[4] = updateVessel.ActionGroups[KSPActionGroup.RCS]; if (updateVessel.altitude < 10000) { //Use surface position under 10k returnUpdate.isSurfaceUpdate = true; returnUpdate.position = new double[4]; returnUpdate.position[0] = updateVessel.latitude; returnUpdate.position[1] = updateVessel.longitude; returnUpdate.position[2] = updateVessel.altitude; VesselUtil.DMPRaycastPair groundRaycast = VesselUtil.RaycastGround(updateVessel.latitude, updateVessel.longitude, updateVessel.mainBody); returnUpdate.position[3] = groundRaycast.altitude; returnUpdate.terrainNormal = new float[3]; returnUpdate.terrainNormal[0] = groundRaycast.terrainNormal.x; returnUpdate.terrainNormal[1] = groundRaycast.terrainNormal.y; returnUpdate.terrainNormal[2] = groundRaycast.terrainNormal.z; returnUpdate.velocity = new double[3]; Vector3d srfVel = Quaternion.Inverse(updateVessel.mainBody.bodyTransform.rotation) * updateVessel.srf_velocity; returnUpdate.velocity[0] = srfVel.x; returnUpdate.velocity[1] = srfVel.y; returnUpdate.velocity[2] = srfVel.z; returnUpdate.acceleration = new double[3]; Vector3d srfAcceleration = Quaternion.Inverse(updateVessel.mainBody.bodyTransform.rotation) * updateVessel.acceleration; returnUpdate.acceleration[0] = srfAcceleration.x; returnUpdate.acceleration[1] = srfAcceleration.y; returnUpdate.acceleration[2] = srfAcceleration.z; } else { //Use orbital positioning over 10k returnUpdate.isSurfaceUpdate = false; returnUpdate.orbit = new double[7]; returnUpdate.orbit[0] = updateVessel.orbit.inclination; returnUpdate.orbit[1] = updateVessel.orbit.eccentricity; returnUpdate.orbit[2] = updateVessel.orbit.semiMajorAxis; returnUpdate.orbit[3] = updateVessel.orbit.LAN; returnUpdate.orbit[4] = updateVessel.orbit.argumentOfPeriapsis; returnUpdate.orbit[5] = updateVessel.orbit.meanAnomalyAtEpoch; returnUpdate.orbit[6] = updateVessel.orbit.epoch; } returnUpdate.sasEnabled = updateVessel.Autopilot.Enabled; if (returnUpdate.sasEnabled) { returnUpdate.autopilotMode = (int)updateVessel.Autopilot.Mode; returnUpdate.lockedRotation = new float[4]; returnUpdate.lockedRotation[0] = updateVessel.Autopilot.SAS.lockedRotation.x; returnUpdate.lockedRotation[1] = updateVessel.Autopilot.SAS.lockedRotation.y; returnUpdate.lockedRotation[2] = updateVessel.Autopilot.SAS.lockedRotation.z; returnUpdate.lockedRotation[3] = updateVessel.Autopilot.SAS.lockedRotation.w; } } catch (Exception e) { DarkLog.Debug("Failed to get vessel update, exception: " + e); returnUpdate = null; } return(returnUpdate); }
public bool ParseModFile(string modFileData) { if (!modControl) { return(true); } bool modCheckOk = true; //Save mod file so we can recheck it. lastModFileData = modFileData; //Err... string tempModFilePath = Path.Combine(Path.Combine(Path.Combine(Path.Combine(Path.Combine(KSPUtil.ApplicationRootPath, "GameData"), "DarkMultiPlayer"), "Plugins"), "Data"), "DMPModControl.txt"); using (StreamWriter sw = new StreamWriter(tempModFilePath)) { sw.WriteLine("#This file is downloaded from the server during connection. It is saved here for convenience."); sw.WriteLine(lastModFileData); } //Parse Dictionary <string, string> parseRequired = new Dictionary <string, string>(); Dictionary <string, string> parseOptional = new Dictionary <string, string>(); List <string> parseWhiteBlackList = new List <string>(); List <string> parsePartsList = new List <string>(); bool isWhiteList = false; string readMode = ""; using (StringReader sr = new StringReader(modFileData)) { while (true) { string currentLine = sr.ReadLine(); if (currentLine == null) { //Done reading break; } //Remove tabs/spaces from the start & end. string trimmedLine = currentLine.Trim(); if (trimmedLine.StartsWith("#") || String.IsNullOrEmpty(trimmedLine)) { //Skip comments or empty lines. continue; } if (trimmedLine.StartsWith("!")) { //New section switch (trimmedLine.Substring(1)) { case "required-files": case "optional-files": case "partslist": readMode = trimmedLine.Substring(1); break; case "resource-blacklist": readMode = trimmedLine.Substring(1); isWhiteList = false; break; case "resource-whitelist": readMode = trimmedLine.Substring(1); isWhiteList = true; break; } } else { switch (readMode) { case "required-files": { string lowerFixedLine = trimmedLine.ToLowerInvariant().Replace('\\', '/'); if (lowerFixedLine.Contains("=")) { string[] splitLine = lowerFixedLine.Split('='); if (splitLine.Length == 2) { if (!parseRequired.ContainsKey(splitLine[0])) { parseRequired.Add(splitLine[0], splitLine[1].ToLowerInvariant()); } } else { if (splitLine.Length == 1) { if (!parseRequired.ContainsKey(splitLine[0])) { parseRequired.Add(splitLine[0], ""); } } } } else { if (!parseRequired.ContainsKey(lowerFixedLine)) { parseRequired.Add(lowerFixedLine, ""); } } } break; case "optional-files": { string lowerFixedLine = trimmedLine.ToLowerInvariant().Replace('\\', '/'); if (lowerFixedLine.Contains("=")) { string[] splitLine = lowerFixedLine.Split('='); if (splitLine.Length == 2) { if (!parseOptional.ContainsKey(splitLine[0])) { parseOptional.Add(splitLine[0], splitLine[1]); } } else { if (splitLine.Length == 1) { if (!parseOptional.ContainsKey(splitLine[0])) { parseOptional.Add(splitLine[0], ""); } } } } else { if (!parseOptional.ContainsKey(lowerFixedLine)) { parseOptional.Add(lowerFixedLine, ""); } } } break; case "resource-whitelist": case "resource-blacklist": { string lowerFixedLine = trimmedLine.ToLowerInvariant().Replace('\\', '/'); //Resource is dll's only. if (lowerFixedLine.ToLowerInvariant().EndsWith(".dll")) { if (parseWhiteBlackList.Contains(lowerFixedLine)) { parseWhiteBlackList.Add(lowerFixedLine); } } } break; case "partslist": if (!parsePartsList.Contains(trimmedLine)) { parsePartsList.Add(trimmedLine); } break; } } } } string[] currentGameDataFiles = Directory.GetFiles(Path.Combine(KSPUtil.ApplicationRootPath, "GameData"), "*", SearchOption.AllDirectories); List <string> currentGameDataFilesNormal = new List <string>(); List <string> currentGameDataFilesLower = new List <string>(); foreach (string currentFile in currentGameDataFiles) { string relativeFilePath = currentFile.Substring(currentFile.ToLowerInvariant().IndexOf("gamedata") + 9).Replace('\\', '/'); currentGameDataFilesNormal.Add(relativeFilePath); currentGameDataFilesLower.Add(relativeFilePath.ToLowerInvariant()); } //Check StringBuilder sb = new StringBuilder(); //Check Required foreach (KeyValuePair <string, string> requiredEntry in parseRequired) { if (!requiredEntry.Key.EndsWith("dll")) { //Protect against windows-style entries in DMPModControl.txt. Also use case insensitive matching. if (!currentGameDataFilesLower.Contains(requiredEntry.Key)) { modCheckOk = false; DarkLog.Debug("Required file " + requiredEntry.Key + " is missing!"); sb.AppendLine("Required file " + requiredEntry.Key + " is missing!"); continue; } //If the entry has a SHA sum, we need to check it. if (requiredEntry.Value != "") { string normalCaseFileName = currentGameDataFilesNormal[currentGameDataFilesLower.IndexOf(requiredEntry.Key)]; string fullFileName = Path.Combine(Path.Combine(KSPUtil.ApplicationRootPath, "GameData"), normalCaseFileName); if (!CheckFile(fullFileName, requiredEntry.Value)) { modCheckOk = false; DarkLog.Debug("Required file " + requiredEntry.Key + " does not match hash " + requiredEntry.Value + "!"); sb.AppendLine("Required file " + requiredEntry.Key + " does not match hash " + requiredEntry.Value + "!"); continue; } } } else { //DLL entries are cached from startup. if (!dllList.ContainsKey(requiredEntry.Key)) { modCheckOk = false; DarkLog.Debug("Required file " + requiredEntry.Key + " is missing!"); sb.AppendLine("Required file " + requiredEntry.Key + " is missing!"); continue; } if (requiredEntry.Value != "") { if (dllList[requiredEntry.Key] != requiredEntry.Value) { modCheckOk = false; DarkLog.Debug("Required file " + requiredEntry.Key + " does not match hash " + requiredEntry.Value + "!"); sb.AppendLine("Required file " + requiredEntry.Key + " does not match hash " + requiredEntry.Value + "!"); continue; } } } } //Check Optional foreach (KeyValuePair <string, string> optionalEntry in parseOptional) { if (!optionalEntry.Key.EndsWith("dll")) { //Protect against windows-style entries in DMPModControl.txt. Also use case insensitive matching. if (!currentGameDataFilesLower.Contains(optionalEntry.Key)) { //File is optional, nothing to check if it doesn't exist. continue; } //If the entry has a SHA sum, we need to check it. if (optionalEntry.Value != "") { string normalCaseFileName = currentGameDataFilesNormal[currentGameDataFilesLower.IndexOf(optionalEntry.Key)]; string fullFileName = Path.Combine(Path.Combine(KSPUtil.ApplicationRootPath, "GameData"), normalCaseFileName); if (!CheckFile(fullFileName, optionalEntry.Value)) { modCheckOk = false; DarkLog.Debug("Optional file " + optionalEntry.Key + " does not match hash " + optionalEntry.Value + "!"); sb.AppendLine("Optional file " + optionalEntry.Key + " does not match hash " + optionalEntry.Value + "!"); continue; } } } else { //DLL entries are cached from startup. if (!dllList.ContainsKey(optionalEntry.Key)) { //File is optional, nothing to check if it doesn't exist. continue; } if (optionalEntry.Value != "") { if (dllList[optionalEntry.Key] != optionalEntry.Value) { modCheckOk = false; DarkLog.Debug("Optional file " + optionalEntry.Key + " does not match hash " + optionalEntry.Value + "!"); sb.AppendLine("Optional file " + optionalEntry.Key + " does not match hash " + optionalEntry.Value + "!"); continue; } } } } if (isWhiteList) { //Check Resource whitelist List <string> autoAllowed = new List <string>(); autoAllowed.Add("darkmultiplayer/plugins/darkmultiplayer.dll"); autoAllowed.Add("darkmultiplayer/plugins/darkmultiplayer-common.dll"); autoAllowed.Add("darkmultiplayer/plugins/messagewriter.dll"); foreach (KeyValuePair <string, string> dllResource in dllList) { //Allow DMP files if (autoAllowed.Contains(dllResource.Key)) { continue; } //Check required (Required implies whitelist) if (parseRequired.ContainsKey(dllResource.Key)) { continue; } //Check optional (Optional implies whitelist) if (parseOptional.ContainsKey(dllResource.Key)) { continue; } //Check whitelist if (parseWhiteBlackList.Contains(dllResource.Key)) { continue; } modCheckOk = false; DarkLog.Debug("Non-whitelisted resource " + dllResource.Key + " exists on client!"); sb.AppendLine("Non-whitelisted resource " + dllResource.Key + " exists on client!"); } } else { //Check Resource blacklist foreach (string blacklistEntry in parseWhiteBlackList) { if (dllList.ContainsKey(blacklistEntry.ToLowerInvariant())) { modCheckOk = false; DarkLog.Debug("Banned resource " + blacklistEntry + " exists on client!"); sb.AppendLine("Banned resource " + blacklistEntry + " exists on client!"); } } } if (!modCheckOk) { failText = sb.ToString(); ModWindow.fetch.display = true; return(false); } allowedParts = parsePartsList; DarkLog.Debug("Mod check passed!"); return(true); }
public void GenerateModControlFile(bool whitelistMode) { string gameDataDir = Path.Combine(KSPUtil.ApplicationRootPath, "GameData"); string[] topLevelFiles = Directory.GetFiles(gameDataDir); string[] modDirectories = Directory.GetDirectories(gameDataDir); List <string> requiredFiles = new List <string>(); List <string> optionalFiles = new List <string>(); List <string> partsList = Common.GetStockParts(); //If whitelisting, add top level dll's to required (It's usually things like modulemanager) foreach (string dllFile in topLevelFiles) { if (Path.GetExtension(dllFile).ToLower() == ".dll") { requiredFiles.Add(Path.GetFileName(dllFile)); } } foreach (string modDirectory in modDirectories) { string lowerDirectoryName = modDirectory.Substring(modDirectory.ToLower().IndexOf("gamedata") + 9).ToLower(); if (lowerDirectoryName.StartsWith("squad")) { continue; } if (lowerDirectoryName.StartsWith("nasamission")) { continue; } if (lowerDirectoryName.StartsWith("darkmultiplayer")) { continue; } bool modIsRequired = false; string[] partFiles = Directory.GetFiles(Path.Combine(gameDataDir, modDirectory), "*", SearchOption.AllDirectories); List <string> modDllFiles = new List <string>(); List <string> modPartCfgFiles = new List <string>(); foreach (string partFile in partFiles) { bool fileIsPartFile = false; string relativeFileName = partFile.Substring(partFile.ToLower().IndexOf("gamedata") + 9).Replace(@"\", "/"); if (Path.GetExtension(partFile).ToLower() == ".cfg") { ConfigNode cn = ConfigNode.Load(partFile); if (cn == null) { continue; } foreach (ConfigNode partNode in cn.GetNodes("PART")) { string partName = partNode.GetValue("name"); if (partName != null) { DarkLog.Debug("Part detected in " + relativeFileName + " , name: " + partName); partName = partName.Replace('_', '.'); modIsRequired = true; fileIsPartFile = true; partsList.Add(partName); } } } if (fileIsPartFile) { modPartCfgFiles.Add(relativeFileName); } if (Path.GetExtension(partFile).ToLower() == ".dll") { modDllFiles.Add(relativeFileName); } } if (modIsRequired) { if (modDllFiles.Count > 0) { //If the mod as a plugin, just require that. It's clear enough. requiredFiles.AddRange(modDllFiles); } else { //If the mod does *not* have a plugin (Scoop-o-matic is an example), add the part files to required instead. requiredFiles.AddRange(modPartCfgFiles); } } else { if (whitelistMode) { optionalFiles.AddRange(modDllFiles); } } } string modFileData = Common.GenerateModFileStringData(requiredFiles.ToArray(), optionalFiles.ToArray(), whitelistMode, new string[0], partsList.ToArray()); string saveModFile = Path.Combine(KSPUtil.ApplicationRootPath, "DMPModControl.txt"); using (StreamWriter sw = new StreamWriter(saveModFile, false)) { sw.Write(modFileData); } ScreenMessages.PostScreenMessage("DMPModFile.txt file generated in your KSP folder", 5f, ScreenMessageStyle.UPPER_CENTER); }