Decompiled source of EMUAdditions v1.1.1

plugins/EMUAdditions/EMUAdditions.dll

Decompiled 2 months ago
using System;
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.Versioning;
using BepInEx;
using BepInEx.Logging;
using EquinoxsModUtils.Additions.ContentAdders;
using EquinoxsModUtils.Additions.Patches;
using FluffyUnderware.DevTools.Extensions;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("EMUAdditions")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("EMUAdditions")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("163385b3-d393-47fc-8f18-a6b38a505f13")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace EquinoxsModUtils.Additions
{
	public static class EMUAdditions
	{
		public static class CustomData
		{
			private static Dictionary<string, object> customMachineData = new Dictionary<string, object>();

			private static bool hasCustomMachineDataLoaded = false;

			private static string dataFolder => EMUAdditionsPlugin.dataFolder;

			public static void Add<T>(uint instanceId, string name, T value)
			{
				if (!new List<string>
				{
					typeof(uint).ToString(),
					typeof(int).ToString(),
					typeof(float).ToString(),
					typeof(double).ToString(),
					typeof(bool).ToString(),
					typeof(string).ToString(),
					typeof(char).ToString()
				}.Contains(typeof(T).ToString()))
				{
					EMUAdditionsPlugin.Log.LogError((object)$"EMU cannot save custom data of type '{typeof(T)}', please use one of: uint, int, float, double, bool, string, char");
				}
				string key = $"{instanceId}-{name}-{typeof(T)}";
				if (!customMachineData.ContainsKey(key))
				{
					customMachineData.Add(key, value);
				}
			}

			public static void Update<T>(uint instanceId, string name, T value)
			{
				if (!new List<string>
				{
					typeof(uint).ToString(),
					typeof(int).ToString(),
					typeof(float).ToString(),
					typeof(double).ToString(),
					typeof(bool).ToString(),
					typeof(string).ToString(),
					typeof(char).ToString()
				}.Contains(typeof(T).ToString()))
				{
					EMUAdditionsPlugin.Log.LogError((object)$"EMU cannot save custom data of type '{typeof(T)}', please use one of: uint, int, float, double, bool, string, char");
				}
				string text = $"{instanceId}-{name}-{typeof(T)}";
				if (!customMachineData.ContainsKey(text))
				{
					EMUAdditionsPlugin.Log.LogWarning((object)("Custom data with key '" + text + "' has not been added for machine yet, adding instead of updating."));
					Add(instanceId, name, value);
				}
				else
				{
					customMachineData[text] = value;
				}
			}

			public static T Get<T>(uint instanceId, string name)
			{
				if (!hasCustomMachineDataLoaded)
				{
					EMUAdditionsPlugin.Log.LogError((object)"GetCustomDataForMachine() called before custom data has loaded.");
					EMUAdditionsPlugin.Log.LogInfo((object)"Try using the SaveStateLoaded event or hasSaveStateLoaded variable");
					return default(T);
				}
				if (!new List<string>
				{
					typeof(uint).ToString(),
					typeof(int).ToString(),
					typeof(float).ToString(),
					typeof(double).ToString(),
					typeof(bool).ToString(),
					typeof(string).ToString(),
					typeof(char).ToString()
				}.Contains(typeof(T).ToString()))
				{
					EMUAdditionsPlugin.Log.LogError((object)$"EMU cannot save custom data of type '{typeof(T)}', please use one of: uint, int, float, double, bool, string, char");
				}
				string text = $"{instanceId}-{name}-{typeof(T)}";
				if (customMachineData.ContainsKey(text))
				{
					return (T)customMachineData[text];
				}
				EMUAdditionsPlugin.Log.LogError((object)("Could not find custom data with key '" + text + "'"));
				return default(T);
			}

			public static bool AnyExists(uint instanceId)
			{
				foreach (string key in customMachineData.Keys)
				{
					if (key.Split(new char[1] { '-' })[0] == instanceId.ToString())
					{
						return true;
					}
				}
				return false;
			}

			public static bool FieldExists<T>(uint instanceId, string name)
			{
				string key = $"{instanceId}-{name}-{typeof(T)}";
				return customMachineData.ContainsKey(key);
			}

			internal static void Save(string worldName)
			{
				List<string> list = new List<string>();
				foreach (KeyValuePair<string, object> customMachineDatum in customMachineData)
				{
					list.Add($"{customMachineDatum.Key}|{customMachineDatum.Value}");
				}
				Directory.CreateDirectory(dataFolder);
				File.WriteAllLines(dataFolder + "/" + worldName + " CustomData.txt", list);
			}

			internal static void Load(string worldName)
			{
				string path = dataFolder + "/" + worldName + " CustomData.txt";
				if (!File.Exists(path))
				{
					EMUAdditionsPlugin.LogWarning("No CustomData save file found for world '" + worldName + "'");
					return;
				}
				string[] array = File.ReadAllLines(path);
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(new char[1] { '|' });
					string text = array2[1];
					object obj = null;
					string text2 = array2[0];
					string text3 = text2.Split(new char[1] { '-' })[2];
					switch (text3)
					{
					case "System.UInt32":
						obj = uint.Parse(text);
						break;
					case "System.Int32":
						obj = int.Parse(text);
						break;
					case "System.Single":
						obj = float.Parse(text);
						break;
					case "System.Double":
						obj = double.Parse(text);
						break;
					case "System.Boolean":
						obj = bool.Parse(text);
						break;
					case "System.String":
						obj = text;
						break;
					case "System.Char":
						obj = char.Parse(text);
						break;
					default:
						EMUAdditionsPlugin.LogError("Cannot load custom data (key: '" + text2 + "') with unhandled type: '" + text3 + "'");
						continue;
					}
					customMachineData[text2] = obj;
				}
				hasCustomMachineDataLoaded = true;
				EMUAdditionsPlugin.LogInfo("Loaded custom machine data");
			}
		}

		public static void AddNewUnlock(NewUnlockDetails details, bool shouldLog = false)
		{
			if (!details.Validate())
			{
				EMUAdditionsPlugin.LogError("Abandoning attempt to add new Unlock '" + details.displayName + "'");
				return;
			}
			Unlock item = details.ConvertToUnlock();
			UnlockAdder.unlocksToAdd.Add(item);
			if (shouldLog)
			{
				EMUAdditionsPlugin.LogInfo("Successfully registered new Unlock '" + details.displayName + "' for adding to game");
			}
		}

		public static void AddNewResource(NewResourceDetails details, bool shouldLog = false)
		{
			if (!details.Validate())
			{
				EMUAdditionsPlugin.LogError("Abandoning attempt to add new Resource '" + details.name + "'");
				return;
			}
			ResourceAdder.resourcesToAdd.Add(details);
			if (shouldLog)
			{
				EMUAdditionsPlugin.LogInfo("Successfully registered new Resource '" + details.name + "' for adding to game");
			}
		}

		public static void AddNewRecipe(NewRecipeDetails details, bool shouldLog = false)
		{
			if (!details.Validate())
			{
				EMUAdditionsPlugin.LogError("Abandoning attempt to add new Recipe");
				return;
			}
			RecipeAdder.recipesToAdd.Add(details);
			if (shouldLog)
			{
				EMUAdditionsPlugin.LogInfo("Successfully registered new Recipe '" + details.GetUniqueName() + "' for adding to game");
			}
		}

		public static void AddNewSchematicsSubHeader(string title, string parentTitle, int priority, bool shouldLog = false)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			if (string.IsNullOrEmpty(title))
			{
				EMUAdditionsPlugin.LogError("New SchematicsSubHeader title cannot be null or empty");
				return;
			}
			if (string.IsNullOrEmpty(parentTitle))
			{
				EMUAdditionsPlugin.LogError("New SchematicsSubHeader '" + title + "' parentTitle cannot be null or empty");
				return;
			}
			SchematicsSubHeader val = (SchematicsSubHeader)ScriptableObject.CreateInstance(typeof(SchematicsSubHeader));
			val.title = title ?? "";
			val.priority = priority;
			SubHeaderAdder.subHeadersToAdd.Add(val);
			SubHeaderAdder.parents.Add(parentTitle);
			if (shouldLog)
			{
				EMUAdditionsPlugin.LogInfo("Successfully registered new SchematicsSubHeader '" + parentTitle + "/" + title + "' to be added to game");
			}
		}

		public static void AddNewMachine<T, V>(MachineDefinition<T, V> definition, NewResourceDetails details, bool shouldLog = false) where T : struct, IMachineInstance<T, V> where V : MachineDefinition<T, V>
		{
			if (!details.Validate())
			{
				EMUAdditionsPlugin.LogError("Abandoning attempt to add new Machine '" + details.name + "'");
				return;
			}
			((ResourceInfo)definition).rawName = details.name;
			MachineAdder.machinesToAdd.Add((ResourceInfo)(object)definition);
			MachineAdder.details.Add(details);
			if (shouldLog)
			{
				EMUAdditionsPlugin.LogInfo("Successfully registered new Machine '" + ((ResourceInfo)definition).displayName + "' for adding to game");
			}
		}

		public static void AddNewEquipment<T>(Equipment equipment, NewResourceDetails details, bool shouldLog = false) where T : ScriptableObject
		{
			if (!details.Validate())
			{
				EMUAdditionsPlugin.LogError("Abandoning attempt to add new Equipment '" + details.name + "'");
				return;
			}
			T val = ScriptableObject.CreateInstance<T>();
			ModUtils.SetPrivateField<Equipment>("_info", equipment, (object)val);
			((ResourceInfo)equipment.info).rawName = details.name;
			EquipmentAdder.equipmentToAdd.Add(equipment);
			EquipmentAdder.details.Add(details);
			if (shouldLog)
			{
				EMUAdditionsPlugin.LogInfo("Successfully registered new Equipment '" + details.name + "' for adding to game");
			}
		}
	}
	public class NewRecipeDetails
	{
		public string GUID;

		public CraftingMethod craftingMethod;

		public int craftTierRequired;

		public float duration;

		public List<RecipeResourceInfo> ingredients = new List<RecipeResourceInfo>();

		public List<RecipeResourceInfo> outputs = new List<RecipeResourceInfo>();

		public int sortPriority;

		public string unlockName;

		public string GetUniqueName()
		{
			return GUID + "-" + outputs[0].name;
		}

		public bool Validate()
		{
			if (outputs.Count == 0)
			{
				EMUAdditionsPlugin.LogError("New Recipe cannot have no outputs");
				return false;
			}
			if (ingredients.Count == 0)
			{
				EMUAdditionsPlugin.LogError("New Recipe cannot have no ingredients '" + GetUniqueName() + "'");
				return false;
			}
			if (string.IsNullOrEmpty(GUID))
			{
				EMUAdditionsPlugin.LogError("GUID cannot be null or empty for new Recipe '" + GetUniqueName() + "'");
				return false;
			}
			return true;
		}

		public SchematicsRecipeData ConvertToRecipe()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0012: 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)
			SchematicsRecipeData val = (SchematicsRecipeData)ScriptableObject.CreateInstance("SchematicsRecipeData");
			val.craftingMethod = craftingMethod;
			val.craftTierRequired = craftTierRequired;
			val.duration = duration;
			val.sortPriority = sortPriority;
			val.ingQuantities = new int[ingredients.Count];
			val.ingTypes = (ResourceInfo[])(object)new ResourceInfo[ingredients.Count];
			val.outputQuantities = new int[outputs.Count];
			val.outputTypes = (ResourceInfo[])(object)new ResourceInfo[outputs.Count];
			((Object)val).name = GetUniqueName();
			for (int i = 0; i < ingredients.Count; i++)
			{
				val.ingQuantities[i] = ingredients[i].quantity;
				ResourceInfo resourceInfoByNameUnsafe = ModUtils.GetResourceInfoByNameUnsafe(ingredients[i].name, false);
				val.ingTypes[i] = resourceInfoByNameUnsafe;
			}
			for (int j = 0; j < outputs.Count; j++)
			{
				val.outputQuantities[j] = outputs[j].quantity;
				ResourceInfo resourceInfoByNameUnsafe2 = ModUtils.GetResourceInfoByNameUnsafe(outputs[j].name, false);
				val.outputTypes[j] = resourceInfoByNameUnsafe2;
			}
			return val;
		}
	}
	public struct RecipeResourceInfo
	{
		public string name;

		public int quantity;

		public RecipeResourceInfo(string _name, int _quantity)
		{
			name = _name;
			quantity = _quantity;
		}
	}
	public class NewResourceDetails
	{
		public string parentName;

		public string name;

		public string description;

		public CraftingMethod craftingMethod;

		public int craftTierRequired;

		public float fuelAmount;

		public string headerTitle;

		public string subHeaderTitle;

		public int maxStackCount = 500;

		public Sprite sprite;

		public int sortPriority;

		public string unlockName;

		internal bool Validate()
		{
			if (string.IsNullOrEmpty(parentName))
			{
				EMUAdditionsPlugin.LogError("parentName cannot be null or empty for NewResourceDetails '" + name + "'");
				return false;
			}
			if (string.IsNullOrEmpty(name))
			{
				EMUAdditionsPlugin.LogError("name cannot be null or empty for NewResourceDetails");
				return false;
			}
			if (string.IsNullOrEmpty(description))
			{
				EMUAdditionsPlugin.LogError("description cannot be null or empty for NewResourceDetails '" + name + "'");
				return false;
			}
			return true;
		}

		internal ResourceInfo ConvertToResourceInfo()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			ResourceInfo obj = ScriptableObject.CreateInstance<ResourceInfo>();
			obj.craftingMethod = craftingMethod;
			obj.craftTierRequired = craftTierRequired;
			obj.description = description;
			obj.fuelAmount = fuelAmount;
			obj.maxStackCount = maxStackCount;
			obj.rawName = name;
			obj.rawSprite = sprite;
			obj.sortPriority = sortPriority;
			return obj;
		}
	}
	public class NewUnlockDetails
	{
		public string displayName;

		public string description;

		public TechCategory category;

		public ResearchTier requiredTier;

		public CoreType coreTypeNeeded;

		public int coreCountNeeded;

		public int treePosition;

		public List<string> dependencyNames = new List<string>();

		public Sprite sprite;

		internal bool Validate()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			if (dependencyNames.Count > 2)
			{
				EMUAdditionsPlugin.LogError("New Unlock '" + displayName + "' cannot have more than 2 dependencies");
				return false;
			}
			if ((int)coreTypeNeeded != 0 && (int)coreTypeNeeded != 2)
			{
				EMUAdditionsPlugin.LogError("New Unlock '" + displayName + "' need to use either Red (Purple in-game) or Green (Blue in-game) cores");
				return false;
			}
			if (!EMUAdditionsPlugin.IsTranslatableStringUnique(displayName))
			{
				EMUAdditionsPlugin.LogError("New Unlock displayName '" + displayName + "' is not unique");
				return false;
			}
			if (!EMUAdditionsPlugin.IsTranslatableStringUnique(description))
			{
				EMUAdditionsPlugin.LogWarning("New Unlock " + displayName + "'s description is not unique");
			}
			return true;
		}

		internal Unlock ConvertToUnlock()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//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_0049: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			Unlock val = (Unlock)ScriptableObject.CreateInstance(typeof(Unlock));
			val.category = category;
			val.coresNeeded = new List<RequiredCores>
			{
				new RequiredCores
				{
					type = coreTypeNeeded,
					number = coreCountNeeded
				}
			};
			val.isCoreTech = false;
			val.isDebugTech = false;
			val.numScansNeeded = 0;
			val.requiredTier = requiredTier;
			val.priority = 0;
			val.scanDuration = 1f;
			val.sprite = sprite;
			val.treePosition = treePosition;
			string hashString = LocsUtility.GetHashString(displayName);
			string hashString2 = LocsUtility.GetHashString(description);
			val.displayNameHash = hashString;
			val.descriptionHash = hashString2;
			EMUAdditionsPlugin.customTranslations[hashString] = displayName;
			EMUAdditionsPlugin.customTranslations[hashString2] = description;
			UnlockAdder.unlockDependencies.Add(hashString, dependencyNames);
			return val;
		}
	}
	internal static class Testing
	{
		internal static bool doUnlockTest;

		internal static bool doResourcePlusTest;

		internal static bool doMachineTest;

		public static void DoTests()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			if (doUnlockTest)
			{
				EMUAdditions.AddNewUnlock(new NewUnlockDetails
				{
					displayName = "Test Unlock 3",
					description = "Third new test unlock",
					category = (TechCategory)0,
					requiredTier = (ResearchTier)4,
					coreTypeNeeded = (CoreType)0,
					coreCountNeeded = 3,
					treePosition = 10
				});
			}
			if (doResourcePlusTest)
			{
				EMUAdditions.AddNewResource(new NewResourceDetails
				{
					parentName = "Limestone",
					name = "Limestone 3",
					description = "Limestone 3 Test",
					headerTitle = "Intermediates",
					subHeaderTitle = "Test Parts 2",
					craftingMethod = (CraftingMethod)0,
					craftTierRequired = 0,
					fuelAmount = 100f,
					sortPriority = 10,
					unlockName = "Basic Manufacturing"
				});
				EMUAdditions.AddNewRecipe(new NewRecipeDetails
				{
					GUID = "com.equinox.EMUAdditions",
					craftingMethod = (CraftingMethod)0,
					craftTierRequired = 0,
					duration = 0.1f,
					ingredients = new List<RecipeResourceInfo>
					{
						new RecipeResourceInfo
						{
							name = "Limestone",
							quantity = 2
						}
					},
					outputs = new List<RecipeResourceInfo>
					{
						new RecipeResourceInfo
						{
							name = "Limestone 3",
							quantity = 2
						}
					},
					sortPriority = 10,
					unlockName = "Basic Manufacturing"
				});
				EMUAdditions.AddNewSchematicsSubHeader("Test Parts 2", "Intermediates", 10);
			}
			if (doMachineTest)
			{
				NewResourceDetails details = new NewResourceDetails
				{
					name = "Void Chest",
					description = "Voids all items inserted into it.",
					craftingMethod = (CraftingMethod)0,
					craftTierRequired = 0,
					headerTitle = "Logistics",
					subHeaderTitle = "Utility",
					maxStackCount = 500,
					sortPriority = 999,
					unlockName = "Basic Logistics",
					parentName = "Container"
				};
				EMUAdditions.AddNewMachine<ChestInstance, ChestDefinition>((MachineDefinition<ChestInstance, ChestDefinition>)(object)ScriptableObject.CreateInstance<ChestDefinition>(), details, shouldLog: true);
				EMUAdditions.AddNewRecipe(new NewRecipeDetails
				{
					GUID = "com.equinox.EMUAdditions",
					craftingMethod = (CraftingMethod)0,
					craftTierRequired = 0,
					duration = 0.1f,
					ingredients = new List<RecipeResourceInfo>
					{
						new RecipeResourceInfo
						{
							name = "Iron Ingot",
							quantity = 10
						}
					},
					outputs = new List<RecipeResourceInfo>
					{
						new RecipeResourceInfo
						{
							name = "Void Chest",
							quantity = 1
						}
					},
					sortPriority = 10,
					unlockName = "Basic Logistics"
				});
			}
		}
	}
	[BepInPlugin("com.equinox.EMUAdditions", "EMUAdditions", "1.1.1")]
	public class EMUAdditionsPlugin : BaseUnityPlugin
	{
		internal const string MyGUID = "com.equinox.EMUAdditions";

		private const string PluginName = "EMUAdditions";

		private const string VersionString = "1.1.1";

		private static readonly Harmony Harmony = new Harmony("com.equinox.EMUAdditions");

		internal static ManualLogSource Log = new ManualLogSource("EMUAdditions");

		internal static Dictionary<string, string> customTranslations = new Dictionary<string, string>();

		internal static string dataFolder = Application.persistentDataPath + "/EMUAdditions";

		internal static Dictionary<string, int> idHistory = new Dictionary<string, int>();

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"PluginName: EMUAdditions, VersionString: 1.1.1 is loading...");
			Harmony.PatchAll();
			LoadIdHistory();
			UnlockAdder.LoadIdHistory();
			RecipeAdder.LoadIdHistory();
			SubHeaderAdder.LoadIdHistory();
			ApplyPatches();
			ModUtils.GameDefinesLoaded += OnGameDefinesLoaded;
			ModUtils.SaveStateLoaded += OnSaveStateLoaded;
			ModUtils.GameSaved += OnGameSaved;
			Testing.DoTests();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"PluginName: EMUAdditions, VersionString: 1.1.1 is loaded.");
		}

		private void Update()
		{
		}

		private void OnGameDefinesLoaded(object sender, EventArgs e)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			UnlockAdder.AddRegisteredUnlocks();
			if (Testing.doMachineTest)
			{
				ChestDefinition val = (ChestDefinition)ModUtils.GetResourceInfoByName("Void Chest", false);
				((BuilderInfo)val).inventorySizes = new List<Vector2Int>
				{
					new Vector2Int(1, 1)
				};
				((BuilderInfo)val).invSizeOutput = new Vector2Int(1, 1);
			}
		}

		private void OnSaveStateLoaded(object sender, EventArgs e)
		{
			EMUAdditions.CustomData.Load(SaveState.instance.metadata.worldName);
			RecipeAdder.FetchUnlocks();
			ResourceAdder.FetchUnlocks();
			MachineAdder.FetchUnlocks();
		}

		private void OnGameSaved(object sender, EventArgs e)
		{
			EMUAdditions.CustomData.Save(sender.ToString());
		}

		internal static void LogInfo(string message)
		{
			Log.LogInfo((object)message);
		}

		internal static void LogWarning(string message)
		{
			Log.LogWarning((object)message);
		}

		internal static void LogError(string message)
		{
			Log.LogError((object)message);
		}

		internal static bool IsTranslatableStringUnique(string input)
		{
			return !customTranslations.ContainsValue(input);
		}

		private void ApplyPatches()
		{
			Harmony.CreateAndPatchAll(typeof(FlowManagerPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(GameDefinesPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(LocsUtilityPatch), (string)null);
		}

		internal static void SaveIdHistory()
		{
			Directory.CreateDirectory(dataFolder);
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, int> item in idHistory)
			{
				list.Add($"{item.Key}|{item.Value}");
			}
			File.WriteAllLines(dataFolder + "/Id History.txt", list);
		}

		private void LoadIdHistory()
		{
			string path = dataFolder + "/Id History.txt";
			if (!File.Exists(path))
			{
				LogWarning("No Id History save file found");
				return;
			}
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '|' });
				idHistory.Add(array2[0], int.Parse(array2[1]));
			}
		}
	}
}
namespace EquinoxsModUtils.Additions.Patches
{
	internal class FlowManagerPatch
	{
		[HarmonyPatch(typeof(FlowManager), "ClearGameState")]
		[HarmonyPostfix]
		private static void ResetContentAdders()
		{
			GameDefinesPatch.loadedCustomData = false;
		}
	}
	internal class GameDefinesPatch
	{
		public static bool loadedCustomData = false;

		public static bool isFirstLoad = true;

		[HarmonyPatch(typeof(GameDefines), "GetMaxResId")]
		[HarmonyPrefix]
		private static void AddCustomData()
		{
			if (!loadedCustomData)
			{
				loadedCustomData = true;
				SubHeaderAdder.AddRegisteredSubHeaders();
				ResourceAdder.AddHistoricResources();
				MachineAdder.AddHistoricMachines();
				ResourceAdder.AddBrandNewResources();
				MachineAdder.AddBrandNewMachines();
				EquipmentAdder.AddHistoricEquipment();
				EquipmentAdder.AddBrandNewEquipment();
				ResourceAdder.FillMissingIds();
				RecipeAdder.AddRegisteredRecipes();
				ModUtils.SetPrivateStaticField<GameDefines>("_topResId", GameDefines.instance, (object)(-1));
				isFirstLoad = false;
			}
		}
	}
	internal class LocsUtilityPatch
	{
		[HarmonyPatch(typeof(LocsUtility), "TranslateStringFromHash", new Type[]
		{
			typeof(string),
			typeof(string),
			typeof(Object)
		})]
		[HarmonyPrefix]
		private static bool GetModdedTranslation(ref string __result, string hash)
		{
			if (string.IsNullOrEmpty(hash))
			{
				return true;
			}
			if (EMUAdditionsPlugin.customTranslations.ContainsKey(hash))
			{
				__result = EMUAdditionsPlugin.customTranslations[hash];
				return false;
			}
			return true;
		}
	}
}
namespace EquinoxsModUtils.Additions.ContentAdders
{
	internal static class EquipmentAdder
	{
		internal static List<Equipment> equipmentToAdd = new List<Equipment>();

		internal static List<NewResourceDetails> details = new List<NewResourceDetails>();

		internal static Dictionary<string, int> idHistory => EMUAdditionsPlugin.idHistory;

		internal static void AddHistoricEquipment()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			List<Equipment> list = equipmentToAdd.Where((Equipment equipment) => idHistory.ContainsKey("Equipment-" + ((ResourceInfo)equipment.info).displayName)).ToList();
			EMUAdditionsPlugin.LogInfo($"{list.Count} historic new Equipments have been registered for adding");
			for (int i = 0; i < list.Count; i++)
			{
				Equipment val = list[i];
				int index = equipmentToAdd.IndexOf(val);
				NewResourceDetails newResourceDetails = details[index];
				EquippableResourceInfo val2 = (EquippableResourceInfo)ModUtils.GetResourceInfoByNameUnsafe(newResourceDetails.parentName, false);
				EquippableResourceInfo info = val.info;
				ModUtils.CloneObject<EquippableResourceInfo>(val2, ref info);
				((ResourceInfo)info).rawName = newResourceDetails.name;
				((UniqueIdScriptableObject)info).uniqueId = idHistory["Equipment-" + ((ResourceInfo)info).displayName];
				AddEquipmentToGame(val);
				EMUAdditionsPlugin.LogInfo($"Added historic new Equipment '{((ResourceInfo)info).rawName}' to the game with id {((UniqueIdScriptableObject)info).uniqueId}");
			}
		}

		internal static void AddBrandNewEquipment()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			List<Equipment> list = equipmentToAdd.Where((Equipment equipment) => !idHistory.ContainsKey("Equipment-" + ((ResourceInfo)equipment.info).displayName)).ToList();
			EMUAdditionsPlugin.LogInfo($"{list.Count} brand new Equipments have been registered for adding");
			for (int i = 0; i < list.Count; i++)
			{
				Equipment val = list[i];
				int index = equipmentToAdd.IndexOf(val);
				NewResourceDetails newResourceDetails = details[index];
				EquippableResourceInfo val2 = (EquippableResourceInfo)ModUtils.GetResourceInfoByNameUnsafe(newResourceDetails.parentName, false);
				EquippableResourceInfo info = val.info;
				ModUtils.CloneObject<EquippableResourceInfo>(val2, ref info);
				((ResourceInfo)info).rawName = newResourceDetails.name;
				((UniqueIdScriptableObject)info).uniqueId = GetNewEquipmentId();
				idHistory.Add("Equipment-" + ((ResourceInfo)info).rawName, ((UniqueIdScriptableObject)info).uniqueId);
				AddEquipmentToGame(val);
				EMUAdditionsPlugin.LogInfo($"Added brand new Equipment '{((ResourceInfo)info).rawName}' to the game with id {((UniqueIdScriptableObject)info).uniqueId}");
			}
			EMUAdditionsPlugin.SaveIdHistory();
		}

		internal static void FetchUnlocks()
		{
			foreach (NewResourceDetails detail in details)
			{
				if (!string.IsNullOrEmpty(detail.name))
				{
					ResourceInfo resourceInfoByNameUnsafe = ModUtils.GetResourceInfoByNameUnsafe(detail.name, false);
					if (!((Object)(object)resourceInfoByNameUnsafe.unlock != (Object)null))
					{
						resourceInfoByNameUnsafe.unlock = ModUtils.GetUnlockByName(detail.unlockName, false);
					}
				}
			}
		}

		private static void AddEquipmentToGame(Equipment equipment)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			int index = equipmentToAdd.IndexOf(equipment);
			NewResourceDetails newResourceDetails = details[index];
			EquippableResourceInfo val = (EquippableResourceInfo)ModUtils.GetResourceInfoByNameUnsafe(newResourceDetails.parentName, false);
			((ResourceInfo)equipment.info).craftingMethod = newResourceDetails.craftingMethod;
			((ResourceInfo)equipment.info).craftTierRequired = newResourceDetails.craftTierRequired;
			((ResourceInfo)equipment.info).description = newResourceDetails.description;
			((ResourceInfo)equipment.info).maxStackCount = newResourceDetails.maxStackCount;
			((ResourceInfo)equipment.info).rawName = newResourceDetails.name;
			((ResourceInfo)equipment.info).rawSprite = newResourceDetails.sprite;
			((ResourceInfo)equipment.info).sortPriority = newResourceDetails.sortPriority;
			if (!string.IsNullOrEmpty(newResourceDetails.subHeaderTitle))
			{
				((ResourceInfo)equipment.info).headerType = ModUtils.GetSchematicsSubHeaderByTitle(newResourceDetails.headerTitle, newResourceDetails.subHeaderTitle, false);
			}
			if ((Object)(object)((ResourceInfo)equipment.info).sprite == (Object)null)
			{
				((ResourceInfo)equipment.info).rawSprite = ((ResourceInfo)val).sprite;
			}
			string hashString = LocsUtility.GetHashString(((ResourceInfo)equipment.info).displayName);
			string hashString2 = LocsUtility.GetHashString(((ResourceInfo)equipment.info).description);
			EMUAdditionsPlugin.customTranslations[hashString] = ((ResourceInfo)equipment.info).displayName;
			EMUAdditionsPlugin.customTranslations[hashString2] = ((ResourceInfo)equipment.info).description;
			GameDefines.instance.resources.Add((ResourceInfo)(object)equipment.info);
			ResourceNames.SafeResources.Add(((ResourceInfo)equipment.info).displayName);
			Dictionary<ResourceInfo, Equipment> dictionary = (Dictionary<ResourceInfo, Equipment>)ModUtils.GetPrivateField<PlayerEquipment>("equipmentLookup", Player.instance.equipment);
			dictionary.Add((ResourceInfo)(object)equipment.info, equipment);
			ModUtils.SetPrivateField<PlayerEquipment>("equipmentLookup", Player.instance.equipment, (object)dictionary);
			EMUAdditionsPlugin.LogInfo("Registered " + ((ResourceInfo)equipment.info).displayName + " with Player.instance.equipment");
			ResourceAdder.addedIds.Add(((UniqueIdScriptableObject)equipment.info).uniqueId);
		}

		private static int GetNewEquipmentId()
		{
			int num = 0;
			foreach (ResourceInfo resource in GameDefines.instance.resources)
			{
				if (((UniqueIdScriptableObject)resource).uniqueId > num)
				{
					num = ((UniqueIdScriptableObject)resource).uniqueId;
				}
			}
			foreach (int value in idHistory.Values)
			{
				if (value > num)
				{
					num = value;
				}
			}
			return num + 1;
		}
	}
	internal static class MachineAdder
	{
		internal static List<ResourceInfo> machinesToAdd = new List<ResourceInfo>();

		internal static List<NewResourceDetails> details = new List<NewResourceDetails>();

		internal static Dictionary<string, int> idHistory => EMUAdditionsPlugin.idHistory;

		internal static void AddHistoricMachines()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			List<ResourceInfo> list = machinesToAdd.Where((ResourceInfo machine) => idHistory.ContainsKey("Machine-" + machine.displayName)).ToList();
			EMUAdditionsPlugin.LogInfo($"{list.Count} historic new Machines have been registered for adding");
			for (int i = 0; i < list.Count; i++)
			{
				ResourceInfo val = list[i];
				int index = machinesToAdd.IndexOf(val);
				NewResourceDetails newResourceDetails = details[index];
				ModUtils.CloneObject<ResourceInfo>((ResourceInfo)(BuilderInfo)ModUtils.GetResourceInfoByNameUnsafe(newResourceDetails.parentName, false), ref val);
				val.rawName = newResourceDetails.name;
				((UniqueIdScriptableObject)val).uniqueId = idHistory["Machine-" + val.displayName];
				AddMachineToGame(val);
				EMUAdditionsPlugin.LogInfo($"Added historic new Machine '{val.rawName}' to the game with id {((UniqueIdScriptableObject)val).uniqueId}");
			}
		}

		internal static void AddBrandNewMachines()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			List<ResourceInfo> list = machinesToAdd.Where((ResourceInfo machine) => !idHistory.ContainsKey("Machine-" + machine.displayName)).ToList();
			EMUAdditionsPlugin.LogInfo($"{list.Count} brand new Machines have been registered for adding");
			for (int i = 0; i < list.Count; i++)
			{
				ResourceInfo val = list[i];
				int index = machinesToAdd.IndexOf(val);
				NewResourceDetails newResourceDetails = details[index];
				ModUtils.CloneObject<ResourceInfo>((ResourceInfo)(BuilderInfo)ModUtils.GetResourceInfoByNameUnsafe(newResourceDetails.parentName, false), ref val);
				val.rawName = newResourceDetails.name;
				((UniqueIdScriptableObject)val).uniqueId = GetNewMachineID();
				idHistory.Add("Machine-" + val.displayName, ((UniqueIdScriptableObject)val).uniqueId);
				AddMachineToGame(val);
				EMUAdditionsPlugin.LogInfo($"Added brand new Machine '{newResourceDetails.name}' to the game with id '{((UniqueIdScriptableObject)val).uniqueId}'");
			}
			EMUAdditionsPlugin.SaveIdHistory();
		}

		internal static void FetchUnlocks()
		{
			foreach (NewResourceDetails detail in details)
			{
				if (!string.IsNullOrEmpty(detail.name))
				{
					ResourceInfo resourceInfoByName = ModUtils.GetResourceInfoByName(detail.name, false);
					if (!((Object)(object)resourceInfoByName.unlock != (Object)null))
					{
						resourceInfoByName.unlock = ModUtils.GetUnlockByName(detail.unlockName, false);
					}
				}
			}
		}

		private static void AddMachineToGame(ResourceInfo machineDefinition)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			int index = machinesToAdd.IndexOf(machineDefinition);
			NewResourceDetails newResourceDetails = details[index];
			ResourceInfo resourceInfoByNameUnsafe = ModUtils.GetResourceInfoByNameUnsafe(newResourceDetails.parentName, false);
			machineDefinition.craftingMethod = newResourceDetails.craftingMethod;
			machineDefinition.craftTierRequired = newResourceDetails.craftTierRequired;
			machineDefinition.description = newResourceDetails.description;
			machineDefinition.maxStackCount = newResourceDetails.maxStackCount;
			machineDefinition.rawName = newResourceDetails.name;
			machineDefinition.rawSprite = newResourceDetails.sprite;
			machineDefinition.sortPriority = newResourceDetails.sortPriority;
			if (!string.IsNullOrEmpty(newResourceDetails.subHeaderTitle))
			{
				machineDefinition.headerType = ModUtils.GetSchematicsSubHeaderByTitle(newResourceDetails.headerTitle, newResourceDetails.subHeaderTitle, false);
			}
			if ((Object)(object)machineDefinition.sprite == (Object)null)
			{
				machineDefinition.rawSprite = resourceInfoByNameUnsafe.sprite;
			}
			string hashString = LocsUtility.GetHashString(machineDefinition.displayName);
			string hashString2 = LocsUtility.GetHashString(machineDefinition.description);
			EMUAdditionsPlugin.customTranslations[hashString] = machineDefinition.displayName;
			EMUAdditionsPlugin.customTranslations[hashString2] = machineDefinition.description;
			GameDefines.instance.resources.Add(machineDefinition);
			GameDefines.instance.buildableResources.Add((BuilderInfo)machineDefinition);
			ResourceNames.SafeResources.Add(machineDefinition.displayName);
			ResourceAdder.addedIds.Add(((UniqueIdScriptableObject)machineDefinition).uniqueId);
		}

		private static int GetNewMachineID()
		{
			int num = 0;
			foreach (ResourceInfo resource in GameDefines.instance.resources)
			{
				if (((UniqueIdScriptableObject)resource).uniqueId > num)
				{
					num = ((UniqueIdScriptableObject)resource).uniqueId;
				}
			}
			foreach (int value in idHistory.Values)
			{
				if (value > num)
				{
					num = value;
				}
			}
			return num + 1;
		}
	}
	internal static class RecipeAdder
	{
		internal static List<NewRecipeDetails> recipesToAdd = new List<NewRecipeDetails>();

		internal static Dictionary<string, int> idHistory = new Dictionary<string, int>();

		private static string dataFolder => EMUAdditionsPlugin.dataFolder;

		internal static void AddRegisteredRecipes()
		{
			EMUAdditionsPlugin.LogInfo($"{recipesToAdd.Count} new Recipes have been registered for adding");
			foreach (NewRecipeDetails item in recipesToAdd.Where((NewRecipeDetails recipe) => idHistory.ContainsKey(recipe.GetUniqueName())).ToList())
			{
				SchematicsRecipeData recipe2 = item.ConvertToRecipe();
				((UniqueIdScriptableObject)recipe2).uniqueId = idHistory[item.GetUniqueName()];
				AddRecipeToGame(item, ref recipe2);
				EMUAdditionsPlugin.LogInfo($"Added historic new Recipe '{item.GetUniqueName()}' to the game with id {((UniqueIdScriptableObject)recipe2).uniqueId}");
			}
			foreach (NewRecipeDetails item2 in recipesToAdd.Where((NewRecipeDetails recipe) => !idHistory.ContainsKey(recipe.GetUniqueName())).ToList())
			{
				SchematicsRecipeData recipe3 = item2.ConvertToRecipe();
				((UniqueIdScriptableObject)recipe3).uniqueId = GetNewRecipeID();
				idHistory.Add(item2.GetUniqueName(), ((UniqueIdScriptableObject)recipe3).uniqueId);
				AddRecipeToGame(item2, ref recipe3);
				EMUAdditionsPlugin.LogInfo($"Added brand new Recipe '{item2.GetUniqueName()}' to the game with id {((UniqueIdScriptableObject)recipe3).uniqueId}");
			}
			SaveIdHistory();
		}

		internal static void FetchUnlocks()
		{
			foreach (NewRecipeDetails item in recipesToAdd)
			{
				if (string.IsNullOrEmpty(item.unlockName))
				{
					continue;
				}
				List<int> list = new List<int>();
				List<int> list2 = new List<int>();
				foreach (RecipeResourceInfo ingredient in item.ingredients)
				{
					list.Add(ModUtils.GetResourceIDByName(ingredient.name, false));
				}
				foreach (RecipeResourceInfo output in item.outputs)
				{
					list2.Add(ModUtils.GetResourceIDByName(output.name, false));
				}
				SchematicsRecipeData val = ModUtils.TryFindRecipe(list, list2, false);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.unlock != (Object)null))
				{
					val.unlock = ModUtils.GetUnlockByName(item.unlockName, false);
				}
			}
		}

		private static void AddRecipeToGame(NewRecipeDetails details, ref SchematicsRecipeData recipe)
		{
			GameDefines.instance.schematicsRecipeEntries.Add(recipe);
		}

		private static int GetNewRecipeID()
		{
			int num = 0;
			foreach (SchematicsRecipeData schematicsRecipeEntry in GameDefines.instance.schematicsRecipeEntries)
			{
				if (((UniqueIdScriptableObject)schematicsRecipeEntry).uniqueId > num)
				{
					num = ((UniqueIdScriptableObject)schematicsRecipeEntry).uniqueId;
				}
			}
			foreach (int value in idHistory.Values)
			{
				if (value > num)
				{
					num = value;
				}
			}
			return num + 1;
		}

		private static void SaveIdHistory()
		{
			Directory.CreateDirectory(dataFolder);
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, int> item in idHistory)
			{
				list.Add($"{item.Key}|{item.Value}");
			}
			File.WriteAllLines(dataFolder + "/Recipe Id History.txt", list);
		}

		internal static void LoadIdHistory()
		{
			string path = dataFolder + "/Recipe Id History.txt";
			if (!File.Exists(path))
			{
				EMUAdditionsPlugin.LogWarning("No Recipe Id History save file found");
				return;
			}
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '|' });
				idHistory.Add(array2[0], int.Parse(array2[1]));
			}
		}
	}
	internal static class ResourceAdder
	{
		internal static List<NewResourceDetails> resourcesToAdd = new List<NewResourceDetails>();

		internal static List<int> addedIds = new List<int>();

		internal static Dictionary<string, int> idHistory => EMUAdditionsPlugin.idHistory;

		internal static void AddHistoricResources()
		{
			List<NewResourceDetails> list = resourcesToAdd.Where((NewResourceDetails details) => idHistory.ContainsKey("Resource-" + details.name)).ToList();
			EMUAdditionsPlugin.LogInfo($"{list.Count} historic new Resources have been registered for adding");
			for (int i = 0; i < list.Count; i++)
			{
				NewResourceDetails newResourceDetails = list[i];
				ResourceInfo resource = newResourceDetails.ConvertToResourceInfo();
				((UniqueIdScriptableObject)resource).uniqueId = idHistory["Resource-" + newResourceDetails.name];
				AddResourceToGame(newResourceDetails, ref resource);
				EMUAdditionsPlugin.LogInfo($"Added historic new Resource '{newResourceDetails.name}' to the game with id {((UniqueIdScriptableObject)resource).uniqueId}");
			}
		}

		internal static void AddBrandNewResources()
		{
			List<NewResourceDetails> list = resourcesToAdd.Where((NewResourceDetails details) => !idHistory.ContainsKey("Resource-" + details.name)).ToList();
			EMUAdditionsPlugin.LogInfo($"{list.Count} brand new Resources have been registered for adding");
			for (int i = 0; i < list.Count; i++)
			{
				NewResourceDetails newResourceDetails = list[i];
				ResourceInfo resource = newResourceDetails.ConvertToResourceInfo();
				((UniqueIdScriptableObject)resource).uniqueId = GetNewResourceID();
				idHistory.Add("Resource-" + newResourceDetails.name, ((UniqueIdScriptableObject)resource).uniqueId);
				AddResourceToGame(newResourceDetails, ref resource);
				EMUAdditionsPlugin.LogInfo($"Added brand new Resource '{newResourceDetails.name}' to the game with id {((UniqueIdScriptableObject)resource).uniqueId}");
			}
			EMUAdditionsPlugin.SaveIdHistory();
		}

		internal static void FillMissingIds()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			foreach (int value in idHistory.Values)
			{
				if (!addedIds.Contains(value))
				{
					EMUAdditionsPlugin.LogWarning($"Historic ResourceId {value} has not added been added this launch");
					ResourceInfo resourceInfoByNameUnsafe = ModUtils.GetResourceInfoByNameUnsafe("SharkRepellant", false);
					ResourceInfo val = (ResourceInfo)ScriptableObject.CreateInstance(typeof(ResourceInfo));
					((Object)val).name = "EMU Hidden Resource";
					val.redacted = true;
					((UniqueIdScriptableObject)val).uniqueId = value;
					val.rawConveyorResourcePrefab = resourceInfoByNameUnsafe.rawConveyorResourcePrefab;
					val.headerType = resourceInfoByNameUnsafe.headerType;
					GameDefines.instance.resources.Add(val);
				}
			}
		}

		internal static void FetchUnlocks()
		{
			foreach (NewResourceDetails item in resourcesToAdd)
			{
				if (!string.IsNullOrEmpty(item.unlockName))
				{
					ResourceInfo resourceInfoByName = ModUtils.GetResourceInfoByName(item.name, false);
					if (!((Object)(object)resourceInfoByName.unlock != (Object)null))
					{
						resourceInfoByName.unlock = ModUtils.GetUnlockByName(item.unlockName, false);
					}
				}
			}
		}

		private static void AddResourceToGame(NewResourceDetails details, ref ResourceInfo resource)
		{
			ResourceInfo resourceInfoByNameUnsafe = ModUtils.GetResourceInfoByNameUnsafe(details.parentName, false);
			if ((Object)(object)resourceInfoByNameUnsafe == (Object)null)
			{
				EMUAdditionsPlugin.LogError("Could not find parent Resource '" + details.parentName + "'");
				EMUAdditionsPlugin.LogError("Abandoning attempt to add new Resource '" + details.name + "'");
				return;
			}
			if (!string.IsNullOrEmpty(details.subHeaderTitle))
			{
				resource.headerType = ModUtils.GetSchematicsSubHeaderByTitle(details.headerTitle, details.subHeaderTitle, false);
			}
			if ((Object)(object)resource.headerType == (Object)null)
			{
				resource.headerType = resourceInfoByNameUnsafe.headerType;
			}
			if ((Object)(object)resource.sprite == (Object)null)
			{
				resource.rawSprite = resourceInfoByNameUnsafe.sprite;
			}
			resource.model3D = resourceInfoByNameUnsafe.model3D;
			resource.rawConveyorResourcePrefab = resourceInfoByNameUnsafe.rawConveyorResourcePrefab;
			string hashString = LocsUtility.GetHashString(details.name);
			string hashString2 = LocsUtility.GetHashString(details.description);
			EMUAdditionsPlugin.customTranslations[hashString] = details.name;
			EMUAdditionsPlugin.customTranslations[hashString2] = details.description;
			GameDefines.instance.resources.Add(resource);
			ResourceNames.SafeResources.Add(resource.displayName);
			addedIds.Add(((UniqueIdScriptableObject)resource).uniqueId);
		}

		private static int GetNewResourceID()
		{
			int num = 0;
			foreach (ResourceInfo resource in GameDefines.instance.resources)
			{
				if (((UniqueIdScriptableObject)resource).uniqueId > num)
				{
					num = ((UniqueIdScriptableObject)resource).uniqueId;
				}
			}
			foreach (int value in idHistory.Values)
			{
				if (value > num)
				{
					num = value;
				}
			}
			return num + 1;
		}
	}
	internal static class SubHeaderAdder
	{
		internal static List<SchematicsSubHeader> subHeadersToAdd = new List<SchematicsSubHeader>();

		internal static List<string> parents = new List<string>();

		internal static Dictionary<string, int> idHistory = new Dictionary<string, int>();

		private static string dataFolder => EMUAdditionsPlugin.dataFolder;

		internal static void AddRegisteredSubHeaders()
		{
			EMUAdditionsPlugin.LogInfo($"{subHeadersToAdd.Count} new SchematicsSubHeaders have been registered for adding");
			foreach (SchematicsSubHeader item in subHeadersToAdd.Where((SchematicsSubHeader subHeader) => idHistory.ContainsKey(subHeader.title)).ToList())
			{
				EMUAdditionsPlugin.LogInfo("Trying to add historic new SchematicsSubHeader '" + item.title + "'");
				((UniqueIdScriptableObject)item).uniqueId = idHistory[item.title];
				if (AddSubHeaderToGame(item))
				{
					EMUAdditionsPlugin.LogInfo($"Added historic new SchematicsSubHeader '{item.title}' to the game with id {((UniqueIdScriptableObject)item).uniqueId}");
				}
			}
			foreach (SchematicsSubHeader item2 in subHeadersToAdd.Where((SchematicsSubHeader subHeader) => !idHistory.ContainsKey(subHeader.title)).ToList())
			{
				EMUAdditionsPlugin.LogInfo("Trying to add brand new SchematicsSubHeader '" + item2.title + "'");
				((UniqueIdScriptableObject)item2).uniqueId = GetNewSubHeaderID();
				idHistory.Add(item2.title, ((UniqueIdScriptableObject)item2).uniqueId);
				if (AddSubHeaderToGame(item2))
				{
					EMUAdditionsPlugin.LogInfo($"Added brand new SchematicsSubHeader '{item2.title}' to the game with id {((UniqueIdScriptableObject)item2).uniqueId}");
				}
			}
			SaveIdHistory();
		}

		private static bool AddSubHeaderToGame(SchematicsSubHeader subHeader)
		{
			int index = subHeadersToAdd.IndexOf(subHeader);
			string text = parents[index];
			subHeader.filterTag = ModUtils.GetSchematicsHeaderByTitle(text, false);
			if ((Object)(object)subHeader.filterTag == (Object)null)
			{
				EMUAdditionsPlugin.LogError("Aborting attempt to add new SchematicsSubHeader '" + subHeader.title + "'");
				return false;
			}
			string hashString = LocsUtility.GetHashString(subHeader.title);
			EMUAdditionsPlugin.customTranslations[hashString] = subHeader.title;
			GameDefines.instance.schematicsSubHeaderEntries.Add(subHeader);
			return true;
		}

		private static int GetNewSubHeaderID()
		{
			int num = 0;
			foreach (SchematicsSubHeader schematicsSubHeaderEntry in GameDefines.instance.schematicsSubHeaderEntries)
			{
				if (((UniqueIdScriptableObject)schematicsSubHeaderEntry).uniqueId > num)
				{
					num = ((UniqueIdScriptableObject)schematicsSubHeaderEntry).uniqueId;
				}
			}
			foreach (int value in idHistory.Values)
			{
				if (value > num)
				{
					num = value;
				}
			}
			return num + 1;
		}

		private static void SaveIdHistory()
		{
			Directory.CreateDirectory(dataFolder);
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, int> item in idHistory)
			{
				list.Add($"{item.Key}|{item.Value}");
			}
			File.WriteAllLines(dataFolder + "/SubHeader Id History.txt", list);
		}

		internal static void LoadIdHistory()
		{
			string path = dataFolder + "/SubHeader Id History.txt";
			if (!File.Exists(path))
			{
				EMUAdditionsPlugin.LogWarning("No SubHeader Id History save file found");
				return;
			}
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '|' });
				idHistory.Add(array2[0], int.Parse(array2[1]));
			}
		}
	}
	internal static class UnlockAdder
	{
		internal static Dictionary<string, int> idHistory = new Dictionary<string, int>();

		internal static Dictionary<string, List<string>> unlockDependencies = new Dictionary<string, List<string>>();

		internal static List<Unlock> unlocksToAdd = new List<Unlock>();

		private static List<string> newUnlockHashedNames = new List<string>();

		private static string dataFolder => EMUAdditionsPlugin.dataFolder;

		internal static void AddRegisteredUnlocks()
		{
			EMUAdditionsPlugin.LogInfo($"{unlocksToAdd.Count} new Unlocks have been registered for adding");
			List<Unlock> list = unlocksToAdd.Where((Unlock unlock) => idHistory.ContainsKey(unlock.displayNameHash)).ToList();
			for (int i = 0; i < list.Count; i++)
			{
				Unlock unlock2 = list[i];
				if (ModUtils.NullCheck((object)unlock2, "New Unlock", false) && FindDependencies(ref unlock2))
				{
					((UniqueIdScriptableObject)unlock2).uniqueId = idHistory[unlock2.displayNameHash];
					AddUnlockToGame(ref unlock2);
					EMUAdditionsPlugin.LogInfo($"Added historic new Unlock '{EMUAdditionsPlugin.customTranslations[unlock2.displayNameHash]}' to the game with id {((UniqueIdScriptableObject)unlock2).uniqueId}");
				}
			}
			List<Unlock> list2 = unlocksToAdd.Where((Unlock unlock) => !idHistory.ContainsKey(unlock.displayNameHash)).ToList();
			for (int j = 0; j < list2.Count; j++)
			{
				Unlock unlock3 = list2[j];
				if (ModUtils.NullCheck((object)unlock3, "New Unlock", false) && FindDependencies(ref unlock3))
				{
					((UniqueIdScriptableObject)unlock3).uniqueId = GetNewUnlockID();
					idHistory.Add(unlock3.displayNameHash, ((UniqueIdScriptableObject)unlock3).uniqueId);
					AddUnlockToGame(ref unlock3);
					EMUAdditionsPlugin.LogInfo($"Added brand new Unlock '{EMUAdditionsPlugin.customTranslations[unlock3.displayNameHash]}' to the game with id {((UniqueIdScriptableObject)unlock3).uniqueId}");
				}
			}
			SaveIdHistory();
		}

		internal static void CleanUnlockStates()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			EMUAdditionsPlugin.Log.LogInfo((object)"Cleaning Unlock States");
			int num = 0;
			while (num < TechTreeState.instance.unlockStates.Count())
			{
				UnlockState val = TechTreeState.instance.unlockStates[num];
				if ((Object)(object)val.unlockRef == (Object)null || GameDefines.instance.unlocks.Contains(val.unlockRef))
				{
					num++;
					continue;
				}
				ArrayExt.RemoveAt<UnlockState>(TechTreeState.instance.unlockStates, num);
				GameState.instance.acknowledgedUnlocks.Remove(((UniqueIdScriptableObject)val.unlockRef).uniqueId);
				EMUAdditionsPlugin.Log.LogInfo((object)$"Could not find Unlock for UnlockState #{num}. Removed.");
			}
			EMUAdditionsPlugin.Log.LogInfo((object)"Clearing duplicate unlock states");
			List<UnlockState> list = new List<UnlockState>();
			for (int i = 0; i < TechTreeState.instance.unlockStates.Count(); i++)
			{
				bool flag = true;
				foreach (UnlockState item in list)
				{
					if (!((Object)(object)TechTreeState.instance.unlockStates[i].unlockRef == (Object)null) && !((Object)(object)item.unlockRef == (Object)null) && ((UniqueIdScriptableObject)TechTreeState.instance.unlockStates[i].unlockRef).uniqueId == ((UniqueIdScriptableObject)item.unlockRef).uniqueId)
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					list.Add(TechTreeState.instance.unlockStates[i]);
				}
			}
			int num2 = TechTreeState.instance.unlockStates.Count() - list.Count;
			EMUAdditionsPlugin.Log.LogInfo((object)$"Found '{list.Count}' unique states");
			EMUAdditionsPlugin.Log.LogInfo((object)$"Removing {num2} duplicates");
			TechTreeState.instance.unlockStates = list.ToArray();
		}

		internal static void CleanTechProgress()
		{
			EMUAdditionsPlugin.Log.LogInfo((object)"Cleaning Tech Progress");
			int num = 0;
			while (num < SaveState.instance.techTree.researchProgress.Count)
			{
				TechProgress val = SaveState.instance.techTree.researchProgress[num];
				if (val.techIndex >= TechTreeState.instance.unlockStates.Length)
				{
					SaveState.instance.techTree.researchProgress.RemoveAt(num);
					EMUAdditionsPlugin.Log.LogInfo((object)$"Could not find UnlockState for TechProgress #{val.techIndex}. Removed.");
				}
				else
				{
					num++;
				}
			}
		}

		private static void AddUnlockToGame(ref Unlock unlock)
		{
			newUnlockHashedNames.Add(unlock.displayNameHash);
			GameDefines.instance.unlocks.Add(unlock);
		}

		private static int GetNewUnlockID()
		{
			int num = 0;
			for (int i = 0; i < GameDefines.instance.unlocks.Count; i++)
			{
				if (((UniqueIdScriptableObject)GameDefines.instance.unlocks[i]).uniqueId > num)
				{
					num = ((UniqueIdScriptableObject)GameDefines.instance.unlocks[i]).uniqueId;
				}
			}
			foreach (int value in idHistory.Values)
			{
				if (value > num)
				{
					num = value;
				}
			}
			return num + 1;
		}

		private static bool FindDependencies(ref Unlock unlock)
		{
			List<Unlock> list = new List<Unlock>();
			foreach (string item in unlockDependencies[unlock.displayNameHash])
			{
				Unlock unlockByName = ModUtils.GetUnlockByName(item, false);
				if ((Object)(object)unlockByName != (Object)null)
				{
					list.Add(unlockByName);
					continue;
				}
				EMUAdditionsPlugin.LogError("Could not find dependency with name '" + item + "'. Abandoning attempt to add.");
				EMUAdditionsPlugin.LogError("Try using a name from EMU.UnlockNames");
				return false;
			}
			unlock.dependencies = list;
			if (list.Count >= 1)
			{
				unlock.dependency1 = list[0];
			}
			if (list.Count == 2)
			{
				unlock.dependency2 = list[1];
			}
			return true;
		}

		internal static void SaveIdHistory()
		{
			Directory.CreateDirectory(dataFolder);
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, int> item in idHistory)
			{
				list.Add($"{item.Key}|{item.Value}");
			}
			File.WriteAllLines(dataFolder + "/Unlock Id History.txt", list);
		}

		internal static void LoadIdHistory()
		{
			string path = dataFolder + "/Unlock Id History.txt";
			if (!File.Exists(path))
			{
				EMUAdditionsPlugin.LogWarning("No Unlock Id History save file found");
				return;
			}
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '|' });
				idHistory.Add(array2[0], int.Parse(array2[1]));
			}
		}
	}
}