Decompiled source of RecipeManager v0.6.3

plugins/RecipeManager.dll

Decompiled 15 hours ago
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)