//Load local RICO settings. public void LocalSettings() { try { PloppableRICODefinition localSettings = null; var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); using (StreamReader streamReader = new System.IO.StreamReader("LocalRICOSettings.xml")) { localSettings = xmlSerializer.Deserialize(streamReader) as PloppableRICODefinition; } foreach (var buildingDef in localSettings.Buildings) { if (PrefabCollection <BuildingInfo> .FindLoaded(buildingDef.name) != null) { var buildingPrefab = PrefabCollection <BuildingInfo> .FindLoaded(buildingDef.name); if (buildingPrefab != null) { //Add local RICO settings to dictionary var local = new PloppableRICODefinition.Building(); local = buildingDef; xmlData[buildingPrefab].local = local; xmlData[buildingPrefab].hasLocal = true; } } } } catch (Exception e) { Debug.LogException(e); } }
/// <summary> /// Saves the current RICO settings to file. /// </summary> private void Save() { // Read current settings from UI elements and convert to XML. SettingsPanel.Panel.Save(); // If the local settings file doesn't already exist, create a new blank template. if (!File.Exists("LocalRICOSettings.xml")) { PloppableRICODefinition newLocalSettings = new PloppableRICODefinition(); XmlSerializer xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); // Create blank file template. using (XmlWriter writer = XmlWriter.Create("LocalRICOSettings.xml")) { xmlSerializer.Serialize(writer, newLocalSettings); } } // Check that file exists before continuing (it really should at this point, but just in case). if (File.Exists("LocalRICOSettings.xml")) { PloppableRICODefinition oldLocalSettings; PloppableRICODefinition newLocalSettings = new PloppableRICODefinition(); XmlSerializer xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); // Read existing file. using (StreamReader streamReader = new StreamReader("LocalRICOSettings.xml")) { oldLocalSettings = xmlSerializer.Deserialize(streamReader) as PloppableRICODefinition; } // Loop though all buildings in the existing file. If they aren't the current selection, write them back to the replacement file. foreach (RICOBuilding buildingDef in oldLocalSettings.Buildings) { if (buildingDef.Name != currentSelection.name) { newLocalSettings.Buildings.Add(buildingDef); } } // If current selection has local settings, add them to the replacement file. if (currentSelection.hasLocal) { newLocalSettings.Buildings.Add(currentSelection.local); } // Write replacement file to disk. using (TextWriter writer = new StreamWriter("LocalRICOSettings.xml")) { xmlSerializer.Serialize(writer, newLocalSettings); } } else { Logging.Error("couldn't find local settings file to save"); } // Force an update of all panels with current values. SettingsPanel.Panel.UpdateSelectedBuilding(currentSelection); }
//This is called by the settings panel. It will serialize any new local settings the player sets in game. public static void SaveLocal(PloppableRICODefinition.Building newBuildingData) { Debug.Log("SaveLocal"); if (File.Exists("LocalRICOSettings.xml") && newBuildingData != null) { PloppableRICODefinition localSettings = null; var newlocalSettings = new PloppableRICODefinition(); var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); using (StreamReader streamReader = new System.IO.StreamReader("LocalRICOSettings.xml")) { localSettings = xmlSerializer.Deserialize(streamReader) as PloppableRICODefinition; } foreach (var buildingDef in localSettings.Buildings) { if (buildingDef.name != newBuildingData.name) { newlocalSettings.Buildings.Add(buildingDef); } } //newBuildingData.name = newBuildingData.name; newlocalSettings.Buildings.Add(newBuildingData); using (TextWriter writer = new StreamWriter("LocalRICOSettings.xml")) { xmlSerializer.Serialize(writer, newlocalSettings); } } }
private static void addCrpShit(PloppableRICODefinition ricoDef) { var crpPath = Util.crpFileIn(ricoDef.sourceFile.Directory); if (crpPath != null) { foreach (var building in ricoDef.Buildings) { building.crpData = crpDataProvider.getCrpData(crpPath.FullName); } } }
public static string ricoDataXml(PloppableRICODefinition RicoDefinition) { try { var ms = new MemoryStream(); var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); xmlSerializer.Serialize(ms, RicoDefinition); ms.Seek(0, SeekOrigin.Begin); return(ms.ToString()); } catch { } return(""); }
public static bool saveRicoData(string fileName, PloppableRICODefinition RicoDefinition) { try { var streamWriter = new System.IO.StreamWriter(fileName); var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); xmlSerializer.Serialize(streamWriter, RicoDefinition); streamWriter.Close(); return(true); } catch { } return(false); }
public void Save() { RICOSettingsPanel.instance.Save(); if (!File.Exists("LocalRICOSettings.xml")) { var newlocalSettings = new PloppableRICODefinition(); var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); using (XmlWriter writer = XmlWriter.Create("LocalRICOSettings.xml")) { xmlSerializer.Serialize(writer, newlocalSettings); } } if (File.Exists("LocalRICOSettings.xml")) { PloppableRICODefinition localSettings; var newlocalSettings = new PloppableRICODefinition(); var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); using (StreamReader streamReader = new System.IO.StreamReader("LocalRICOSettings.xml")) { localSettings = xmlSerializer.Deserialize(streamReader) as PloppableRICODefinition; } //Loop though all buildings in the file. If they arent the current selection, write them back to file. foreach (var buildingDef in localSettings.Buildings) { if (buildingDef.name != currentSelection.name) { newlocalSettings.Buildings.Add(buildingDef); } } //If current selection has local settings, add them to file. if (currentSelection.hasLocal) { newlocalSettings.Buildings.Add(currentSelection.local); } using (TextWriter writer = new StreamWriter("LocalRICOSettings.xml")) { xmlSerializer.Serialize(writer, newlocalSettings); } } }
//Load settings from settings mods. (Currently disabled) public void ModSettings() { var workshopModSettingsPath = Path.Combine(Util.SettingsModPath("629850626"), "WorkshopRICOSettings.xml"); var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); PloppableRICODefinition workshopSettings = null; using (StreamReader streamReader = new System.IO.StreamReader(workshopModSettingsPath)) { workshopSettings = xmlSerializer.Deserialize(streamReader) as PloppableRICODefinition; } foreach (var buildingDef in workshopSettings.Buildings) { if (PrefabCollection <BuildingInfo> .FindLoaded(buildingDef.name) != null) { var buildingPrefab = PrefabCollection <BuildingInfo> .FindLoaded(buildingDef.name); //Add settings mod settings here } } }
/// <summary> /// Called by the game when the mod is initialised at the start of the loading process. /// </summary> /// <param name="loading">Loading mode (e.g. game, editor, scenario, etc.)</param> public override void OnCreated(ILoading loading) { base.OnCreated(loading); // Don't do anything if not in game (e.g. if we're going into an editor). if (loading.currentMode != AppMode.Game) { isModEnabled = false; Logging.KeyMessage("not loading into game, skipping activation"); // Set harmonyLoaded flag to suppress Harmony warning when e.g. loading into editor. harmonyLoaded = true; // Unload Harmony patches and exit before doing anything further. Patcher.UnpatchAll(); return; } // Ensure that Harmony patches have been applied. harmonyLoaded = Patcher.Patched; if (!harmonyLoaded) { isModEnabled = false; Logging.Error("Harmony patches not applied; aborting"); return; } // Check for mod conflicts. if (ModUtils.IsModConflict()) { // Conflict detected. conflictingMod = true; isModEnabled = false; // Unload Harmony patches and exit before doing anything further. Patcher.UnpatchAll(); return; } // Passed all checks - okay to load (if we haven't already fo some reason). if (!isModEnabled) { isModEnabled = true; Logging.KeyMessage("v " + PloppableRICOMod.Version + " loading"); // Check for other mods, including any soft conflicts. softModConflct = ModUtils.CheckMods(); // Check for Advanced Building Level Control. ModUtils.ABLCReflection(); // Create instances if they don't already exist. if (convertPrefabs == null) { convertPrefabs = new ConvertPrefabs(); } if (xmlManager == null) { xmlManager = new RICOPrefabManager { prefabHash = new Dictionary <BuildingInfo, BuildingData>(), }; } // Reset broken prefabs list. brokenPrefabs = new List <BuildingInfo>(); // Read any local RICO settings. string ricoDefPath = "LocalRICOSettings.xml"; localRicoDef = null; if (!File.Exists(ricoDefPath)) { Logging.Message("no ", ricoDefPath, " file found"); } else { localRicoDef = RICOReader.ParseRICODefinition(ricoDefPath, isLocal: true); if (localRicoDef == null) { Logging.Message("no valid definitions in ", ricoDefPath); } } } }
/// <summary> /// Called by the game when the mod is initialised at the start of the loading process. /// </summary> /// <param name="loading">Loading mode (e.g. game, editor, scenario, etc.)</param> public override void OnCreated(ILoading loading) { // Don't do anything if not in game (e.g. if we're going into an editor). if (loading.currentMode != AppMode.Game) { isModEnabled = false; Debugging.Message("not loading into game, skipping activation"); } else { // Check for conflicting (and other) mods. isModEnabled = ModUtils.CheckMods(); } // If we're not enabling the mod due to one of the above checks failing, unapply Harmony patches before returning without doing anything. if (!isModEnabled) { Patcher.UnpatchAll(); return; } // Make sure patches have been applied before proceeding. if (!Patcher.Patched) { Debugging.Message("Harmony patches not applied, exiting"); isModEnabled = false; return; } // Otherwise, game on! Debugging.Message("v" + PloppableRICOMod.Version + " loading"); // Ensure patch watchdog flag is properly initialised. patchOperating = false; // Create instances if they don't already exist. if (convertPrefabs == null) { convertPrefabs = new ConvertPrefabs(); } if (xmlManager == null) { xmlManager = new RICOPrefabManager { prefabHash = new Dictionary <BuildingInfo, BuildingData>(), prefabList = new List <BuildingData>() }; } // Read mod settings. SettingsFile settingsFile = Configuration <SettingsFile> .Load(); Settings.plainThumbs = settingsFile.PlainThumbs; Settings.debugLogging = settingsFile.DebugLogging; Settings.resetOnLoad = settingsFile.ResetOnLoad; // Read any local RICO settings. string ricoDefPath = "LocalRICOSettings.xml"; localRicoDef = null; if (!File.Exists(ricoDefPath)) { Debugging.Message("no " + ricoDefPath + " file found"); } else { localRicoDef = RICOReader.ParseRICODefinition("", ricoDefPath, insanityOK: true); if (localRicoDef == null) { Debugging.Message("no valid definitions in " + ricoDefPath); } } base.OnCreated(loading); }
public static bool Prefix(BuildingInfo __instance) { // Basic sanity check before proceeding; if failed, don't do anything here - just continue on to game method. if (__instance.name == null) { return(true); } // Create a new building record for this prefab and add it to our lists. BuildingData buildingData = new BuildingData { prefab = __instance, name = __instance.name, density = Loading.xmlManager.SetPrefabDensity(__instance), category = Loading.xmlManager.AssignCategory(__instance), }; Loading.xmlManager.prefabHash[__instance] = buildingData; // Add to broken prefabs list (will be removed later if it's not broken). Loading.brokenPrefabs.Add(__instance); // Search for PloppableRICODefinition.xml files with this asset. // Need to use FindAssetByName(string, AssetType) because FindAssetByName(string) doesn't catch all assets at this stage of initialisation // (those two methods are more different than you might think - discovered that the hard way). Package.Asset asset = PackageManager.FindAssetByName(__instance.name, Package.AssetType.Object); // Get custom asset filesystem location (if CRP pacakge). string crpPath = asset?.package?.packagePath; if (!string.IsNullOrEmpty(crpPath)) { // Look for RICO settings file. string ricoDefPath = Path.Combine(Path.GetDirectoryName(crpPath), "PloppableRICODefinition.xml"); if (File.Exists(ricoDefPath)) { // Parse the file. PloppableRICODefinition tempRicoDef = RICOReader.ParseRICODefinition(ricoDefPath); if (tempRicoDef != null) { foreach (RICOBuilding buildingDef in tempRicoDef.Buildings) { // Go through each building parsed and check to see if we've got a match for this prefab. if (MatchRICOName(buildingDef.Name, __instance.name, asset.package.packageName)) { // Match! Add these author settings to our prefab dictionary. Logging.Message("found author settings for ", buildingDef.Name); Loading.xmlManager.prefabHash[__instance].author = buildingDef; Loading.xmlManager.prefabHash[__instance].hasAuthor = true; } } } } } // Check for and add any local settings for this prefab to our list. if (Loading.localRicoDef != null) { // Step through our previously loaded local settings and see if we've got a match. foreach (RICOBuilding buildingDef in Loading.localRicoDef.Buildings) { if (buildingDef.Name.Equals(__instance.name)) { // Match! Add these author settings to our prefab dictionary. Loading.xmlManager.prefabHash[__instance].local = buildingDef; Loading.xmlManager.prefabHash[__instance].hasLocal = true; } } } // Check for any Workshop RICO mod settings for this prefab. if (Loading.mod1RicoDef != null) { // Step through our previously loaded local settings and see if we've got a match. foreach (RICOBuilding buildingDef in Loading.mod1RicoDef.Buildings) { if (buildingDef.Name.Equals(__instance.name)) { // Match! Add these author settings to our prefab dictionary. Loading.xmlManager.prefabHash[__instance].mod = buildingDef; Loading.xmlManager.prefabHash[__instance].hasMod = true; } } } // Check for Modern Japan CCP mod settings for this prefab. if (Loading.mod2RicoDef != null) { // Step through our previously loaded local settings and see if we've got a match. foreach (RICOBuilding buildingDef in Loading.mod2RicoDef.Buildings) { if (buildingDef.Name.Equals(__instance.name)) { // Match! Add these author settings to our prefab dictionary. Loading.xmlManager.prefabHash[__instance].mod = buildingDef; Loading.xmlManager.prefabHash[__instance].hasMod = true; } } } // Apply appropriate RICO settings to prefab. if (Loading.convertPrefabs != null) { // Start with local settings. if (Loading.xmlManager.prefabHash[__instance].hasLocal) { // If local settings disable RICO, dont convert. if (Loading.xmlManager.prefabHash[__instance].local.ricoEnabled) { Loading.convertPrefabs.ConvertPrefab(Loading.xmlManager.prefabHash[__instance].local, __instance); } } // If no local settings, apply author settings. else if (Loading.xmlManager.prefabHash[__instance].hasAuthor) { // If author settings disable RICO, dont convert. if (Loading.xmlManager.prefabHash[__instance].author.ricoEnabled) { Loading.convertPrefabs.ConvertPrefab(Loading.xmlManager.prefabHash[__instance].author, __instance); } } // If none of the above, apply mod settings. else if (Loading.xmlManager.prefabHash[__instance].hasMod) { // If mod settings disable RICO, dont convert. if (Loading.xmlManager.prefabHash[__instance].mod.ricoEnabled) { Loading.convertPrefabs.ConvertPrefab(Loading.xmlManager.prefabHash[__instance].mod, __instance); } } else { // No RICO settings; replicate game InitializePrefab checks overridden by transpiler. int privateServiceIndex = ItemClass.GetPrivateServiceIndex(__instance.m_class.m_service); if (privateServiceIndex != -1) { if (__instance.m_placementStyle == ItemClass.Placement.Manual) { throw new PrefabException(__instance, "Private building cannot have manual placement style"); } if (__instance.m_paths != null && __instance.m_paths.Length != 0) { throw new PrefabException(__instance, "Private building cannot include roads or other net types"); } } } } else { // This means that there's been a significant failure. Ploppable RICO settings can't be applied. Logging.Error("convertPrefabs not initialised"); } // Continue on to execute game InitializePrefab. return(true); }
//Load RICO Settings from asset folders public void AssetSettings() { var ricoDefParseErrors = new HashSet <string>(); var checkedPaths = new List <string>(); for (uint i = 0; i < PrefabCollection <BuildingInfo> .LoadedCount(); i++) { var prefab = PrefabCollection <BuildingInfo> .GetLoaded(i); if (prefab == null) { continue; } // search for PloppableRICODefinition.xml var asset = PackageManager.FindAssetByName(prefab.name); if (asset == null || asset.package == null) { continue; } var crpPath = asset.package.packagePath; if (crpPath == null) { continue; } var ricoDefPath = Path.Combine(Path.GetDirectoryName(crpPath), "PloppableRICODefinition.xml"); // skip files which were already parsed if (checkedPaths.Contains(ricoDefPath)) { continue; } checkedPaths.Add(ricoDefPath); if (!File.Exists(ricoDefPath)) { continue; } PloppableRICODefinition ricoDef = null; var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); try { using (StreamReader streamReader = new System.IO.StreamReader(ricoDefPath)) { ricoDef = xmlSerializer.Deserialize(streamReader) as PloppableRICODefinition; } } catch (Exception e) { Debug.LogException(e); ricoDefParseErrors.Add(asset.package.packageName + " - " + e.Message); continue; } if (ricoDef == null || ricoDef.Buildings == null || ricoDef.Buildings.Count == 0) { ricoDefParseErrors.Add(asset.package.packageName + " - ricoDef is null or empty."); continue; } foreach (var buildingDef in ricoDef.Buildings) { if (buildingDef == null || buildingDef.name == null) { ricoDefParseErrors.Add(asset.package.packageName + " - Building name missing."); continue; } var buildingPrefab = FindPrefab(buildingDef.name, asset.package.packageName); if (buildingPrefab == null) { ricoDefParseErrors.Add(asset.package.packageName + " - Building with name " + buildingDef.name + " not loaded."); continue; } try { UnityEngine.Debug.Log($"data index: {buildingPrefab.m_prefabDataIndex}"); if (buildingPrefab != null) { //Add asset author settings to dictionary. var author = new PloppableRICODefinition.Building(); author = buildingDef; xmlData[buildingPrefab].author = author; xmlData[buildingPrefab].hasAuthor = true; } } catch (Exception e) { Debug.LogException(e); ricoDefParseErrors.Add(asset.package.packageName + " - " + e.Message); } } } if (ricoDefParseErrors.Count > 0) { var errorMessage = "Error while parsing Ploppable RICO definition file(s). Contact the author of the assets. \n" + "List of errors:\n"; foreach (var error in ricoDefParseErrors) { errorMessage += error + '\n'; } UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Ploppable RICO", errorMessage, true); } }
/// <summary> /// Loads and parses the given RICO file. /// </summary> /// <param name="ricoDefPath">Definition file path</param> /// <param name="isLocal">True if this is a local settings file, false for author settings file</param> /// <returns>Parsed Ploppable RICO definition file</returns> public static PloppableRICODefinition ParseRICODefinition(string ricoDefPath, bool isLocal = false) { // Local settings flag. string localOrAuthor = isLocal ? "local" : "author"; try { // Open file. using (StreamReader reader = new StreamReader(ricoDefPath)) { // Create new XML (de)serializer XmlAttributes attrs = new XmlAttributes(); XmlElementAttribute attr = new XmlElementAttribute { ElementName = "RICOBuilding", Type = typeof(RICOBuilding) }; XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides(); attrOverrides.Add(typeof(RICOBuilding), "Building", attrs); // Read XML. XmlSerializer xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition), attrOverrides); PloppableRICODefinition result = xmlSerializer.Deserialize(reader) as PloppableRICODefinition; StringBuilder errorList; if (result.Buildings.Count == 0) { Logging.Message("no parseable buildings in ", localOrAuthor, " XML settings file at ", ricoDefPath); } else { foreach (RICOBuilding building in result.Buildings) { // Check for fatal errors in each building. errorList = building.FatalErrors; if (errorList.Length == 0) { // No fatal errors; check for non-fatal errors. errorList = building.NonFatalErrors; if (errorList.Length != 0) { if (isLocal && building.ricoEnabled) { // Errors in local settings need to be reported, except for buildings that aren't activated in RICO (e.g. for when the user has de-activated a RICO builidng with issues). Logging.Error("non-fatal errors for building '", building.Name, "' in local settings:\r\n", errorList); } else { // Errors in other settings should be logged if verbose logging is enabled, but otherwise continue. Logging.Message("non-fatal errors for building '", building.Name, "' in author settings:\r\n", errorList); } } } else { // Fatal errors! Need to be reported direct to user and the building ignored. Logging.Error("fatal errors for building '", building.Name, "' in ", localOrAuthor, " settings:\r\n", errorList); } } } reader.Close(); return(result); } } catch (Exception e) { Logging.LogException(e, "Unexpected Exception while deserializing ", localOrAuthor, " RICO file at ", ricoDefPath); return(null); } }
void RicoSettings(Dictionary <string, string> foo, bool isLocal = false, bool isAuthored = false, bool isMod = false) { var allParseErrors = new List <string>(); foreach (var packageId in foo.Keys) { var ricoDefPath = foo[packageId]; if (!File.Exists(ricoDefPath)) { continue; } PloppableRICODefinition ricoDef = null; if (isLocal == true) { ricoDef = RICOReader.ParseRICODefinition(packageId, ricoDefPath, insanityOK: true); } else { ricoDef = RICOReader.ParseRICODefinition(packageId, ricoDefPath); } if (ricoDef != null) { //Debug.Log("RICO Def isnt null"); var j = 0; foreach (var buildingDef in ricoDef.Buildings) { j++; BuildingInfo prefab; prefab = Util.FindPrefab(buildingDef.name, packageId); if (prefab != null) { if (prefabHash.ContainsKey(prefab)) { if (isAuthored) { prefabHash[prefab].author = buildingDef; prefabHash[prefab].hasAuthor = true; } else if (isLocal) { prefabHash[prefab].local = buildingDef; prefabHash[prefab].hasLocal = true; } else if (isMod) { //Debug.Log(prefabHash[pf].name + " Has Mod"); prefabHash[prefab].mod = buildingDef; prefabHash[prefab].hasMod = true; } } allParseErrors.AddRange(ricoDef.errors); } } } else { allParseErrors.AddRange(RICOReader.LastErrors); } } if (allParseErrors.Count > 0) { var errorMessage = new StringBuilder(); foreach (var error in allParseErrors) { errorMessage.Append(error).Append('\n'); } UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Ploppable RICO", errorMessage.ToString(), true); } }
private void SetupControls() { save = UIUtils.CreateButton(this); save.text = "Save"; addLocal = UIUtils.CreateButton(this); addLocal.text = "Add Local"; addLocal.eventClick += (c, p) => { if (currentSelection.hasLocal == false) { var newlocal = new PloppableRICODefinition.Building(); currentSelection.hasLocal = true; currentSelection.local = newlocal; currentSelection.local.name = currentSelection.name; } }; removeLocal = UIUtils.CreateButton(this); removeLocal.text = "Remove Local"; save.eventClick += (c, p) => { //Serialize the new RICO settings. //XMLManager.SaveLocal(currentSelection.local); RICOSettingsPanel.instance.Save(); if (File.Exists("LocalRICOSettings.xml") && currentSelection.local != null) { PloppableRICODefinition localSettings; var newlocalSettings = new PloppableRICODefinition(); var xmlSerializer = new XmlSerializer(typeof(PloppableRICODefinition)); using (StreamReader streamReader = new System.IO.StreamReader("LocalRICOSettings.xml")) { localSettings = xmlSerializer.Deserialize(streamReader) as PloppableRICODefinition; } foreach (var buildingDef in localSettings.Buildings) { if (buildingDef.name != currentSelection.local.name) { newlocalSettings.Buildings.Add(buildingDef); } } //newBuildingData.name = newBuildingData.name; newlocalSettings.Buildings.Add(currentSelection.local); using (TextWriter writer = new StreamWriter("LocalRICOSettings.xml")) { xmlSerializer.Serialize(writer, newlocalSettings); } } }; reset = UIUtils.CreateButton(this); reset.text = "Reset"; }