/// <summary> /// Checks for known mod conflicts and function extenders. /// </summary> /// <returns>Whether or not Ploppable RICO should load</returns> internal static bool CheckMods() { // Check for conflicting mods. if (IsModEnabled(586012417ul)) { // Original Ploppable RICO mod detected. conflictingMod = true; Debugging.Message("Original Ploppable RICO detected - RICO Revisited exiting"); conflictMessage = Translations.Translate("PRR_CON_OPR") + " - " + Translations.Translate("PRR_CON_DWN") + "\r\n\r\n" + Translations.Translate("PRR_CON_ONE"); return(false); } else if (IsModInstalled("EnhancedBuildingCapacity")) { // Enhanced Building Capacity mod detected. conflictingMod = true; Debugging.Message("Enhanced Building Capacity mod detected - RICO Revisited exiting"); conflictMessage = Translations.Translate("PRR_CON_EBC") + " - " + Translations.Translate("PRR_CON_DWN") + "\r\n\r\n" + Translations.Translate("PRR_CON_ONE"); return(false); } else if (IsModInstalled("VanillaGarbageBinBlocker")) { // Garbage bin controller mod detected. conflictingMod = true; Debugging.Message("Garbage Bin Controller mod detected - RICO Revisited exiting"); conflictMessage = Translations.Translate("PRR_CON_GBC") + " - " + Translations.Translate("PRR_CON_DWN") + "\r\n\r\n" + Translations.Translate("PRR_CON_ONE"); return(false); } else if (IsModInstalled(1372431101ul)) { // Painter mod detected. conflictingMod = true; Debugging.Message("Painter detected - RICO Revisited exiting"); conflictMessage = Translations.Translate("PRR_CON_PTR") + " - " + Translations.Translate("PRR_CON_DWN") + "\r\n\r\n" + Translations.Translate("PRR_CON_PTR1"); return(false); } // No conflicts - now check for realistic population mods. realPopEnabled = (IsModInstalled("RealPopRevisited", true) || IsModInstalled("WG_BalancedPopMod", true)); // Check for Workshop RICO settings mod. if (IsModEnabled(629850626uL)) { Debugging.Message("found Workshop RICO settings mod"); Loading.mod1RicoDef = RICOReader.ParseRICODefinition("", Path.Combine(Util.SettingsModPath("629850626"), "WorkshopRICOSettings.xml"), false); } // Check for Ryuichi Kaminogi's "RICO Settings for Modern Japan CCP" Package modernJapanRICO = PackageManager.GetPackage("2035770233"); if (modernJapanRICO != null) { Debugging.Message("found RICO Settings for Modern Japan CCP"); Loading.mod2RicoDef = RICOReader.ParseRICODefinition("", Path.Combine(Path.GetDirectoryName(modernJapanRICO.packagePath), "PloppableRICODefinition.xml"), false); } return(true); }
/// <summary> /// Checks for known 'soft' mod conflicts and function extenders. /// </summary> /// <returns>Whether or not a soft mod conflict was detected</returns> internal static bool CheckMods() { // Initialise flag and list of conflicting mods. bool conflictDetected = false; conflictingModNames = new List <string>(); // No hard conflicts - check for 'soft' conflicts. if (IsPtGInstalled()) { conflictDetected = true; Logging.Message("Plop the Growables detected"); // Add PTG to mod conflict list. conflictingModNames.Add("PTG"); } // Check for realistic population mods. realPopEnabled = (IsModInstalled("RealPopRevisited", true) || IsModInstalled("WG_BalancedPopMod", true)); // Check for Workshop RICO settings mod. if (IsModEnabled(629850626uL)) { Logging.Message("found Workshop RICO settings mod"); Loading.mod1RicoDef = RICOReader.ParseRICODefinition(Path.Combine(Util.SettingsModPath("629850626"), "WorkshopRICOSettings.xml"), false); } // Check for Ryuichi Kaminogi's "RICO Settings for Modern Japan CCP" Package modernJapanRICO = PackageManager.GetPackage("2035770233"); if (modernJapanRICO != null) { Logging.Message("found RICO Settings for Modern Japan CCP"); Loading.mod2RicoDef = RICOReader.ParseRICODefinition(Path.Combine(Path.GetDirectoryName(modernJapanRICO.packagePath), "PloppableRICODefinition.xml"), false); } return(conflictDetected); }
/// <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); }
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); } }