Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RecipeManager v0.6.3
plugins/RecipeManager.dll
Decompiled 15 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using RecipeManager.Common; using UnityEngine; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("RecipeManager")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RecipeManager")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.6.3")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.6.3.0")] namespace RecipeManager { internal class ConversionPrintCommand : ConsoleCommand { public override string Name => "RM_Conversion_PrintAll"; public override string Help => "Prints all conversions."; public override bool IsCheat => true; public override void Run(string[] args) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Starting to dump conversion list"); } string path = Path.Combine(Paths.ConfigPath, "RecipeManager", "AllConversionsDebug.yaml"); DataObjects.ConversionModificationCollection conversionModificationCollection = new DataObjects.ConversionModificationCollection(); List<Smelter> list = (from pc in Resources.FindObjectsOfTypeAll<Smelter>() where !((Object)pc).name.EndsWith("(Clone)") && !Regex.IsMatch(((Object)pc).name.Trim(), "\\(\\d+\\)") select pc).ToList(); List<Fermenter> list2 = (from pc in Resources.FindObjectsOfTypeAll<Fermenter>() where !((Object)pc).name.EndsWith("(Clone)") && !Regex.IsMatch(((Object)pc).name.Trim(), "\\(\\d+\\)") select pc).ToList(); List<CookingStation> list3 = (from pc in Resources.FindObjectsOfTypeAll<CookingStation>() where !((Object)pc).name.EndsWith("(Clone)") && !Regex.IsMatch(((Object)pc).name.Trim(), "\\(\\d+\\)") select pc).ToList(); foreach (Smelter item in list) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Building Smelter definition " + ((Object)((Component)item).gameObject).name); } DataObjects.ConversionModification conversionModification = new DataObjects.ConversionModification(); Logger.LogInfo("Set name " + ((Object)((Component)item).gameObject).name); conversionModification.prefab = ((Object)((Component)item).gameObject).name; conversionModification.action = DataObjects.ConversionAction.Modify; Logger.LogInfo($"Set fuelPerProduct {item.m_fuelPerProduct}"); conversionModification.fuelPerProduct = item.m_fuelPerProduct; Logger.LogInfo($"Set maxFuel {item.m_maxFuel}"); conversionModification.maxFuel = item.m_maxFuel; Logger.LogInfo($"Set maxOres {item.m_maxOre}"); conversionModification.maxOres = item.m_maxOre; if ((Object)(object)item.m_fuelItem != (Object)null) { Logger.LogInfo("Set fuelItem " + ((Object)((Component)item.m_fuelItem).gameObject).name); conversionModification.fuelItem = ((Object)((Component)item.m_fuelItem).gameObject).name; } Logger.LogInfo($"Set requiresFuel {(Object)(object)item.m_fuelItem != (Object)null}"); Logger.LogInfo($"Set conversionTime {item.m_secPerProduct}"); conversionModification.conversionTime = item.m_secPerProduct; List<DataObjects.ConversionDef> list4 = new List<DataObjects.ConversionDef>(); if (item.m_conversion != null && item.m_conversion.Count > 0) { foreach (ItemConversion item2 in item.m_conversion) { if (item2 != null) { DataObjects.ConversionDef conversionDef = new DataObjects.ConversionDef(); if ((Object)(object)item2.m_from != (Object)null) { conversionDef.fromPrefab = ((Object)((Component)item2.m_from).gameObject).name; Logger.LogInfo("Convert From: " + ((Object)((Component)item2.m_from).gameObject).name); } if ((Object)(object)item2.m_to != (Object)null) { conversionDef.toPrefab = ((Object)((Component)item2.m_to).gameObject).name; Logger.LogInfo("Convert To: " + ((Object)((Component)item2.m_to).gameObject).name); } list4.Add(conversionDef); } } } conversionModification.conversions = list4; Logger.LogInfo("Added."); conversionModificationCollection.ConversionModifications.Add(((Object)((Component)item).gameObject).name, conversionModification); } foreach (Fermenter item3 in list2) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Building Fermenter definition " + item3.m_name); } DataObjects.ConversionModification conversionModification2 = new DataObjects.ConversionModification(); conversionModification2.prefab = ((Object)((Component)item3).gameObject).name; conversionModification2.action = DataObjects.ConversionAction.Modify; conversionModification2.conversionTime = item3.m_fermentationDuration; List<DataObjects.ConversionDef> list5 = new List<DataObjects.ConversionDef>(); foreach (ItemConversion item4 in item3.m_conversion) { if (item4 != null) { DataObjects.ConversionDef conversionDef2 = new DataObjects.ConversionDef(); conversionDef2.fromPrefab = ((Object)item4.m_from).name; conversionDef2.toPrefab = ((Object)item4.m_to).name; conversionDef2.amount = item4.m_producedItems; list5.Add(conversionDef2); } } conversionModification2.conversions = list5; conversionModificationCollection.ConversionModifications.Add(((Object)((Component)item3).gameObject).name, conversionModification2); } foreach (CookingStation item5 in list3) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Building Cooking Station definition " + item5.m_name); } DataObjects.ConversionModification conversionModification3 = new DataObjects.ConversionModification(); conversionModification3.prefab = ((Object)((Component)item5).gameObject).name; conversionModification3.action = DataObjects.ConversionAction.Modify; if ((Object)(object)item5.m_fuelItem != (Object)null) { conversionModification3.fuelItem = ((Object)item5.m_fuelItem).name; } if (conversionModification3.overCookedItem != null) { conversionModification3.overCookedItem = ((Object)item5.m_overCookedItem).name; } conversionModification3.secPerFuel = item5.m_secPerFuel; conversionModification3.maxFuel = item5.m_maxFuel; List<DataObjects.ConversionDef> list6 = new List<DataObjects.ConversionDef>(); foreach (ItemConversion item6 in item5.m_conversion) { if (item6 != null) { DataObjects.ConversionDef conversionDef3 = new DataObjects.ConversionDef(); if ((Object)(object)item6.m_from != (Object)null) { conversionDef3.fromPrefab = ((Object)item6.m_from).name; } if ((Object)(object)item6.m_to != (Object)null) { conversionDef3.toPrefab = ((Object)item6.m_to).name; } conversionDef3.cookTime = item6.m_cookTime; list6.Add(conversionDef3); } } conversionModification3.conversions = list6; conversionModificationCollection.ConversionModifications.Add(((Object)((Component)item5).gameObject).name, conversionModification3); } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Serializing and printing conversions."); } string value = ValConfig.yamlserializer.Serialize((object)conversionModificationCollection); using StreamWriter streamWriter = new StreamWriter(path); streamWriter.WriteLine(value); } } internal class ConversionReloadCommand : ConsoleCommand { public override string Name => "RM_Conversion_Reload"; public override string Help => "Resynchronizes conversion modifications."; public override bool IsCheat => true; public override void Run(string[] args) { ConversionUpdater.RevertConversionModifications(); ValConfig.ReloadConversionFiles(); ConversionUpdater.BuildConversionTracker(); ConversionUpdater.ConversionUpdateRunner(); } } internal class ConversionUpdater { private class ConversionSnapshot { private GameObject gameObject; private bool hasSmelter; private List<ItemConversion> smelterConversions; private ItemDrop smelterFuelItem; private int smelterFuelPerProduct; private float smelterSecPerProduct; private int smelterMaxOre; private int smelterMaxFuel; private bool hasFermenter; private List<ItemConversion> fermenterConversions; private float fermentationDuration; private bool hasCookingStation; private List<ItemConversion> cookingConversions; private ItemDrop cookingFuelItem; private int cookingMaxFuel; private bool cookingUseFuel; private bool cookingRequireFire; private int cookingSecPerFuel; public bool IsEmpty { get { if (!hasSmelter && !hasFermenter) { return !hasCookingStation; } return false; } } public static ConversionSnapshot From(GameObject go) { ConversionSnapshot conversionSnapshot = new ConversionSnapshot { gameObject = go }; Smelter component = go.GetComponent<Smelter>(); if ((Object)(object)component != (Object)null) { conversionSnapshot.hasSmelter = true; conversionSnapshot.smelterConversions = Copy(component.m_conversion); conversionSnapshot.smelterFuelItem = component.m_fuelItem; conversionSnapshot.smelterFuelPerProduct = component.m_fuelPerProduct; conversionSnapshot.smelterSecPerProduct = component.m_secPerProduct; conversionSnapshot.smelterMaxOre = component.m_maxOre; conversionSnapshot.smelterMaxFuel = component.m_maxFuel; } Fermenter component2 = go.GetComponent<Fermenter>(); if ((Object)(object)component2 != (Object)null) { conversionSnapshot.hasFermenter = true; conversionSnapshot.fermenterConversions = Copy(component2.m_conversion); conversionSnapshot.fermentationDuration = component2.m_fermentationDuration; } CookingStation component3 = go.GetComponent<CookingStation>(); if ((Object)(object)component3 != (Object)null) { conversionSnapshot.hasCookingStation = true; conversionSnapshot.cookingConversions = Copy(component3.m_conversion); conversionSnapshot.cookingFuelItem = component3.m_fuelItem; conversionSnapshot.cookingMaxFuel = component3.m_maxFuel; conversionSnapshot.cookingUseFuel = component3.m_useFuel; conversionSnapshot.cookingRequireFire = component3.m_requireFire; conversionSnapshot.cookingSecPerFuel = component3.m_secPerFuel; } return conversionSnapshot; } public bool WriteBack() { if ((Object)(object)gameObject == (Object)null) { return false; } if (hasSmelter) { Smelter component = gameObject.GetComponent<Smelter>(); if ((Object)(object)component != (Object)null) { component.m_conversion = Copy(smelterConversions); component.m_fuelItem = smelterFuelItem; component.m_fuelPerProduct = smelterFuelPerProduct; component.m_secPerProduct = smelterSecPerProduct; component.m_maxOre = smelterMaxOre; component.m_maxFuel = smelterMaxFuel; } } if (hasFermenter) { Fermenter component2 = gameObject.GetComponent<Fermenter>(); if ((Object)(object)component2 != (Object)null) { component2.m_conversion = Copy(fermenterConversions); component2.m_fermentationDuration = fermentationDuration; } } if (hasCookingStation) { CookingStation component3 = gameObject.GetComponent<CookingStation>(); if ((Object)(object)component3 != (Object)null) { component3.m_conversion = Copy(cookingConversions); component3.m_fuelItem = cookingFuelItem; component3.m_maxFuel = cookingMaxFuel; component3.m_useFuel = cookingUseFuel; component3.m_requireFire = cookingRequireFire; component3.m_secPerFuel = cookingSecPerFuel; } } return true; } private static List<T> Copy<T>(List<T> source) { if (source != null) { return new List<T>(source); } return null; } } public static Dictionary<string, DataObjects.ConversionModification> ConversionsToModify = new Dictionary<string, DataObjects.ConversionModification>(); public static List<DataObjects.TrackedConversion> TrackedConversions = new List<DataObjects.TrackedConversion>(); private static readonly Dictionary<int, ConversionSnapshot> OriginalConversions = new Dictionary<int, ConversionSnapshot>(); public static void InitialSychronization() { BuildConversionTracker(); ConversionUpdateRunner(); } public static void ConversionUpdateRunner() { Logger.LogInfo($"Applying {TrackedConversions.Count} conversion modifications"); foreach (DataObjects.TrackedConversion trackedConversion in TrackedConversions) { ApplyConversionModifications(trackedConversion); } } public static void ApplyConversionModifications(DataObjects.TrackedConversion conv) { if (conv == null || (Object)(object)conv.prefab == (Object)null) { Logger.LogWarning("A tracked conversion has no target prefab, this modification will be skipped."); return; } Logger.LogDebug($"Applying conversion ({((Object)conv.prefab).name}) modification action: {conv.action}"); IEnumerable<GameObject> enumerable = from obj in Resources.FindObjectsOfTypeAll<GameObject>() where (Object)(object)obj != (Object)null && ((Object)obj).name.StartsWith(((Object)conv.prefab).name) select obj; if (!enumerable.Any()) { Logger.LogWarning("No Prefabs found for conversion " + ((Object)conv.prefab).name + ", skipping modification."); return; } foreach (GameObject item in enumerable) { if (!((Object)(object)item == (Object)null)) { switch (conv.action) { case DataObjects.ConversionAction.Modify: ModifyConversion(conv, item); break; case DataObjects.ConversionAction.Add: AddConversion(conv, item); break; case DataObjects.ConversionAction.Remove: RemoveConversion(conv, item); break; } } } } public static void RevertConversionModifications() { if (OriginalConversions.Count == 0) { return; } Logger.LogInfo($"Reverting {OriginalConversions.Count} conversion modifications"); List<int> list = new List<int>(); int num = 0; foreach (KeyValuePair<int, ConversionSnapshot> originalConversion in OriginalConversions) { if (originalConversion.Value.WriteBack()) { num++; } else { list.Add(originalConversion.Key); } } foreach (int item in list) { OriginalConversions.Remove(item); } Logger.LogDebug($"Restored {num} conversion station(s), {list.Count} no longer exist."); } private static void CaptureOriginal(GameObject go) { if ((Object)(object)go == (Object)null) { return; } int instanceID = ((Object)go).GetInstanceID(); if (!OriginalConversions.ContainsKey(instanceID)) { ConversionSnapshot conversionSnapshot = ConversionSnapshot.From(go); if (!conversionSnapshot.IsEmpty) { OriginalConversions.Add(instanceID, conversionSnapshot); } } } private static void ModifyConversion(DataObjects.TrackedConversion conversion, GameObject go) { CaptureOriginal(go); switch (conversion.convertType) { case DataObjects.ConversionType.Smelter: { Smelter component3 = go.GetComponent<Smelter>(); if ((Object)(object)component3 == (Object)null) { Logger.LogInfo("Smelter component not found on " + ((Object)go).name + ", cannot apply conversion modifications."); break; } if (conversion.updatedSmelterConversions != null) { component3.m_conversion = conversion.updatedSmelterConversions; } if ((Object)(object)conversion.fuelItem != (Object)null) { component3.m_fuelItem = conversion.fuelItem; } if (conversion.fuelPerProduct.HasValue) { component3.m_fuelPerProduct = conversion.fuelPerProduct.Value; } if (conversion.conversionTime.HasValue) { component3.m_secPerProduct = conversion.conversionTime.Value; } if (conversion.maxOres.HasValue) { component3.m_maxOre = conversion.maxOres.Value; } if (conversion.maxFuel.HasValue) { component3.m_maxFuel = conversion.maxFuel.Value; } break; } case DataObjects.ConversionType.Fermenter: { Fermenter component2 = go.GetComponent<Fermenter>(); if ((Object)(object)component2 == (Object)null) { Logger.LogInfo("Fermenter component not found on " + ((Object)go).name + ", cannot apply conversion modifications."); break; } if (conversion.updatedFermenterConversions != null) { component2.m_conversion = conversion.updatedFermenterConversions; } if (conversion.conversionTime.HasValue) { component2.m_fermentationDuration = conversion.conversionTime.Value; } break; } case DataObjects.ConversionType.CookingStation: { CookingStation component = go.GetComponent<CookingStation>(); if ((Object)(object)component == (Object)null) { Logger.LogInfo("CookingStation component not found on " + ((Object)go).name + ", cannot apply conversion modifications."); break; } if (conversion.updatedCookingConversions != null) { component.m_conversion = conversion.updatedCookingConversions; } if (conversion.maxFuel.HasValue) { component.m_maxFuel = conversion.maxFuel.Value; } if ((Object)(object)conversion.fuelItem != (Object)null) { component.m_fuelItem = conversion.fuelItem; } if (conversion.secPerFuel.HasValue) { component.m_secPerFuel = (int)conversion.secPerFuel.Value; } break; } } } private static void AddEntries<T>(List<T> target, List<T> entries) { if (entries == null) { return; } foreach (T entry in entries) { if (!target.Contains(entry)) { target.Add(entry); } } } private static void RemoveEntries<T>(List<T> target, List<T> entries) { if (entries == null) { return; } foreach (T entry in entries) { target.Remove(entry); } } public static void AddConversion(DataObjects.TrackedConversion conversion, GameObject go) { CaptureOriginal(go); switch (conversion.convertType) { case DataObjects.ConversionType.Smelter: { Smelter component2 = go.GetComponent<Smelter>(); if ((Object)(object)component2 == (Object)null) { Logger.LogWarning("Smelter component not found on " + ((Object)go).name + ", no conversions can be added to it."); break; } if (component2.m_conversion == null) { component2.m_conversion = new List<ItemConversion>(); } AddEntries(component2.m_conversion, conversion.updatedSmelterConversions); break; } case DataObjects.ConversionType.Fermenter: { Fermenter component3 = go.GetComponent<Fermenter>(); if ((Object)(object)component3 == (Object)null) { Logger.LogWarning("Fermenter component not found on " + ((Object)go).name + ", no conversions can be added to it."); break; } if (component3.m_conversion == null) { component3.m_conversion = new List<ItemConversion>(); } AddEntries(component3.m_conversion, conversion.updatedFermenterConversions); break; } case DataObjects.ConversionType.CookingStation: { CookingStation component = go.GetComponent<CookingStation>(); if ((Object)(object)component == (Object)null) { Logger.LogWarning("CookingStation component not found on " + ((Object)go).name + ", no conversions can be added to it."); break; } if (component.m_conversion == null) { component.m_conversion = new List<ItemConversion>(); } AddEntries(component.m_conversion, conversion.updatedCookingConversions); break; } } } public static void RemoveConversion(DataObjects.TrackedConversion conversion, GameObject go) { CaptureOriginal(go); switch (conversion.convertType) { case DataObjects.ConversionType.Smelter: { Smelter component3 = go.GetComponent<Smelter>(); if ((Object)(object)component3 == (Object)null || component3.m_conversion == null) { Logger.LogWarning("Smelter component not found on " + ((Object)go).name + ", no conversions can be removed from it."); } else { RemoveEntries(component3.m_conversion, conversion.updatedSmelterConversions); } break; } case DataObjects.ConversionType.Fermenter: { Fermenter component2 = go.GetComponent<Fermenter>(); if ((Object)(object)component2 == (Object)null || component2.m_conversion == null) { Logger.LogWarning("Fermenter component not found on " + ((Object)go).name + ", no conversions can be removed from it."); } else { RemoveEntries(component2.m_conversion, conversion.updatedFermenterConversions); } break; } case DataObjects.ConversionType.CookingStation: { CookingStation component = go.GetComponent<CookingStation>(); if ((Object)(object)component == (Object)null || component.m_conversion == null) { Logger.LogWarning("CookingStation component not found on " + ((Object)go).name + ", no conversions can be removed from it."); } else { RemoveEntries(component.m_conversion, conversion.updatedCookingConversions); } break; } } } public static void BuildConversionTracker() { //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Expected O, but got Unknown //IL_0601: Unknown result type (might be due to invalid IL or missing references) //IL_0608: Expected O, but got Unknown //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Expected O, but got Unknown TrackedConversions.Clear(); foreach (KeyValuePair<string, DataObjects.ConversionModification> item in ConversionsToModify) { if (item.Key == null) { continue; } Logger.LogDebug("Constructing Conversion modifications for " + item.Key); bool flag = true; DataObjects.TrackedConversion trackedConversion = new DataObjects.TrackedConversion(); trackedConversion.action = item.Value.action; try { GameObject prefab = PrefabManager.Instance.GetPrefab(item.Value.prefab); if ((Object)(object)prefab == (Object)null) { Logger.LogWarning("Could not find piece with name: " + item.Value.prefab + ", this modification will be skipped."); continue; } trackedConversion.prefab = prefab; Smelter val = (prefab.GetComponent<Smelter>() ?? prefab.GetComponentInChildren<Smelter>()) ?? prefab.GetComponentInParent<Smelter>(); if ((Object)(object)val != (Object)null) { trackedConversion.smelterComponent = val; trackedConversion.convertType = DataObjects.ConversionType.Smelter; } Fermenter val2 = (prefab.GetComponent<Fermenter>() ?? prefab.GetComponentInChildren<Fermenter>()) ?? prefab.GetComponentInParent<Fermenter>(); if ((Object)(object)val2 != (Object)null) { trackedConversion.fermenterComponent = val2; trackedConversion.convertType = DataObjects.ConversionType.Fermenter; } CookingStation val3 = (prefab.GetComponent<CookingStation>() ?? prefab.GetComponentInChildren<CookingStation>()) ?? prefab.GetComponentInParent<CookingStation>(); if ((Object)(object)val3 != (Object)null) { trackedConversion.cookingStationComponent = val3; trackedConversion.convertType = DataObjects.ConversionType.CookingStation; } } catch (Exception ex) { Logger.LogWarning("Could not resolve the prefab (" + item.Value.prefab + ") referenced by " + item.Key + ", this modification will be skipped. Define a prefab to modify to fix this. Error: " + ex.Message); continue; } if ((Object)(object)trackedConversion.cookingStationComponent == (Object)null && (Object)(object)trackedConversion.fermenterComponent == (Object)null && (Object)(object)trackedConversion.smelterComponent == (Object)null) { Logger.LogWarning(item.Value.prefab + " did not have an attached Fermenter, Smelter, or CookingStation. This modification will be skipped."); continue; } switch (trackedConversion.convertType) { case DataObjects.ConversionType.Fermenter: { Logger.LogDebug("Setting Fermenter"); List<ItemConversion> list2 = new List<ItemConversion>(); if (item.Value.conversions != null && item.Value.conversions.Count > 0) { foreach (DataObjects.ConversionDef conversion in item.Value.conversions) { Logger.LogDebug("Creating Conversion " + conversion.fromPrefab + " to " + conversion.toPrefab); GetConversionGOs(conversion, out var togo2, out var fromgo2); if (!((Object)(object)togo2 == (Object)null) && !((Object)(object)fromgo2 == (Object)null)) { ItemConversion val5 = new ItemConversion(); val5.m_to = togo2.GetComponent<ItemDrop>(); val5.m_from = fromgo2.GetComponent<ItemDrop>(); val5.m_producedItems = conversion.amount; list2.Add(val5); } } } trackedConversion.updatedFermenterConversions = list2; if (item.Value.conversionTime.HasValue) { if (item.Value.conversionTime.Value > 0f) { trackedConversion.conversionTime = item.Value.conversionTime; } else { Logger.LogWarning($"{item.Key} has a conversionTime of {item.Value.conversionTime.Value}, it must be above 0. The fermentation time will not be changed."); } } break; } case DataObjects.ConversionType.CookingStation: { Logger.LogDebug("Setting CookingStation"); List<ItemConversion> list3 = new List<ItemConversion>(); if (item.Value.conversions != null && item.Value.conversions.Count > 0) { foreach (DataObjects.ConversionDef conversion2 in item.Value.conversions) { Logger.LogDebug("Creating Conversion " + conversion2.fromPrefab + " to " + conversion2.toPrefab); GetConversionGOs(conversion2, out var togo3, out var fromgo3); if (!((Object)(object)togo3 == (Object)null) && !((Object)(object)fromgo3 == (Object)null)) { ItemConversion val6 = new ItemConversion(); val6.m_to = togo3.GetComponent<ItemDrop>(); val6.m_from = fromgo3.GetComponent<ItemDrop>(); val6.m_cookTime = conversion2.cookTime; list3.Add(val6); } } } trackedConversion.updatedCookingConversions = list3; if (item.Value.overCookedTime > 0f) { trackedConversion.overCookedTime = item.Value.overCookedTime; } trackedConversion.maxFuel = NonNegative(item.Key, "maxFuel", item.Value.maxFuel); if (item.Value.secPerFuel.HasValue) { if (item.Value.secPerFuel.Value > 0f) { trackedConversion.secPerFuel = item.Value.secPerFuel; } else { Logger.LogWarning($"{item.Key} has a secPerFuel of {item.Value.secPerFuel.Value}, it must be above 0 and will be ignored."); } } trackedConversion.fuelItem = ResolveFuelItem(item.Key, item.Value.fuelItem); break; } case DataObjects.ConversionType.Smelter: { Logger.LogDebug("Setting Smelter"); List<ItemConversion> list = new List<ItemConversion>(); if (item.Value.conversions != null && item.Value.conversions.Count > 0) { foreach (DataObjects.ConversionDef conversion3 in item.Value.conversions) { Logger.LogDebug("Creating Conversion " + conversion3.fromPrefab + " to " + conversion3.toPrefab); GetConversionGOs(conversion3, out var togo, out var fromgo); if (!((Object)(object)togo == (Object)null) && !((Object)(object)fromgo == (Object)null)) { ItemConversion val4 = new ItemConversion(); val4.m_to = togo.GetComponent<ItemDrop>(); val4.m_from = fromgo.GetComponent<ItemDrop>(); list.Add(val4); } } } trackedConversion.updatedSmelterConversions = list; trackedConversion.conversionTime = SmelterConversionTime(item.Key, item.Value.conversionTime); trackedConversion.fuelPerProduct = NonNegative(item.Key, "fuelPerProduct", item.Value.fuelPerProduct); trackedConversion.maxFuel = NonNegative(item.Key, "maxFuel", item.Value.maxFuel); trackedConversion.maxOres = NonNegative(item.Key, "maxOres", item.Value.maxOres); if (trackedConversion.maxOres == 0) { Logger.LogWarning(item.Key + " sets maxOres to 0, the station will not accept any items to convert."); } trackedConversion.fuelItem = ResolveFuelItem(item.Key, item.Value.fuelItem); break; } } if (!flag) { Logger.LogWarning("Conversion request was not valid, skipping."); } else { TrackedConversions.Add(trackedConversion); } } static void GetConversionGOs(DataObjects.ConversionDef conv, out GameObject reference2, out GameObject reference) { reference = PrefabManager.Instance.GetPrefab(conv.fromPrefab); reference2 = PrefabManager.Instance.GetPrefab(conv.toPrefab); if ((Object)(object)reference == (Object)null) { Logger.LogWarning("Conversion could not find " + conv.fromPrefab + ", this conversion will be skipped."); } if ((Object)(object)reference2 == (Object)null) { Logger.LogWarning("Conversion could not find " + conv.toPrefab + ", this conversion will be skipped."); } } static int? NonNegative(string entry, string field, int? value) { if (value.HasValue && value.Value < 0) { Logger.LogWarning($"{entry} has a {field} of {value.Value}, it can not be negative and will be ignored."); return null; } return value; } static ItemDrop ResolveFuelItem(string entry, string fuelItem) { if (!string.IsNullOrEmpty(fuelItem)) { GameObject prefab2 = PrefabManager.Instance.GetPrefab(fuelItem); ItemDrop obj = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponent<ItemDrop>() : null); if ((Object)(object)obj == (Object)null) { Logger.LogWarning(entry + " could not find an item named " + fuelItem + ", the fuel item will not be changed."); } return obj; } return null; } static float? SmelterConversionTime(string entry, float? conversionTime) { if (!conversionTime.HasValue) { return null; } if (conversionTime.Value <= 0f) { Logger.LogWarning($"{entry} has a conversionTime of {conversionTime.Value}, a smelter with no conversion time never produces anything. The conversion time will not be changed."); return null; } if (conversionTime.Value < 1f) { Logger.LogWarning($"{entry} has a conversionTime of {conversionTime.Value}, smelters can not produce more than one item per second and a shorter time only burns more fuel. Using 1 instead."); return 1f; } return conversionTime; } } public static void UpdateConversionModifications(DataObjects.ConversionModificationCollection convMods) { ConversionsToModify.Clear(); foreach (KeyValuePair<string, DataObjects.ConversionModification> conversionModification in convMods.ConversionModifications) { ConversionsToModify.Add(conversionModification.Key, conversionModification.Value); } } public static void UpdateConversionModificationsFromRPC(string rpcRecieved) { Logger.LogInfo("RPC Recieved: " + rpcRecieved); Logger.LogInfo($"RPC Data: {rpcRecieved.Length}"); UpdateConversionModifications(ValConfig.yamldeserializer.Deserialize<DataObjects.ConversionModificationCollection>(rpcRecieved)); } public static void UpdateConversionModificationsFromList(List<DataObjects.ConversionModificationCollection> convMods) { ConversionsToModify.Clear(); foreach (DataObjects.ConversionModificationCollection convMod in convMods) { foreach (KeyValuePair<string, DataObjects.ConversionModification> conversionModification in convMod.ConversionModifications) { ConversionsToModify.Add(conversionModification.Key, conversionModification.Value); } } } } internal class ItemReloadCommand : ConsoleCommand { public override string Name => "RM_Items_Reload"; public override string Help => "Reloads item additions and modifications. Stats, names, icons and textures are re-applied; new or removed items need a restart."; public override bool IsCheat => true; public override void Run(string[] args) { ValConfig.ReloadItemFiles(); ItemUpdater.ReapplyExistingItems(); ItemCommandUtils.Respond($"Reloaded {ItemUpdater.ItemDefinitions.Count} item entry(s), {ItemUpdater.ModifiedItems.Count} of which modify an existing item."); try { ValConfig.SendUpdatedItemConfigs(); } catch (Exception ex) { if (ValConfig.EnableDebugMode.Value) { Logger.LogDebug("Item configs were not sent to peers: " + ex.Message); } } } } internal class ItemPrintCommand : ConsoleCommand { public override string Name => "RM_Items_PrintAll"; public override string Help => "Prints items in the Object DB to a reference file, with their real stats. Usage: RM_Items_PrintAll [nameFilter]"; public override bool IsCheat => true; public override void Run(string[] args) { if ((Object)(object)ObjectDB.instance == (Object)null) { ItemCommandUtils.Respond("The object DB is not available yet, load into a world first."); return; } string text = ((args != null && args.Length != 0) ? args[0] : null); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Starting to dump items"); } string text2 = Path.Combine(Paths.ConfigPath, "RecipeManager", "ObjectDBItems.yaml"); DataObjects.ItemAdditionCollection itemAdditionCollection = new DataObjects.ItemAdditionCollection(); foreach (GameObject item in ObjectDB.instance.m_items.ToList()) { if ((Object)(object)item == (Object)null || (text != null && ((Object)item).name.IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0)) { continue; } SharedData val = item.GetComponent<ItemDrop>()?.m_itemData?.m_shared; if (val == null) { continue; } if (itemAdditionCollection.ItemAdditions.ContainsKey(((Object)item).name)) { Logger.LogWarning(((Object)item).name + " was already added to the list of items and will be skipped."); continue; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Building item definition " + ((Object)item).name); } itemAdditionCollection.ItemAdditions.Add(((Object)item).name, DescribeItem(((Object)item).name, val)); } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Serializing and printing items."); } using (StreamWriter streamWriter = new StreamWriter(text2)) { streamWriter.WriteLine("# Reference dump of the items in the object DB, with the stats they currently have."); streamWriter.WriteLine("# This file is NOT loaded by the mod, it is here so you can see what the numbers are."); streamWriter.WriteLine("#"); streamWriter.WriteLine("# To change one of these items, copy its entry into your own Items.yaml and delete"); streamWriter.WriteLine("# every line you do not want to change - anything left out keeps its current value."); streamWriter.WriteLine("# To create a new item from one instead, set 'action: Add', point 'clonedFrom' at the"); streamWriter.WriteLine("# prefab below and give 'prefab' a new unique name."); streamWriter.WriteLine(); streamWriter.WriteLine(ValConfig.yamlserializer.Serialize((object)itemAdditionCollection)); } ItemCommandUtils.Respond($"Dumped {itemAdditionCollection.ItemAdditions.Count} item(s) to {text2}"); } private static DataObjects.ItemAddition DescribeItem(string prefabName, SharedData shared) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Invalid comparison between Unknown and I4 //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) DataObjects.ItemAddition itemAddition = new DataObjects.ItemAddition { action = DataObjects.ItemAction.Modify, prefab = prefabName, name = shared.m_name, description = shared.m_description, weight = shared.m_weight, maxStackSize = shared.m_maxStackSize, value = shared.m_value, teleportable = shared.m_teleportable }; if (shared.m_food > 0f || shared.m_foodStamina > 0f || shared.m_foodEitr > 0f || (int)shared.m_itemType == 2) { DataObjects.FoodStats obj = new DataObjects.FoodStats { health = shared.m_food, stamina = shared.m_foodStamina, eitr = shared.m_foodEitr, duration = shared.m_foodBurnTime, regen = shared.m_foodRegen, eatAnimTime = shared.m_foodEatAnimTime, isDrink = shared.m_isDrink }; StatusEffect consumeStatusEffect = shared.m_consumeStatusEffect; obj.consumeStatusEffect = ((consumeStatusEffect != null) ? ((Object)consumeStatusEffect).name : null); itemAddition.food = obj; } if (((DamageTypes)(ref shared.m_damages)).HaveDamage() || ((DamageTypes)(ref shared.m_damagesPerLevel)).HaveDamage() || shared.m_toolTier > 0) { itemAddition.weapon = new DataObjects.WeaponStats { damage = DescribeDamage(shared.m_damages), damagePerLevel = DescribeDamage(shared.m_damagesPerLevel), attackForce = shared.m_attackForce, backstabBonus = shared.m_backstabBonus, toolTier = shared.m_toolTier }; } if (shared.m_armor > 0f || shared.m_blockPower > 0f || shared.m_movementModifier != 0f || shared.m_eitrRegenModifier != 0f) { itemAddition.armor = new DataObjects.ArmorStats { armor = shared.m_armor, armorPerLevel = shared.m_armorPerLevel, blockPower = shared.m_blockPower, blockPowerPerLevel = shared.m_blockPowerPerLevel, deflectionForce = shared.m_deflectionForce, deflectionForcePerLevel = shared.m_deflectionForcePerLevel, movementModifier = shared.m_movementModifier, eitrRegenModifier = shared.m_eitrRegenModifier }; } if (shared.m_damageModifiers != null && shared.m_damageModifiers.Count > 0) { itemAddition.resistances = new List<DataObjects.DamageResistance>(); foreach (DamageModPair damageModifier in shared.m_damageModifiers) { itemAddition.resistances.Add(new DataObjects.DamageResistance { type = damageModifier.m_type, modifier = damageModifier.m_modifier }); } } if ((Object)(object)shared.m_equipStatusEffect != (Object)null || (Object)(object)shared.m_attackStatusEffect != (Object)null) { DataObjects.ItemStatusEffects itemStatusEffects = new DataObjects.ItemStatusEffects(); StatusEffect equipStatusEffect = shared.m_equipStatusEffect; itemStatusEffects.equipped = ((equipStatusEffect != null) ? ((Object)equipStatusEffect).name : null); StatusEffect attackStatusEffect = shared.m_attackStatusEffect; itemStatusEffects.onHit = ((attackStatusEffect != null) ? ((Object)attackStatusEffect).name : null); itemStatusEffects.onHitChance = (((Object)(object)shared.m_attackStatusEffect != (Object)null) ? new float?(shared.m_attackStatusEffectChance) : ((float?)null)); itemAddition.statusEffects = itemStatusEffects; } if (!string.IsNullOrEmpty(shared.m_setName)) { DataObjects.SetBonus obj2 = new DataObjects.SetBonus { name = shared.m_setName, size = shared.m_setSize }; StatusEffect setStatusEffect = shared.m_setStatusEffect; obj2.statusEffect = ((setStatusEffect != null) ? ((Object)setStatusEffect).name : null); itemAddition.setBonus = obj2; } return itemAddition; } private static DataObjects.DamageValues DescribeDamage(DamageTypes damages) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) return new DataObjects.DamageValues { damage = damages.m_damage, blunt = damages.m_blunt, slash = damages.m_slash, pierce = damages.m_pierce, chop = damages.m_chop, pickaxe = damages.m_pickaxe, fire = damages.m_fire, frost = damages.m_frost, lightning = damages.m_lightning, poison = damages.m_poison, spirit = damages.m_spirit }; } public override List<string> CommandOptionList() { List<string> list = new List<string>(); if (ObjectDB.instance?.m_items == null) { return list; } foreach (GameObject item in ObjectDB.instance.m_items) { if ((Object)(object)item != (Object)null) { list.Add(((Object)item).name); } } return list; } } internal class TextureDumpCommand : ConsoleCommand { public override string Name => "RM_Textures_Dump"; public override string Help => "Dumps a prefab's icons and material textures to disk as PNGs. Usage: RM_Textures_Dump <prefabName>"; public override bool IsCheat => true; public override void Run(string[] args) { if (args == null || args.Length < 1 || string.IsNullOrEmpty(args[0])) { ItemCommandUtils.Respond("Usage: " + ((ConsoleCommand)this).Name + " <prefabName>"); return; } string text = args[0]; GameObject prefab = PrefabManager.Instance.GetPrefab(text); if ((Object)(object)prefab == (Object)null) { ItemCommandUtils.Respond("No prefab named '" + text + "' could be found. Prefab names are case sensitive."); return; } try { string outputDirectory; int num = TextureTools.DumpPrefab(prefab, out outputDirectory); if (num == 0) { ItemCommandUtils.Respond("Found no textures to dump for '" + text + "'. See " + outputDirectory + "\\_dump_info.txt"); } else { ItemCommandUtils.Respond($"Dumped {num} texture(s) for '{text}' to {outputDirectory}"); } } catch (Exception ex) { ItemCommandUtils.Respond("Dumping textures for '" + text + "' failed: " + ex.Message); Logger.LogError($"Texture dump for '{text}' failed. Error: {ex}"); } } public override List<string> CommandOptionList() { List<string> list = new List<string>(); if (ObjectDB.instance?.m_items == null) { return list; } foreach (GameObject item in ObjectDB.instance.m_items) { if ((Object)(object)item != (Object)null) { list.Add(((Object)item).name); } } return list; } } internal static class ItemCommandUtils { internal static void Respond(string message) { Logger.LogInfo(message); if ((Object)(object)Console.instance != (Object)null) { Console.instance.Print(message); } } } internal class ItemUpdater { public static Dictionary<string, DataObjects.ItemAddition> ItemDefinitions = new Dictionary<string, DataObjects.ItemAddition>(); public static List<DataObjects.TrackedItem> TrackedItems = new List<DataObjects.TrackedItem>(); public static List<DataObjects.TrackedItem> ModifiedItems = new List<DataObjects.TrackedItem>(); private static readonly HashSet<string> CreatedPrefabs = new HashSet<string>(); private static readonly HashSet<string> ModifiedPrefabs = new HashSet<string>(); private const string TokenPrefix = "rm_item_"; public static void CreateCustomItems() { if (ItemDefinitions.Count == 0) { return; } TrackedItems.Clear(); foreach (KeyValuePair<string, DataObjects.ItemAddition> itemDefinition in ItemDefinitions) { if (itemDefinition.Value == null) { Logger.LogError("Item entry '" + itemDefinition.Key + "' is empty, it needs at least an action and a prefab. Skipping."); } else if (itemDefinition.Value.action != DataObjects.ItemAction.Modify) { try { CreateCustomItem(itemDefinition.Key, itemDefinition.Value); } catch (Exception arg) { Logger.LogError($"Item addition '{itemDefinition.Key}' failed and will be skipped. Error: {arg}"); } } } if (TrackedItems.Count > 0) { Logger.LogInfo($"Registered {TrackedItems.Count} custom item(s)."); } } private static void CreateCustomItem(string modificationName, DataObjects.ItemAddition def) { //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Expected O, but got Unknown if (!ValidateDefinition(modificationName, def)) { return; } if (def.action == DataObjects.ItemAction.Remove) { if (CreatedPrefabs.Contains(def.prefab)) { Logger.LogWarning("Item addition '" + modificationName + "' is set to Remove, but " + def.prefab + " was already registered this session. Restart the game to fully remove it."); } return; } DataObjects.TrackedItem trackedItem = new DataObjects.TrackedItem { action = def.action, prefab = def.prefab, clonedFrom = def.clonedFrom, definition = def }; if (CreatedPrefabs.Contains(def.prefab)) { GameObject prefab = PrefabManager.Instance.GetPrefab(def.prefab); if ((Object)(object)prefab == (Object)null) { Logger.LogWarning(def.prefab + " was registered earlier but can no longer be resolved, skipping."); return; } trackedItem.itemPrefab = prefab; TrackedItems.Add(trackedItem); return; } if ((Object)(object)PrefabManager.Instance.GetPrefab(def.prefab) != (Object)null) { Logger.LogError("Item addition '" + modificationName + "' wants to create the prefab '" + def.prefab + "', but a prefab with that name already exists. Prefab names must be globally unique, and changing an item that already exists is done with 'action: Modify'. This addition will be skipped."); return; } GameObject val = PrefabManager.Instance.CreateClonedPrefab(def.prefab, def.clonedFrom); if ((Object)(object)val == (Object)null) { Logger.LogError("Item addition '" + modificationName + "' could not clone '" + def.clonedFrom + "'. Check that the prefab name is spelled correctly. This addition will be skipped."); return; } if ((Object)(object)val.GetComponent<ItemDrop>() == (Object)null) { Logger.LogError("'" + def.clonedFrom + "' has no ItemDrop component, so it cannot be used as the source for an item. Item addition '" + modificationName + "' will be skipped."); return; } ApplyDefinition(val, def); CustomItem val2 = new CustomItem(val, false); if (!val2.IsValid()) { Logger.LogError("The item created by '" + modificationName + "' is not valid and will be skipped."); return; } if (!ItemManager.Instance.AddItem(val2)) { Logger.LogError("Jotunn rejected the item created by '" + modificationName + "'. This addition will be skipped."); return; } CreatedPrefabs.Add(def.prefab); trackedItem.itemPrefab = val; trackedItem.customItem = val2; if (def.recipe != null) { CustomRecipe val3 = BuildRecipe(modificationName, def); if (val3 != null && !ItemManager.Instance.AddRecipe(val3)) { Logger.LogWarning("Could not register the recipe for '" + modificationName + "'. The item exists but will not be craftable."); } } TrackedItems.Add(trackedItem); Logger.LogInfo("Created item " + def.prefab + " from " + def.clonedFrom + "."); } private static bool ValidateDefinition(string modificationName, DataObjects.ItemAddition def) { if (string.IsNullOrEmpty(def.prefab)) { Logger.LogError("Item addition '" + modificationName + "' has no 'prefab' set. This is the name of the new item and is required. Skipping."); return false; } if (def.action != DataObjects.ItemAction.Remove && string.IsNullOrEmpty(def.clonedFrom)) { Logger.LogError("Item addition '" + modificationName + "' has no 'clonedFrom' set. This is the existing prefab to copy and is required. If you meant to change an item that already exists, use 'action: Modify' instead. Skipping."); return false; } if (string.Equals(def.prefab, def.clonedFrom, StringComparison.Ordinal)) { Logger.LogError("Item addition '" + modificationName + "' has 'prefab' and 'clonedFrom' set to the same value (" + def.prefab + "). The new item needs its own unique name, and changing the original in place is done with 'action: Modify'. Skipping."); return false; } return true; } public static void ApplyDefinition(GameObject prefab, DataObjects.ItemAddition def) { SharedData sharedData = GetSharedData(prefab); if (sharedData == null) { Logger.LogWarning(def.prefab + " has no usable ItemDrop data, nothing to apply."); return; } ItemAttributes.CaptureOriginal(def.prefab, sharedData); ItemAttributes.RestoreOriginal(def.prefab, sharedData); ApplyStats(sharedData, def, statusEffectsAvailable: false); ApplyArt(prefab, def.prefab, warnWhenIconless: true); } private static void ApplyStats(SharedData shared, DataObjects.ItemAddition def, bool statusEffectsAvailable) { if (def.action == DataObjects.ItemAction.Modify) { if (!string.IsNullOrEmpty(def.name)) { shared.m_name = ResolveToken(def.name, def.prefab, string.Empty); } } else { shared.m_name = ResolveNameToken(def); } string text = ResolveToken(def.description, def.prefab, "_desc"); if (text != null) { shared.m_description = text; } ItemAttributes.Apply(shared, def, statusEffectsAvailable); } private static void ApplyArt(GameObject prefab, string prefabName, bool warnWhenIconless) { SharedData sharedData = GetSharedData(prefab); if (sharedData != null) { Sprite[] array = TextureTools.LoadIcons(prefabName, sharedData.m_icons); if (array != null && array.Length != 0) { sharedData.m_icons = array; } else if (warnWhenIconless) { Logger.LogWarning(prefabName + " ended up with no icons and would not be pickupable. Check that the prefab it was cloned from has an icon."); } int num = TextureTools.ApplyTextureOverrides(prefab, prefabName); if (num > 0) { Logger.LogInfo($"Applied {num} texture override(s) to {prefabName}."); } } } public static void ApplyItemModifications() { Dictionary<string, List<DataObjects.ItemAddition>> dictionary = GroupModificationsByPrefab(); RevertPrefabs(Except(ModifiedPrefabs, dictionary.Keys)); ModifiedItems.Clear(); int num = 0; foreach (KeyValuePair<string, List<DataObjects.ItemAddition>> item in dictionary) { try { if (ApplyModification(item.Key, item.Value)) { num++; } } catch (Exception arg) { Logger.LogError($"Could not modify {item.Key}. Error: {arg}"); } } if (num > 0) { Logger.LogInfo($"Applied modifications to {num} existing item(s)."); } } private static bool ApplyModification(string prefabName, List<DataObjects.ItemAddition> definitions) { GameObject val = ResolveItemPrefab(prefabName); if ((Object)(object)val == (Object)null) { Logger.LogWarning("No item named '" + prefabName + "' could be found, the modification targeting it will be skipped. Prefab names are case sensitive, run RM_Items_PrintAll to see the ones that exist."); return false; } SharedData sharedData = GetSharedData(val); if (sharedData == null) { Logger.LogWarning("'" + prefabName + "' has no usable ItemDrop data, the modification targeting it will be skipped."); return false; } ItemAttributes.CaptureOriginal(prefabName, sharedData); ItemAttributes.RestoreOriginal(prefabName, sharedData); foreach (DataObjects.ItemAddition definition in definitions) { ApplyStats(sharedData, definition, statusEffectsAvailable: true); ModifiedItems.Add(new DataObjects.TrackedItem { action = DataObjects.ItemAction.Modify, prefab = prefabName, itemPrefab = val, definition = definition }); } ApplyArt(val, prefabName, warnWhenIconless: false); ModifiedPrefabs.Add(prefabName); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Modified " + prefabName + "."); } return true; } private static Dictionary<string, List<DataObjects.ItemAddition>> GroupModificationsByPrefab() { Dictionary<string, List<DataObjects.ItemAddition>> dictionary = new Dictionary<string, List<DataObjects.ItemAddition>>(); foreach (KeyValuePair<string, DataObjects.ItemAddition> itemDefinition in ItemDefinitions) { DataObjects.ItemAddition value = itemDefinition.Value; if (value == null || value.action != DataObjects.ItemAction.Modify) { continue; } if (string.IsNullOrEmpty(value.prefab)) { Logger.LogError("Item modification '" + itemDefinition.Key + "' has no 'prefab' set. This is the item to change and is required. Skipping."); } else if (CreatedPrefabs.Contains(value.prefab)) { Logger.LogError("Item modification '" + itemDefinition.Key + "' targets " + value.prefab + ", which is an item this mod adds. Put the stats on that 'action: Add' entry instead of modifying it separately. Skipping."); } else { if (!dictionary.TryGetValue(value.prefab, out var value2)) { value2 = new List<DataObjects.ItemAddition>(); dictionary.Add(value.prefab, value2); } value2.Add(value); } } return dictionary; } public static void RevertItemModifications() { RevertPrefabs(new List<string>(ModifiedPrefabs)); ModifiedItems.Clear(); } private static void RevertPrefabs(List<string> prefabNames) { foreach (string prefabName in prefabNames) { SharedData sharedData = GetSharedData(ResolveItemPrefab(prefabName)); if (sharedData == null) { Logger.LogWarning(prefabName + " can no longer be resolved, its original stats could not be restored."); } else if (ItemAttributes.RestoreOriginal(prefabName, sharedData) && ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Restored the original stats of " + prefabName + "."); } ModifiedPrefabs.Remove(prefabName); } } private static List<string> Except(IEnumerable<string> source, ICollection<string> exclude) { List<string> list = new List<string>(); foreach (string item in source) { if (!exclude.Contains(item)) { list.Add(item); } } return list; } private static GameObject ResolveItemPrefab(string prefabName) { GameObject val = null; if ((Object)(object)ObjectDB.instance != (Object)null) { val = ObjectDB.instance.GetItemPrefab(prefabName); } if ((Object)(object)val == (Object)null) { val = PrefabManager.Instance.GetPrefab(prefabName); } return val; } private static SharedData GetSharedData(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return null; } return prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared; } public static void ResolveDeferredReferences() { ResolveDeferredReferences(TrackedItems); ResolveDeferredReferences(ModifiedItems); } private static void ResolveDeferredReferences(List<DataObjects.TrackedItem> tracked) { foreach (DataObjects.TrackedItem item in tracked) { if (item.definition != null && !((Object)(object)item.itemPrefab == (Object)null)) { SharedData sharedData = GetSharedData(item.itemPrefab); if (sharedData != null) { ItemAttributes.ApplyStatusEffects(sharedData, item.definition, warnOnMissing: true); } } } } private static string ResolveNameToken(DataObjects.ItemAddition def) { if (string.IsNullOrEmpty(def.name)) { Logger.LogWarning("Item addition for " + def.prefab + " has no 'name' set. Falling back to the prefab name - set 'name' to give it a proper display name."); return ResolveToken(def.prefab, def.prefab, string.Empty); } return ResolveToken(def.name, def.prefab, string.Empty); } private static string ResolveToken(string configured, string prefab, string suffix) { if (string.IsNullOrEmpty(configured)) { return null; } if (configured.StartsWith("$", StringComparison.Ordinal)) { return configured; } string result = "$rm_item_" + prefab.ToLowerInvariant() + suffix; LocalizationManager.Instance.GetLocalization().AddTranslation(ref result, configured); return result; } private static CustomRecipe BuildRecipe(string modificationName, DataObjects.ItemAddition def) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown DataObjects.ItemRecipe recipe = def.recipe; List<RequirementConfig> list = new List<RequirementConfig>(); foreach (DataObjects.Ingrediant ingredient in recipe.ingredients) { if (ingredient == null || string.IsNullOrEmpty(ingredient.prefab)) { Logger.LogWarning("Recipe for '" + modificationName + "' has an ingredient with no prefab set, it will be ignored."); continue; } list.Add(new RequirementConfig { Item = ingredient.prefab, Amount = ingredient.craftCost, AmountPerLevel = ingredient.upgradeCost, Recover = false }); } return new CustomRecipe(new RecipeConfig { Name = "Recipe_" + def.prefab, Item = def.prefab, Amount = recipe.craftAmount, CraftingStation = recipe.craftedAt, RepairStation = (string.IsNullOrEmpty(recipe.repairAt) ? recipe.craftedAt : recipe.repairAt), MinStationLevel = recipe.minStationLevel, RequireOnlyOneIngredient = recipe.anyOneResource, Enabled = true, Requirements = list.ToArray() }); } public static void ReapplyExistingItems() { HashSet<string> hashSet = new HashSet<string>(); foreach (KeyValuePair<string, DataObjects.ItemAddition> itemDefinition in ItemDefinitions) { DataObjects.ItemAddition value = itemDefinition.Value; if (value == null || string.IsNullOrEmpty(value.prefab) || value.action == DataObjects.ItemAction.Remove || value.action == DataObjects.ItemAction.Modify) { continue; } hashSet.Add(value.prefab); if (!CreatedPrefabs.Contains(value.prefab)) { Logger.LogWarning("'" + itemDefinition.Key + "' defines a new item (" + value.prefab + ") which cannot be added while the game is running. Restart the game or return to the main menu to create it."); continue; } GameObject prefab = PrefabManager.Instance.GetPrefab(value.prefab); if ((Object)(object)prefab == (Object)null) { Logger.LogWarning(value.prefab + " was registered but can no longer be resolved, skipping."); continue; } try { ApplyDefinition(prefab, value); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Refreshed " + value.prefab + "."); } } catch (Exception arg) { Logger.LogError($"Could not refresh {value.prefab}. Error: {arg}"); } } foreach (string createdPrefab in CreatedPrefabs) { if (!hashSet.Contains(createdPrefab)) { Logger.LogWarning(createdPrefab + " was removed from the configuration but is already registered. Restart the game to remove it."); } } ApplyItemModifications(); ResolveDeferredReferences(TrackedItems); } public static void UpdateItemAdditions(DataObjects.ItemAdditionCollection itemAdditions) { ItemDefinitions.Clear(); if (itemAdditions?.ItemAdditions == null) { return; } foreach (KeyValuePair<string, DataObjects.ItemAddition> itemAddition in itemAdditions.ItemAdditions) { ItemDefinitions.Add(itemAddition.Key, itemAddition.Value); } } public static void UpdateItemAdditionsFromList(List<DataObjects.ItemAdditionCollection> collections) { ItemDefinitions.Clear(); foreach (DataObjects.ItemAdditionCollection collection in collections) { if (collection?.ItemAdditions == null) { continue; } foreach (KeyValuePair<string, DataObjects.ItemAddition> itemAddition in collection.ItemAdditions) { if (ItemDefinitions.ContainsKey(itemAddition.Key)) { Logger.LogWarning("Item entry '" + itemAddition.Key + "' is defined more than once, only the first definition will be used."); } else { ItemDefinitions.Add(itemAddition.Key, itemAddition.Value); } } } } public static void UpdateItemAdditionsFromRPC(string yaml) { UpdateItemAdditions(ValConfig.yamldeserializer.Deserialize<DataObjects.ItemAdditionCollection>(yaml)); } } internal class PieceReloadCommand : ConsoleCommand { public override string Name => "RM_Pieces_Reload"; public override string Help => "Resynchronizes piece modifications."; public override bool IsCheat => true; public override void Run(string[] args) { PieceUpdater.RevertPieceModifications(); ValConfig.ReloadPieceFiles(); PieceUpdater.BuildPieceTracker(); PieceUpdater.PieceUpdateRunner(); ValConfig.SendUpdatedPieceConfigs(); } } internal class PiecePrintCommand : ConsoleCommand { public override string Name => "RM_Pieces_PrintAll"; public override string Help => "Prints all the Pieces found."; public override bool IsCheat => true; public override void Run(string[] args) { //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Starting to dump piece list"); } string text = Path.Combine(Paths.ConfigPath, "RecipeManager", "AllPiecesDebug.yaml"); DataObjects.PieceModificationCollection pieceModificationCollection = new DataObjects.PieceModificationCollection(); using StreamWriter streamWriter = new StreamWriter(text); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Gathering Pieces"); } foreach (Piece item in (from pc in Resources.FindObjectsOfTypeAll<Piece>() where !((Object)pc).name.EndsWith("(Clone)") && !Regex.IsMatch(((Object)pc).name.Trim(), "\\(\\d+\\)") select pc).ToList()) { if ((Object)(object)item == (Object)null || ((Object)item).name == null) { continue; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Building Piece definition " + item.m_name)); } DataObjects.PieceModification pieceModification = new DataObjects.PieceModification(); pieceModification.action = DataObjects.PieceAction.Enable; pieceModification.EnablePiece = ((Behaviour)item).enabled; pieceModification.CanBeDeconstructed = item.m_canBeRemoved; pieceModification.CultivatedGroundOnly = item.m_cultivatedGroundOnly; pieceModification.ComfortGroup = item.m_comfortGroup; pieceModification.ComfortAmount = item.m_comfort; pieceModification.GroundPlacement = item.m_groundPiece; pieceModification.SpaceRequired = item.m_spaceRequirement; pieceModification.AllowedInDungeon = item.m_allowedInDungeons; pieceModification.CraftingStationConnectionRadius = item.m_connectRadius; pieceModification.MustBeAvobeConnectedStation = item.m_mustBeAboveConnected; pieceModification.OnlyInSelectBiome = item.m_onlyInBiome; pieceModification.PieceCategory = item.m_category; pieceModification.PieceDescription = item.m_description; pieceModification.PieceName = item.m_name; pieceModification.prefab = ((Object)((Component)item).gameObject).name; if ((Object)(object)item.m_craftingStation != (Object)null) { pieceModification.RequiredToPlaceCraftingStation = ((Object)item.m_craftingStation).name; } pieceModification.IsUpgradeForStation = item.m_isUpgrade; List<DataObjects.SimpleRequirement> list = new List<DataObjects.SimpleRequirement>(); if (item.m_resources != null && item.m_resources.Length != 0) { Requirement[] resources = item.m_resources; foreach (Requirement val in resources) { try { list.Add(new DataObjects.SimpleRequirement { amount = val.m_amount, Prefab = ((Object)val.m_resItem).name, recover = val.m_recover }); } catch (Exception arg) { if (ValConfig.EnableDebugMode.Value) { Logger.LogWarning((object)$"Piece requirement setup error {val} \n{arg}"); } } } } pieceModification.requirements = list; if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Adding " + pieceModification.prefab + " to collection.")); } if (!pieceModificationCollection.PieceModifications.ContainsKey(pieceModification.prefab)) { pieceModificationCollection.PieceModifications.Add(pieceModification.prefab, pieceModification); } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Piece " + pieceModification.prefab + " Added.")); } } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Serializing and printing recipes."); } string value = ValConfig.yamlserializer.Serialize((object)pieceModificationCollection); streamWriter.WriteLine(value); Logger.LogInfo((object)("Recipes dumped to file " + text)); } } internal class PieceUpdater { private class PieceSnapshot { private Requirement[] resources; private CraftingStation craftingStation; private bool allowedInDungeons; private bool canBeRemoved; private PieceCategory category; private int comfort; private ComfortGroup comfortGroup; private float connectRadius; private string description; private bool enabled; private string name; private Biome onlyInBiome; private bool isUpgrade; private bool cultivatedGroundOnly; private bool mustBeAboveConnected; private float spaceRequirement; private bool groundPiece; public static PieceSnapshot From(Piece pcomp) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) return new PieceSnapshot { resources = pcomp.m_resources, craftingStation = pcomp.m_craftingStation, allowedInDungeons = pcomp.m_allowedInDungeons, canBeRemoved = pcomp.m_canBeRemoved, category = pcomp.m_category, comfort = pcomp.m_comfort, comfortGroup = pcomp.m_comfortGroup, connectRadius = pcomp.m_connectRadius, description = pcomp.m_description, enabled = pcomp.m_enabled, name = pcomp.m_name, onlyInBiome = pcomp.m_onlyInBiome, isUpgrade = pcomp.m_isUpgrade, cultivatedGroundOnly = pcomp.m_cultivatedGroundOnly, mustBeAboveConnected = pcomp.m_mustBeAboveConnected, spaceRequirement = pcomp.m_spaceRequirement, groundPiece = pcomp.m_groundPiece }; } public void WriteTo(Piece pcomp) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) pcomp.m_resources = resources; pcomp.m_craftingStation = craftingStation; pcomp.m_allowedInDungeons = allowedInDungeons; pcomp.m_canBeRemoved = canBeRemoved; pcomp.m_category = category; pcomp.m_comfort = comfort; pcomp.m_comfortGroup = comfortGroup; pcomp.m_connectRadius = connectRadius; pcomp.m_description = description; pcomp.m_enabled = enabled; pcomp.m_name = name; pcomp.m_onlyInBiome = onlyInBiome; pcomp.m_isUpgrade = isUpgrade; pcomp.m_cultivatedGroundOnly = cultivatedGroundOnly; pcomp.m_mustBeAboveConnected = mustBeAboveConnected; pcomp.m_spaceRequirement = spaceRequirement; pcomp.m_groundPiece = groundPiece; } } public static Dictionary<string, DataObjects.PieceModification> PiecesToModify = new Dictionary<string, DataObjects.PieceModification>(); public static List<DataObjects.TrackedPiece> TrackedPieces = new List<DataObjects.TrackedPiece>(); private static readonly Dictionary<string, PieceSnapshot> OriginalPieces = new Dictionary<string, PieceSnapshot>(); public static void InitialSychronization() { BuildPieceTracker(); PieceUpdateRunner(); } public static void PieceUpdateRunner() { Logger.LogInfo($"Applying {TrackedPieces.Count} piece modifications"); foreach (DataObjects.TrackedPiece trackedPiece in TrackedPieces) { ApplyPieceModifications(trackedPiece); } } public static void ApplyPieceModifications(DataObjects.TrackedPiece piece) { if (piece == null) { Logger.LogWarning("A tracked piece was null, this modification will be skipped."); return; } Logger.LogDebug($"Applying piece ({piece.prefab}) modification action: {piece.action}"); switch (piece.action) { case DataObjects.PieceAction.Disable: DisablePiece(piece); break; case DataObjects.PieceAction.Modify: ModifyPiece(piece); break; case DataObjects.PieceAction.Enable: EnablePiece(piece); break; } } public static void RevertPieceModifications() { if (OriginalPieces.Count == 0) { return; } Logger.LogInfo($"Reverting {OriginalPieces.Count} piece modifications"); foreach (KeyValuePair<string, PieceSnapshot> originalPiece in OriginalPieces) { RevertPiece(originalPiece.Key, originalPiece.Value); } } private static void RevertPiece(string prefabName, PieceSnapshot original) { Piece val = ResolvePiece(prefabName); if (!((Object)(object)val == (Object)null)) { original.WriteTo(val); Logger.LogDebug("Restored the original settings of " + prefabName + "."); } } private static void CaptureOriginal(string prefabName, Piece pcomp) { if (!string.IsNullOrEmpty(prefabName) && !((Object)(object)pcomp == (Object)null) && !OriginalPieces.ContainsKey(prefabName)) { OriginalPieces.Add(prefabName, PieceSnapshot.From(pcomp)); } } private static Piece ResolvePiece(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { Logger.LogWarning("A piece entry has no prefab configured, it will be skipped. Define a prefab to modify to fix this."); return null; } GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { Logger.LogWarning("Could not find a prefab named " + prefabName + ", it will be skipped. Check that whatever provides this piece is installed."); return null; } Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { Logger.LogWarning("Prefab " + prefabName + " has no Piece component, it will be skipped."); } return component; } public static void EnablePiece(DataObjects.TrackedPiece piece) { Logger.LogDebug("Enabling " + piece.prefab); Piece val = ResolvePiece(piece.prefab); if (!((Object)(object)val == (Object)null)) { CaptureOriginal(piece.prefab, val); val.m_enabled = true; } } private static void ModifyPiece(DataObjects.TrackedPiece piece) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) Logger.LogDebug("Modifying " + piece.prefab); Piece val = ResolvePiece(piece.prefab); CaptureOriginal(piece.prefab, val); if ((Object)(object)val != (Object)null) { if (piece.updatedRequirements != null) { val.m_resources = piece.updatedRequirements; } val.m_craftingStation = piece.RequiredToPlaceCraftingStation; val.m_allowedInDungeons = piece.AllowedInDungeon; val.m_canBeRemoved = piece.CanBeDeconstructed; val.m_category = piece.PieceCategory; if (piece.ComfortAmount != -1) { val.m_comfort = piece.ComfortAmount; } if ((int)piece.ComfortGroup != 0) { val.m_comfortGroup = piece.ComfortGroup; } if (piece.CraftingStationConnectionRadius != -1f) { val.m_connectRadius = piece.CraftingStationConnectionRadius; } if (piece.PieceDescription != null) { val.m_description = piece.PieceDescription; } val.m_enabled = piece.EnablePiece; if (piece.PieceName != null) { val.m_name = piece.PieceName; } val.m_onlyInBiome = piece.OnlyInBiome; val.m_isUpgrade = piece.IsUpgradeForStation; val.m_cultivatedGroundOnly = piece.CultivatedGroundOnly; val.m_mustBeAboveConnected = piece.MustBeAvobeConnectedStation; if (piece.SpaceRequired != -1f) { val.m_spaceRequirement = piece.SpaceRequired; } val.m_groundPiece = piece.GroundPlacement; } } private static void DisablePiece(DataObjects.TrackedPiece piece) { Logger.LogDebug("Disabling " + piece.prefab); Piece val = ResolvePiece(piece.prefab); if (!((Object)(object)val == (Object)null)) { CaptureOriginal(piece.prefab, val); val.m_enabled = false; } } public static void BuildPieceTracker() { //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Invalid comparison between Unknown and I4 //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown TrackedPieces.Clear(); foreach (KeyValuePair<string, DataObjects.PieceModification> item in PiecesToModify) { if (item.Key == null) { continue; } Logger.LogInfo("Constructing piece modification for " + item.Key); DataObjects.TrackedPiece trackedPiece = new DataObjects.TrackedPiece(); trackedPiece.action = item.Value.action; trackedPiece.prefab = item.Value.prefab; Piece val = ResolvePiece(item.Value.prefab); if ((Object)(object)val == (Object)null) { continue; } if (item.Value.action == DataObjects.PieceAction.Enable || item.Value.action == DataObjects.PieceAction.Disable) { TrackedPieces.Add(trackedPiece); continue; } if (item.Value.requirements == null) { trackedPiece.updatedRequirements = null; } else { List<Requirement> list = new List<Requirement>(); foreach (DataObjects.SimpleRequirement requirement in item.Value.requirements) { if (requirement == null || string.IsNullOrEmpty(requirement.Prefab)) { Logger.LogWarning("A requirement on " + item.Key + " has no prefab set, it will be ignored."); continue; } GameObject prefab = PrefabManager.Instance.GetPrefab(requirement.Prefab); ItemDrop val2 = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<ItemDrop>()); if ((Object)(object)val2 == (Object)null) { Logger.LogWarning("Could not find an itemDrop for resource with name: " + requirement.Prefab + ", this requirement will be ignored."); continue; } list.Add(new Requirement { m_amount = requirement.amount, m_resItem = val2, m_recover = requirement.recover }); Logger.LogDebug($"Building requirement with res:{((Object)val2).name} amount:{requirement.amount}"); } trackedPiece.updatedRequirements = list.ToArray(); } if (item.Value.RequiredToPlaceCraftingStation != null && item.Value.RequiredToPlaceCraftingStation != "") { if (item.Value.RequiredToPlaceCraftingStation.ToLower() == "none") { trackedPiece.RequiredToPlaceCraftingStation = null; } else { GameObject prefab2 = PrefabManager.Instance.GetPrefab(item.Value.RequiredToPlaceCraftingStation); CraftingStation val3 = ((prefab2 != null) ? prefab2.GetComponent<CraftingStation>() : null); if ((Object)(object)val3 != (Object)null) { trackedPiece.RequiredToPlaceCraftingStation = val3; } else { Logger.LogWarning("Could not link required crafting station, are you sure a crafting station exists with piecename: " + item.Value.RequiredToPlaceCraftingStation); } } } else { trackedPiece.RequiredToPlaceCraftingStation = val.m_craftingStation; } trackedPiece.IsUpgradeForStation = item.Value.IsUpgradeForStation; trackedPiece.AllowedInDungeon = item.Value.AllowedInDungeon; trackedPiece.CanBeDeconstructed = item.Value.CanBeDeconstructed; trackedPiece.ComfortAmount = item.Value.ComfortAmount; trackedPiece.ComfortGroup = item.Value.ComfortGroup; trackedPiece.CraftingStationConnectionRadius = item.Value.CraftingStationConnectionRadius; trackedPiece.PieceDescription = item.Value.PieceDescription; trackedPiece.PieceName = item.Value.PieceName; trackedPiece.EnablePiece = item.Value.EnablePiece; trackedPiece.CultivatedGroundOnly = item.Value.CultivatedGroundOnly; trackedPiece.MustBeAvobeConnectedStation = item.Value.MustBeAvobeConnectedStation; trackedPiece.SpaceRequired = item.Value.SpaceRequired; trackedPiece.GroundPlacement = item.Value.GroundPlacement; if ((int)item.Value.PieceCategory != 100) { trackedPiece.PieceCategory = item.Value.PieceCategory; } else { trackedPiece.PieceCategory = val.m_category; } TrackedPieces.Add(trackedPiece); } } public static void UpdatePieceModificationsFromList(List<DataObjects.PieceModificationCollection> lPieceMods) { PiecesToModify.Clear(); foreach (DataObjects.PieceModificationCollection lPieceMod in lPieceMods) { foreach (KeyValuePair<string, DataObjects.PieceModification> pieceModification in lPieceMod.PieceModifications) { PiecesToModify.Add(pieceModification.Key, pieceModification.Value); } } } public static void UpdatePieceModificationsFromRPC(string rpcRecieved) { Logger.LogInfo("RPC Recieved: " + rpcRecieved); Logger.LogInfo($"RPC Data: {rpcRecieved.Length}"); UpdatePieceModifications(ValConfig.yamldeserializer.Deserialize<DataObjects.PieceModificationCollection>(rpcRecieved)); } public static void UpdatePieceModifications(DataObjects.PieceModificationCollection PieceMods) { PiecesToModify.Clear(); foreach (KeyValuePair<string, DataObjects.PieceModification> pieceModification in PieceMods.PieceModifications) { PiecesToModify.Add(pieceModification.Key, pieceModification.Value); } } } internal class RecipeReloadCommand : ConsoleCommand { public override string Name => "RM_Recipes_Reload"; public override string Help => "Resynchronizes recipes."; public override bool IsCheat => true; public override void Run(string[] args) { RecipeUpdater.RecipeRevert(); ValConfig.ReloadRecipeFiles(); RecipeUpdater.BuildRecipesForTracking(); RecipeUpdater.SecondaryRecipeSync(); ValConfig.SendUpdatedRecipeConfigs(); } } internal class RecipeUnapplyCommand : ConsoleCommand { public override string Name => "RM_Recipes_Unapply"; public override string Help => "Removes recipe modifications."; public override bool IsCheat => true; public override void Run(string[] args) { RecipeUpdater.RecipeRevert(); } } internal class RecipePrintCommand : ConsoleCommand { public override string Name => "RM_Recipes_PrintAll"; public override string Help => "Prints all the recipes stored in the Object DB"; public override bool IsCheat => true; public override void Run(string[] args) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Starting to dump recipes"); } string text = Path.Combine(Paths.ConfigPath, "RecipeManager", "ObjectDBRecipes.yaml"); DataObjects.RecipeModificationCollection recipeModificationCollection = new DataObjects.RecipeModificationCollection(); using StreamWriter streamWriter = new StreamWriter(text); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Loading recipes from ODB"); } foreach (Recipe item in ObjectDB.instance.m_recipes.ToList()) { if ((Object)(object)item == (Object)null || ((Object)item).name == null) { continue; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Building Recipe " + ((Object)item).name)); } DataObjects.RecipeModification recipeModification = new DataObjects.RecipeModification(); recipeModification.recipeName = ((Object)item).name; recipeModification.minStationLevel = (short)item.m_minStationLevel; recipeModification.craftAmount = (short)item.m_amount; recipeModification.action = DataObjects.Action.Enable; if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Checking for empty referenced objects"); } if ((Object)(object)item.m_craftingStation != (Object)null) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Adding crafting station"); } recipeModification.craftedAt = ((Object)item.m_craftingStation).name; } if ((Object)(object)item.m_repairStation != (Object)null) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Adding repair station"); } recipeModification.repairAt = ((Object)item.m_repairStation).name; } if ((Object)(object)item.m_item != (Object)null) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Adding prefab"); } recipeModification.prefab = ((Object)item.m_item).name; } DataObjects.SimpleRecipe simpleRecipe = new DataObjects.SimpleRecipe(); if (item.m_resources != null && item.m_resources.Length != 0) { simpleRecipe.anyOneResource = item.m_requireOnlyOneIngredient; if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Building resource requirements"); } Requirement[] resources = item.m_resources; foreach (Requirement val in resources) { try { DataObjects.Ingrediant ingrediant = new DataObjects.Ingrediant(); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Setting crafting cost"); } ingrediant.craftCost = (short)val.m_amount; if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Setting upgrade cost"); } ingrediant.upgradeCost = (short)val.m_amountPerLevel; if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Setting prefab name"); } if ((Object)(object)val.m_resItem != (Object)null) { ingrediant.prefab = ((Object)val.m_resItem).name; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Adding to ingrediants list"); } simpleRecipe.ingredients.Add(ingrediant); } catch (Exception arg) { if (ValConfig.EnableDebugMode.Value) { Logger.LogWarning((object)$"Requirement did not contain all of the details required to set an ingrediant {val} \n{arg}"); } } } } if (simpleRecipe.ingredients != null && simpleRecipe.ingredients.Count > 0) { recipeModification.recipe = simpleRecipe; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Adding " + ((Object)item).name + " to collection.")); } if (recipeModificationCollection.RecipeModifications.ContainsKey(((Object)item).name)) { try { int num = Random.Range(0, 1000); recipeModificationCollection.RecipeModifications.Add(((Object)item).name + $"_{num}", recipeModification); Logger.LogWarning((object)$"{((Object)item).name} was already added to the list of recipes and will be renamed {((Object)item).name}_{num}, please use unique recipe names."); } catch { Logger.LogWarning((object)(((Object)item).name + " was already added to the list of recipes and will be skipped, please use unique recipe names.")); } } else { recipeModificationCollection.RecipeModifications.Add(((Object)item).name, recipeModification); } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Recipe " + ((Object)item).name + " Added.")); } } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Serializing and printing recipes."); } string value = ValConfig.yamlserializer.Serialize((object)recipeModificationCollection); streamWriter.WriteLine(value); Logger.LogInfo((object)("Recipes dumped to file " + text)); } } internal class RecipeUpdater { public static Dictionary<string, DataObjects.RecipeModification> RecipesToModify = new Dictionary<string, DataObjects.RecipeModification>(); public static List<DataObjects.TrackedRecipe> TrackedRecipes = new List<DataObjects.TrackedRecipe>(); public static void SecondaryRecipeSync() { if (TrackedRecipes.Count == 0) { return; } Logger.LogInfo((object)$"Validating {TrackedRecipes.Count} Recipe modifications"); foreach (DataObjects.TrackedRecipe trackedRecipe in TrackedRecipes) { if (!CheckIfRecipeWasModified(trackedRecipe)) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Tracked " + trackedRecipe.prefab + " recipe still has its original recipe in the db. Modifying.")); } ApplyRecipeModifcations(trackedRecipe); } } } public static void RecipeRevert() { foreach (DataObjects.TrackedRecipe trackedRecipe in TrackedRecipes) { ReverseRecipeModifications(trackedRecipe); } } public static void InitialRecipesAndSynchronize() { BuildRecipesForTracking(); RecipeUpdateRunner(); } public static void RecipeUpdateRunner() { Logger.LogDebug((object)$"Applying {TrackedRecipes.Count} Recipe modifications"); foreach (DataObjects.TrackedRecipe trackedRecipe in TrackedRecipes) { ApplyRecipeModifcations(trackedRecipe); } } private static bool HasTargetsForAction(DataObjects.TrackedRecipe tracked_recipe, string verb) { if (tracked_recipe == null) { Logger.LogWarning((object)("A tracked recipe was null and cannot be " + verb + ", skipping it.")); return false; } if ((tracked_recipe.action == DataObjects.Action.Disable || tracked_recipe.action == DataObjects.Action.Enable || tracked_recipe.action == DataObjects.Action.Delete || tracked_recipe.action == DataObjects.Action.Modify) && (Object)(object)tracked_recipe.originalRecipe == (Object)null) { Logger.LogWarning((object)("No existing recipe could be found for " + tracked_recipe.prefab + ", so it cannot be " + verb + ". Check the prefab or recipeName in the config, RM_Recipes_PrintAll lists the recipes that exist.")); return false; } if ((tracked_recipe.action == DataObjects.Action.Add || tracked_recipe.action == DataObjects.Action.Modify) && (Object)(object)tracked_recipe.updatedRecipe == (Object)null) { Logger.LogWarning((object)("No replacement recipe could be built for " + tracked_recipe.prefab + ", so it cannot be " + verb + ". Check that the entry has a valid recipe block.")); return false; } return true; } public static void ApplyRecipeModifcations(DataObjects.TrackedRecipe tracked_recipe) { if (!HasTargetsForAction(tracked_recipe, "applied")) { return; } if ((Object)(object)ObjectDB.instance == (Object)null) { Logger.LogWarning((object)("The object database is not available yet, the modification for " + tracked_recipe.prefab + " will be skipped.")); return; } if (ValConfig.EnableDebugMode.Value) { if ((Object)(object)tracked_recipe.updatedRecipe != (Object)null) { string text = ""; Requirement[] array = (Requirement[])(((object)tracked_recipe.updatedRecipe.m_resources) ?? ((object)new Requirement[0])); foreach (Requirement val in array) { text += $" {val.m_resItem},{val.m_amount},{val.m_amountPerLevel}"; } Logger.LogInfo((object)("Applying Updated Recipe: " + ((Object)tracked_recipe.updatedRecipe).name + "\n" + $"amount:{tracked_recipe.updatedRecipe.m_amount}\n" + $"enabled:{tracked_recipe.updatedRecipe.m_enabled}\n" + $"craftingStation:{tracked_recipe.updatedRecipe.m_craftingStation}\n" + $"reqStationLevel:{tracked_recipe.updatedRecipe.m_minStationLevel}\n" + $"reqOneIngrediant:{tracked_recipe.updatedRecipe.m_requireOnlyOneIngredient}\n" + "resources:" + text)); } if ((Object)(object)tracked_recipe.originalRecipe != (Object)null) { string text2 = ""; Requirement[] array = (Requirement[])(((object)tracked_recipe.originalRecipe.m_resources) ?? ((object)new Requirement[0])); foreach (Requirement val2 in array) { text2 += $" {val2.m_resItem},{val2.m_amount},{val2.m_amountPerLevel}"; } Logger.LogInfo((object)("Targeting Original Recipe: " + ((Object)tracked_recipe.originalRecipe).name + "\n" + $"amount:{tracked_recipe.originalRecipe.m_amount}\n" + $"enabled:{tracked_recipe.originalRecipe.m_enabled}\n" + $"amount:{tracked_recipe.originalRecipe.m_amount}\n" + $"craftingStation:{tracked_recipe.originalRecipe.m_craftingStation}\n" + $"reqStationLevel:{tracked_recipe.originalRecipe.m_minStationLevel}\n" + $"reqOneIngrediant:{tracked_recipe.originalRecipe.m_requireOnlyOneIngredient}\n" + "resources:" + text2)); } } bool flag = false; if (tracked_recipe.action == DataObjects.Action.Disable) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Disable Action called for " + tracked_recipe.prefab + " recipe")); } flag = DisableRecipe(tracked_recipe.originalRecipe); } if (tracked_recipe.action == DataObjects.Action.Delete) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Delete Action called for " + tracked_recipe.prefab + " recipe")); } flag = DeleteRecipe(tracked_recipe.originalRecipe); } if (tracked_recipe.action == DataObjects.Action.Modify) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Modify Action called for " + tracked_recipe.prefab + " recipe")); } if (ObjectDB.instance.m_recipes.Contains(tracked_recipe.updatedRecipe)) { DeleteRecipe(tracked_recipe.originalRecipe); flag = true; } else if (ObjectDB.instance.m_recipes.Contains(tracked_recipe.originalRecipe)) { flag = ModifyRecipeInODB(tracked_recipe.originalRecipe, tracked_recipe.updatedRecipe); ModifyRecipeInJotunnManager(tracked_recipe.originalCustomRecipe, tracked_recipe.updatedCustomRecipe); } } if (tracked_recipe.action == DataObjects.Action.Add) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Add Action called for " + tracked_recipe.prefab + " recipe")); } flag = AddRecipe(tracked_recipe.updatedRecipe); } if (tracked_recipe.action == DataObjects.Action.Enable) { if (ValConfig.EnableDebugMode.Value) { Logger.LogWarning((object)("Enable Action called for " + tracked_recipe.prefab + " recipe. Are you sure you wanted that? Most recipes are already enabled.")); } flag = EnableRecipe(tracked_recipe.originalRecipe); } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)$"{tracked_recipe.prefab} recipe update applied? {flag}"); } } public static void ReverseRecipeModifications(DataObjects.TrackedRecipe tracked_recipe) { if (!HasTargetsForAction(tracked_recipe, "reverted")) { return; } if ((Object)(object)ObjectDB.instance == (Object)null) { Logger.LogWarning((object)("The object database is not available yet, the revert for " + tracked_recipe.prefab + " will be skipped.")); return; } bool flag = false; if (tracked_recipe.action == DataObjects.Action.Disable) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Reverting disable for " + tracked_recipe.prefab + " recipe")); } flag = EnableRecipe(tracked_recipe.originalRecipe); } if (tracked_recipe.action == DataObjects.Action.Delete) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Reverting delete for " + tracked_recipe.prefab + " recipe")); } flag = AddRecipe(tracked_recipe.originalRecipe); } if (tracked_recipe.action == DataObjects.Action.Modify) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Reversing modify for " + tracked_recipe.prefab + " recipe")); } flag = ModifyRecipeInODB(tracked_recipe.updatedRecipe, tracked_recipe.originalRecipe); ModifyRecipeInJotunnManager(tracked_recipe.updatedCustomRecipe, tracked_recipe.originalCustomRecipe); } if (tracked_recipe.action == DataObjects.Action.Add) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Reverting add for " + tracked_recipe.prefab + " recipe")); } flag = DeleteRecipe(tracked_recipe.updatedRecipe); } if (tracked_recipe.action == DataObjects.Action.Enable) { flag = DisableRecipe(tracked_recipe.originalRecipe); } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)$"{tracked_recipe.prefab} recipe modification reverted? {flag}"); } } public static bool CheckIfRecipeWasModified(DataObjects.TrackedRecipe trackedRecipe) { if (trackedRecipe == null || (Object)(object)ObjectDB.instance == (Object)null) { return true; } bool flag = true; if ((trackedRecipe.action == DataObjects.Action.Modify || trackedRecipe.action == DataObjects.Action.Delete) && ObjectDB.instance.m_recipes.IndexOf(trackedRecipe.originalRecipe) > 0) { flag = false; } if (trackedRecipe.action == DataObjects.Action.Add && ObjectDB.instance.m_recipes.IndexOf(trackedRecipe.updatedRecipe) < 0) { flag = false; } if (trackedRecipe.action == DataObjects.Action.Enable || trackedRecipe.action == DataObjects.Action.Disable) { flag = false; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)$"recipe {trackedRecipe.recipeName} already modified? {flag}"); } return flag; } public static void BuildRecipesForTracking() { //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Expected O, but got Unknown //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Expected O, but got Unknown //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Expected O, but got Unknown if (RecipesToModify.Count == 0) { return; } TrackedRecipes.Clear(); foreach (KeyValuePair<string, DataObjects.RecipeModification> item2 in RecipesToModify) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)("Constructing modification details for " + item2.Key)); } DataObjects.TrackedRecipe trackedRecipe = new DataObjects.TrackedRecipe(); trackedRecipe.action = item2.Value.action; trackedRecipe.prefab = item2.Value.prefab; int num = -1; if (item2.Value.recipeName != null) { num = RecipeIndexForRecipeName(item2.Value.recipeName); trackedRecipe.recipeName = item2.Value.recipeName; } if (num == -1) { num = RecipeIndexForPrefab(item2.Value.prefab); } if (num > -1) { trackedRecipe.originalRecipe = ObjectDB.instance.m_recipes[num]; } else if (ValConfig.EnableDebugMode.Value) { Logger.LogWarning((object)("Could not find recipe for: " + item2.Value.prefab)); } CustomRecipe val; Recipe recipe; if (item2.Value.recipe != null) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Found custom recipe modifications, building out definition."); } RequirementConfig[] array = (RequirementConfig[])(object)new RequirementConfig[0]; if (!item2.Value.recipe.noRecipeCost) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo((object)"Setting recipe cost requirements."); } if (item2.Value.recipe.ingredients == null)