/// <summary> /// Patches the scenario file with reputation data /// </summary> private static string UpdateScenarioWithTechnologyData(string scenarioData, TechNodeInfo techNode) { var document = new XmlDocument(); document.LoadXml(scenarioData); var configNodeData = Encoding.UTF8.GetString(techNode.Data, 0, techNode.NumBytes); var newNodeDoc = new XmlDocument(); newNodeDoc.LoadXml(ConfigNodeXmlParser.ConvertToXml(configNodeData)); var parentNode = document.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}"); if (parentNode != null) { var newTechXmlNode = newNodeDoc.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}/{ConfigNodeXmlParser.ParentNode}[@name='Tech']"); if (newTechXmlNode != null) { var importNode = document.ImportNode(newTechXmlNode, true); parentNode.AppendChild(importNode); } } return(document.ToIndentedString()); }
/// <summary> /// Raw updates a vessel in the dictionary and takes care of the locking in case we received another vessel message type /// </summary> public static void RawConfigNodeInsertOrUpdate(Guid vesselId, string vesselDataInConfigNodeFormat) { Task.Run(() => { lock (Semaphore.GetOrAdd(vesselId, new object())) { var vesselAsXml = ConfigNodeXmlParser.ConvertToXml(vesselDataInConfigNodeFormat); if (GeneralSettings.SettingsStore.ModControl) { var vesselParts = GetPartNames(vesselAsXml); if (vesselParts != null) { var bannedParts = vesselParts.Except(ModFileSystem.ModControl.AllowedParts); if (bannedParts.Any()) { LunaLog.Warning($"Received a vessel with BANNED parts! {vesselId}"); return; } } } VesselStoreSystem.CurrentVesselsInXmlFormat.AddOrUpdate(vesselId, vesselAsXml, (key, existingVal) => vesselAsXml); } }); }
/// <summary> /// Patches the scenario file with strategy data /// </summary> private static string UpdateScenarioWithStrategyData(string scenarioData, StrategyInfo strategy) { var document = new XmlDocument(); document.LoadXml(scenarioData); var strategiesList = document.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}/{ConfigNodeXmlParser.ParentNode}[@name='STRATEGIES']"); if (strategiesList != null) { var receivedStrategy = DeserializeAndImportNode(strategy.Data, strategy.NumBytes, document); if (receivedStrategy != null) { var existingStrategy = strategiesList.SelectSingleNode($"{ConfigNodeXmlParser.ParentNode}[@name='STRATEGY']/" + $@"{ConfigNodeXmlParser.ValueNode}[@name='name' and text()=""{strategy.Name}""]/" + $"parent::{ConfigNodeXmlParser.ParentNode}[@name='STRATEGY']"); if (existingStrategy != null) { //Replace the existing stragegy value with the received one existingStrategy.InnerXml = receivedStrategy.InnerXml; } else { var newStrategyNode = ConfigNodeXmlParser.CreateXmlNode("STRATEGY", document); newStrategyNode.InnerXml = receivedStrategy.InnerXml; strategiesList.AppendChild(newStrategyNode); } } } return(document.ToIndentedString()); }
private static XmlNode DeserializeAndImportNode(byte[] data, int numBytes, XmlDocument docToImportTo) { var auxDoc = new XmlDocument(); auxDoc.LoadXml(ConfigNodeXmlParser.ConvertToXml(Encoding.UTF8.GetString(data, 0, numBytes))); var newXmlNode = auxDoc.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}"); return(newXmlNode == null ? null : docToImportTo.ImportNode(newXmlNode, true)); }
/// <summary> /// Raw updates a scenario in the dictionary /// </summary> public static void RawConfigNodeInsertOrUpdate(string scenarioModule, string scenarioDataInConfigNodeFormat) { Task.Run(() => { lock (Semaphore.GetOrAdd(scenarioModule, new object())) { var scenarioAsXml = ConfigNodeXmlParser.ConvertToXml(scenarioDataInConfigNodeFormat); ScenarioStoreSystem.CurrentScenariosInXmlFormat.AddOrUpdate(scenarioModule, scenarioAsXml, (key, existingVal) => scenarioAsXml); } }); }
/// <summary> /// Raw updates a vessel in the dictionary and takes care of the locking in case we received another vessel message type /// </summary> public static void RawConfigNodeInsertOrUpdate(Guid vesselId, string vesselDataInConfigNodeFormat) { Task.Run(() => { lock (Semaphore.GetOrAdd(vesselId, new object())) { var vesselAsXml = ConfigNodeXmlParser.ConvertToXml(vesselDataInConfigNodeFormat); VesselStoreSystem.CurrentVesselsInXmlFormat.AddOrUpdate(vesselId, vesselAsXml, (key, existingVal) => vesselAsXml); } }); }
private static void SwitchToXmlAndBack(string filePath) { if (!File.Exists(filePath)) { return; } var configNode = File.ReadAllText(filePath); var xml = ConfigNodeXmlParser.ConvertToXml(configNode); var backToConfigNode = ConfigNodeXmlParser.ConvertToConfigNode(xml); Assert.IsTrue(configNode.Equals(backToConfigNode), $"Error serializing config node. File: {Path.GetFileName(filePath)}"); }
/// <summary> /// Patches the scenario file with reputation data /// </summary> private static string UpdateScenarioWithTechnologyData(string scenarioData, TechNodeInfo techNode) { var document = new XmlDocument(); document.LoadXml(scenarioData); var configNodeData = Encoding.UTF8.GetString(techNode.Data, 0, techNode.NumBytes); var newNodeDoc = new XmlDocument(); newNodeDoc.LoadXml(ConfigNodeXmlParser.ConvertToXml(configNodeData)); var parentNode = document.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}"); if (parentNode != null) { var newTechXmlNode = newNodeDoc.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}/{ConfigNodeXmlParser.ParentNode}[@name='Tech']"); if (newTechXmlNode != null) { var existingNode = parentNode.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}/{ConfigNodeXmlParser.ParentNode}[@name='Tech']" + $@"/{ConfigNodeXmlParser.ValueNode}[@name='id' and text()=""{techNode.Id}""]" + $"/parent::{ConfigNodeXmlParser.ParentNode}[@name='Tech']"); if (existingNode != null) { var parts = newTechXmlNode.SelectNodes($"{ConfigNodeXmlParser.ValueNode}[@name='part']"); if (parts != null) { foreach (var part in parts.Cast <XmlNode>()) { var existingPart = existingNode.SelectSingleNode($@"{ConfigNodeXmlParser.ValueNode}[@name='part' and text()=""{part.InnerText}""]"); if (existingPart == null) { var importNode = document.ImportNode(part, true); existingNode.AppendChild(importNode); } } } } else { var importNode = document.ImportNode(newTechXmlNode, true); parentNode.AppendChild(importNode); } } } return(document.ToIndentedString()); }
/// <summary> /// Patches the scenario file with part purchase data /// </summary> private static string UpdateScenarioWithPartPurchaseData(string scenarioData, string techId, string partName) { var document = new XmlDocument(); document.LoadXml(scenarioData); var techNode = document.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}/{ConfigNodeXmlParser.ParentNode}[@name='Tech']" + $@"/{ConfigNodeXmlParser.ValueNode}[@name='id' and text()=""{techId}""]" + $"/parent::{ConfigNodeXmlParser.ParentNode}[@name='Tech']"); if (techNode != null) { var newPart = ConfigNodeXmlParser.CreateXmlParameter("part", document); newPart.InnerXml = partName; techNode.AppendChild(newPart); } return(document.ToIndentedString()); }
/// <summary> /// Patches the scenario file with reputation data /// </summary> private static string UpdateScenarioWithContractData(string scenarioData, ContractInfo[] contracts) { var document = new XmlDocument(); document.LoadXml(scenarioData); var contractsList = document.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}/{ConfigNodeXmlParser.ParentNode}[@name='CONTRACTS']"); if (contractsList != null) { foreach (var contract in contracts) { var receivedContract = DeserializeAndImportNode(contract.Data, contract.NumBytes, document); if (receivedContract == null) { continue; } var existingContract = contractsList.SelectSingleNode($"{ConfigNodeXmlParser.ParentNode}[@name='CONTRACT']/" + $@"{ConfigNodeXmlParser.ValueNode}[@name='guid' and text()=""{contract.ContractGuid}""]/" + $"parent::{ConfigNodeXmlParser.ParentNode}[@name='CONTRACT']"); if (existingContract != null) { //Replace the existing contract values with the received one existingContract.InnerXml = receivedContract.InnerXml; } else { var newContractNode = ConfigNodeXmlParser.CreateXmlNode("CONTRACT", document); newContractNode.InnerXml = receivedContract.InnerXml; contractsList.AppendChild(newContractNode); } } } return(document.ToIndentedString()); }
/// <summary> /// Patches the scenario file with achievement data /// </summary> private static string UpdateScenarioWithAchievementData(string scenarioData, AchievementInfo[] achievements) { var document = new XmlDocument(); document.LoadXml(scenarioData); var progressList = document.SelectSingleNode($"/{ConfigNodeXmlParser.StartElement}/{ConfigNodeXmlParser.ParentNode}[@name='Progress']"); if (progressList != null) { foreach (var achievement in achievements) { var receivedAchievementXmlNode = DeserializeAndImportNode(achievement.Data, achievement.NumBytes, document); if (receivedAchievementXmlNode == null) { continue; } var existingAchievement = progressList.SelectSingleNode($"{ConfigNodeXmlParser.ParentNode}[@name='{achievement.Id}']"); if (existingAchievement != null) { //Replace the existing contract values with the received one existingAchievement.InnerXml = receivedAchievementXmlNode.InnerXml; } else { var newAchievement = ConfigNodeXmlParser.CreateXmlNode(achievement.Id, document); newAchievement.InnerXml = receivedAchievementXmlNode.InnerXml; progressList.AppendChild(newAchievement); } } } return(document.ToIndentedString()); }
/// <summary> /// Returns a XML vessel in the standard KSP format /// </summary> public static string GetVesselInConfigNodeFormat(Guid vesselId) { return(CurrentVesselsInXmlFormat.TryGetValue(vesselId, out var vesselInXmlFormat) ? ConfigNodeXmlParser.ConvertToConfigNode(vesselInXmlFormat) : null); }
public static void GenerateUniverse(string saveName) { var universeFolder = CommonUtil.CombinePaths(MainSystem.KspPath, "Universe"); if (Directory.Exists(universeFolder)) { Directory.Delete(universeFolder, true); } var saveFolder = CommonUtil.CombinePaths(SavesFolder, saveName); if (!Directory.Exists(saveFolder)) { LunaLog.Log($"[LMP]: Failed to generate a LMP universe for '{saveName}', Save directory doesn't exist"); LunaScreenMsg.PostScreenMessage($"Failed to generate a LMP universe for '{saveName}', Save directory doesn't exist", 5f, ScreenMessageStyle.UPPER_CENTER); return; } var persistentFile = CommonUtil.CombinePaths(saveFolder, "persistent.sfs"); if (!File.Exists(persistentFile)) { LunaLog.Log($"[LMP]: Failed to generate a LMP universe for '{saveName}', persistent.sfs doesn't exist"); LunaScreenMsg.PostScreenMessage($"Failed to generate a LMP universe for '{saveName}', persistent.sfs doesn't exist", 5f, ScreenMessageStyle.UPPER_CENTER); return; } Directory.CreateDirectory(universeFolder); var vesselFolder = CommonUtil.CombinePaths(universeFolder, "Vessels"); Directory.CreateDirectory(vesselFolder); var scenarioFolder = CommonUtil.CombinePaths(universeFolder, "Scenarios"); Directory.CreateDirectory(scenarioFolder); var kerbalFolder = CommonUtil.CombinePaths(universeFolder, "Kerbals"); Directory.CreateDirectory(kerbalFolder); //Load game data var persistentData = ConfigNode.Load(persistentFile); if (persistentData == null) { LunaLog.Log($"[LMP]: Failed to generate a LMP universe for '{saveName}', failed to load persistent data"); LunaScreenMsg.PostScreenMessage($"Failed to generate a LMP universe for '{saveName}', failed to load persistent data", 5f, ScreenMessageStyle.UPPER_CENTER); return; } var gameData = persistentData.GetNode("GAME"); if (gameData == null) { LunaLog.Log($"[LMP]: Failed to generate a LMP universe for '{saveName}', failed to load game data"); LunaScreenMsg.PostScreenMessage($"Failed to generate a LMP universe for '{saveName}', failed to load game data", 5f, ScreenMessageStyle.UPPER_CENTER); return; } //Save vessels var flightState = gameData.GetNode("FLIGHTSTATE"); if (flightState == null) { LunaLog.Log($"[LMP]: Failed to generate a LMP universe for '{saveName}', failed to load flight state data"); LunaScreenMsg.PostScreenMessage($"Failed to generate a LMP universe for '{saveName}', failed to load flight state data", 5f, ScreenMessageStyle.UPPER_CENTER); return; } var vesselNodes = flightState.GetNodes("VESSEL"); if (vesselNodes != null) { foreach (var cn in vesselNodes) { var vesselId = Common.ConvertConfigStringToGuidString(cn.GetValue("pid")); LunaLog.Log($"[LMP]: Saving vessel {vesselId}, Name: {cn.GetValue("name")}"); var xmlData = ConfigNodeXmlParser.ConvertToXml(Encoding.UTF8.GetString(ConfigNodeSerializer.Serialize(cn))); File.WriteAllText(CommonUtil.CombinePaths(vesselFolder, $"{vesselId}.xml"), xmlData); } } //Save scenario data var scenarioNodes = gameData.GetNodes("SCENARIO"); if (scenarioNodes != null) { foreach (var cn in scenarioNodes) { var scenarioName = cn.GetValue("name"); if (string.IsNullOrEmpty(scenarioName)) { continue; } LunaLog.Log($"[LMP]: Saving scenario: {scenarioName}"); var xmlData = ConfigNodeXmlParser.ConvertToXml(Encoding.UTF8.GetString(ConfigNodeSerializer.Serialize(cn))); File.WriteAllText(CommonUtil.CombinePaths(scenarioFolder, $"{scenarioName}.xml"), xmlData); } } //Save kerbal data var kerbalNodes = gameData.GetNode("ROSTER").GetNodes("KERBAL"); if (kerbalNodes != null) { foreach (var cn in kerbalNodes) { var kerbalName = cn.GetValue("name"); LunaLog.Log($"[LMP]: Saving kerbal: {kerbalName}"); cn.Save(CommonUtil.CombinePaths(kerbalFolder, $"{kerbalName}.txt")); } } LunaLog.Log($"[LMP]: Generated KSP_folder/Universe from {saveName}"); LunaScreenMsg.PostScreenMessage($"Generated KSP_folder/Universe from {saveName}", 5f, ScreenMessageStyle.UPPER_CENTER); }
/// <summary> /// Returns a XML scenario in the standard KSP format /// </summary> public static string GetScenarioInConfigNodeFormat(string scenarioName) { return(CurrentScenariosInXmlFormat.TryGetValue(scenarioName, out var scenarioInXmlFormat) ? ConfigNodeXmlParser.ConvertToConfigNode(scenarioInXmlFormat) : null); }