Decompiled source of OdinsMissingPatch v0.3.0

OdinsMissingPatch.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Valheim.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("OdinsMissingPatch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e04ed725ff3bf8678203c36bea55678c46ebfa14")]
[assembly: AssemblyProduct("OdinsMissingPatch")]
[assembly: AssemblyTitle("OdinsMissingPatch")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace OdinsMissingPatch
{
	internal static class ChestFavorites
	{
		private static readonly int FavoritesHash = StringExtensionMethods.GetStableHashCode("OMP_ChestFavorites");

		private const char Separator = '\n';

		internal static bool Used
		{
			get
			{
				if (!QuickStack.Instance.On)
				{
					return ChestButtons.Instance.On;
				}
				return true;
			}
		}

		internal static string Marks(Container chest)
		{
			ZNetView val = (((Object)(object)chest != (Object)null) ? chest.m_nview : null);
			if (!((Object)(object)val != (Object)null) || !val.IsValid())
			{
				return "";
			}
			return val.GetZDO().GetString(FavoritesHash, "");
		}

		internal static bool Marked(string marks, string itemName)
		{
			if (string.IsNullOrEmpty(marks) || string.IsNullOrEmpty(itemName))
			{
				return false;
			}
			for (int num = marks.IndexOf(itemName, StringComparison.Ordinal); num >= 0; num = marks.IndexOf(itemName, num + 1, StringComparison.Ordinal))
			{
				int num2 = num + itemName.Length;
				if (num > 0 && num2 < marks.Length && marks[num - 1] == '\n' && marks[num2] == '\n')
				{
					return true;
				}
			}
			return false;
		}

		internal static bool Accepts(Container chest, string itemName)
		{
			return Marked(Marks(chest), itemName);
		}

		internal static List<string> Names(Container chest)
		{
			List<string> list = new List<string>();
			string[] array = Marks(chest).Split(new char[1] { '\n' });
			foreach (string text in array)
			{
				if (text.Length > 0)
				{
					list.Add(text);
				}
			}
			return list;
		}

		internal static bool Toggle(Container chest, string itemName)
		{
			List<string> list = Names(chest);
			bool num = !list.Remove(itemName);
			if (num)
			{
				list.Add(itemName);
			}
			Write(chest, list);
			return num;
		}

		internal static void Clear(Container chest)
		{
			Write(chest, new List<string>());
		}

		internal static string Describe(Container chest)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (string item in Names(chest))
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append("- ").Append(Localize(item));
			}
			return stringBuilder.ToString();
		}

		internal static string Localize(string itemName)
		{
			if (Localization.instance == null)
			{
				return itemName;
			}
			return Localization.instance.Localize(itemName);
		}

		internal static Container OpenChest(Inventory inventory)
		{
			InventoryGui instance = InventoryGui.instance;
			Container val = (((Object)(object)instance != (Object)null) ? instance.m_currentContainer : null);
			if (!((Object)(object)val != (Object)null) || inventory == null || val.m_inventory != inventory)
			{
				return null;
			}
			return val;
		}

		private static void Write(Container chest, List<string> names)
		{
			ZNetView val = (((Object)(object)chest != (Object)null) ? chest.m_nview : null);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return;
			}
			if (!val.IsOwner())
			{
				val.ClaimOwnership();
			}
			if (!val.IsOwner())
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (string name in names)
			{
				stringBuilder.Append('\n').Append(name);
			}
			if (stringBuilder.Length > 0)
			{
				stringBuilder.Append('\n');
			}
			val.GetZDO().Set(FavoritesHash, stringBuilder.ToString());
		}
	}
	internal sealed class ChestGlow : MonoBehaviour
	{
		private const float Duration = 7f;

		private static readonly Color Gold = new Color(1f, 0.78f, 0.25f);

		private float time;

		internal static void Flash(Container chest, string text)
		{
			//IL_0057: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)chest == (Object)null))
			{
				GameObject val = (((Object)(object)chest.m_rootObjectOverride != (Object)null) ? ((Component)chest.m_rootObjectOverride).gameObject : ((Component)chest).gameObject);
				ChestGlow chestGlow = val.GetComponent<ChestGlow>();
				if ((Object)(object)chestGlow == (Object)null)
				{
					chestGlow = val.AddComponent<ChestGlow>();
				}
				chestGlow.time = 0f;
				if (text != null)
				{
					ShowText(((Component)chest).transform.position + Vector3.up, text);
				}
			}
		}

		private static void ShowText(Vector3 position, string text)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			DamageText instance = DamageText.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				Camera mainCamera = Utils.GetMainCamera();
				float num = (((Object)(object)mainCamera != (Object)null) ? Vector3.Distance(((Component)mainCamera).transform.position, position) : 0f);
				instance.AddInworldText((TextType)7, position, num, text, false);
			}
		}

		private void Update()
		{
			//IL_0064: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			time += Time.deltaTime;
			MaterialMan instance = MaterialMan.instance;
			if ((Object)(object)instance == (Object)null || time >= 7f)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			float num = Mathf.Abs(Mathf.Sin(time / 7f * (float)Math.PI * 3f));
			instance.SetValue<Color>(((Component)this).gameObject, ShaderProps._EmissionColor, Gold * (0.6f * num), false);
			instance.SetValue<Color>(((Component)this).gameObject, ShaderProps._Color, Color.Lerp(Color.white, Gold, 0.6f * num), false);
		}

		private void OnDestroy()
		{
			MaterialMan instance = MaterialMan.instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.ResetValue(((Component)this).gameObject, ShaderProps._EmissionColor);
				instance.ResetValue(((Component)this).gameObject, ShaderProps._Color);
			}
		}
	}
	internal static class Hotkeys
	{
		internal static bool Pressed(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey, false))
			{
				return false;
			}
			return ModifiersHeld(shortcut);
		}

		internal static bool Held(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey, false))
			{
				return false;
			}
			return ModifiersHeld(shortcut);
		}

		private static bool ModifiersHeld(KeyboardShortcut shortcut)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, false))
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class InventorySorter
	{
		internal static bool Sort(Inventory inventory, int fromRow, Func<ItemData, bool> keep)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			if (inventory == null)
			{
				return false;
			}
			List<ItemData> allItems = inventory.GetAllItems();
			int width = inventory.GetWidth();
			int height = inventory.GetHeight();
			bool[,] array = new bool[width, height];
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData item in allItems)
			{
				Vector2i gridPos = item.m_gridPos;
				bool flag = gridPos.x >= 0 && gridPos.x < width && gridPos.y >= 0 && gridPos.y < height;
				if (flag && gridPos.y >= fromRow && (keep == null || !keep(item)))
				{
					list.Add(item);
				}
				else if (flag)
				{
					array[gridPos.x, gridPos.y] = true;
				}
			}
			if (list.Count == 0)
			{
				return false;
			}
			List<Vector2i> list2 = new List<Vector2i>();
			for (int i = fromRow; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					if (!array[j, i])
					{
						list2.Add(new Vector2i(j, i));
					}
				}
			}
			if (list2.Count < list.Count)
			{
				return false;
			}
			MaterialOrder.Prepare();
			list.Sort(Compare);
			List<ItemData> list3 = Merge(list, allItems);
			for (int k = 0; k < list3.Count; k++)
			{
				list3[k].m_gridPos = list2[k];
			}
			inventory.Changed(false, false);
			return true;
		}

		private static List<ItemData> Merge(List<ItemData> sorted, List<ItemData> all)
		{
			List<ItemData> list = new List<ItemData>(sorted.Count);
			foreach (ItemData item in sorted)
			{
				int maxStackSize = item.m_shared.m_maxStackSize;
				if (maxStackSize > 1)
				{
					foreach (ItemData item2 in list)
					{
						if (item.m_stack <= 0)
						{
							break;
						}
						if (item2.m_stack < maxStackSize && SameStack(item2, item))
						{
							int num = Math.Min(maxStackSize - item2.m_stack, item.m_stack);
							item2.m_stack += num;
							item.m_stack -= num;
						}
					}
				}
				if (item.m_stack > 0)
				{
					list.Add(item);
				}
				else
				{
					all.Remove(item);
				}
			}
			return list;
		}

		private static bool SameStack(ItemData a, ItemData b)
		{
			if (a.m_shared.m_name != b.m_shared.m_name || a.m_quality != b.m_quality || a.m_variant != b.m_variant || a.m_worldLevel != b.m_worldLevel || a.m_cheated != b.m_cheated)
			{
				return false;
			}
			if (a.m_customData.Count != b.m_customData.Count)
			{
				return false;
			}
			foreach (KeyValuePair<string, string> customDatum in a.m_customData)
			{
				if (!b.m_customData.TryGetValue(customDatum.Key, out var value) || value != customDatum.Value)
				{
					return false;
				}
			}
			return true;
		}

		private static int Compare(ItemData a, ItemData b)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Invalid comparison between Unknown and I4
			int num = Rank(a.m_shared.m_itemType).CompareTo(Rank(b.m_shared.m_itemType));
			if (num != 0)
			{
				return num;
			}
			if ((int)a.m_shared.m_itemType == 1 && (int)b.m_shared.m_itemType == 1)
			{
				num = Portable(a).CompareTo(Portable(b));
				if (num != 0)
				{
					return num;
				}
				num = MaterialOrder.Compare(a, b);
				if (num != 0)
				{
					return num;
				}
			}
			num = string.Compare(DisplayName(a), DisplayName(b), StringComparison.CurrentCultureIgnoreCase);
			if (num != 0)
			{
				return num;
			}
			num = b.m_quality.CompareTo(a.m_quality);
			if (num != 0)
			{
				return num;
			}
			num = a.m_variant.CompareTo(b.m_variant);
			if (num == 0)
			{
				return b.m_stack.CompareTo(a.m_stack);
			}
			return num;
		}

		private static int Portable(ItemData item)
		{
			return (!item.m_shared.m_teleportable) ? 1 : 0;
		}

		private static string DisplayName(ItemData item)
		{
			string name = item.m_shared.m_name;
			Localization instance = Localization.instance;
			if (instance == null)
			{
				return name;
			}
			return instance.Localize(name);
		}

		private static int Rank(ItemType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected I4, but got Unknown
			switch (type - 1)
			{
			case 2:
			case 3:
			case 13:
			case 14:
			case 19:
			case 21:
				return 0;
			case 4:
				return 1;
			case 18:
				return 2;
			case 5:
				return 3;
			case 6:
				return 4;
			case 10:
				return 5;
			case 16:
				return 6;
			case 11:
				return 7;
			case 9:
				return 8;
			case 17:
				return 9;
			case 23:
				return 10;
			case 8:
				return 11;
			case 22:
				return 12;
			case 1:
				return 13;
			case 20:
				return 14;
			case 0:
				return 15;
			case 12:
				return 16;
			case 15:
				return 17;
			default:
				return 18;
			}
		}
	}
	internal static class MaterialOrder
	{
		private struct Place
		{
			internal int Family;

			internal int Depth;
		}

		private sealed class Step
		{
			internal SharedData Result;

			internal readonly List<SharedData> Inputs = new List<SharedData>();

			internal int Station = -1;

			internal int Level;
		}

		private sealed class Group
		{
			internal readonly List<SharedData> Members = new List<SharedData>();

			internal int Low = int.MaxValue;

			internal string Name;

			internal void Note(SharedData kind, int depth)
			{
				Members.Add(kind);
				string text = Label(kind);
				if (depth < Low || (depth == Low && string.Compare(text, Name, StringComparison.CurrentCultureIgnoreCase) < 0))
				{
					Low = depth;
					Name = text;
				}
			}
		}

		private const int MaxPasses = 32;

		private static ObjectDB source;

		private static int sourceRecipes;

		private static int sourceItems;

		private static Dictionary<SharedData, Place> places;

		internal static void Prepare()
		{
			ObjectDB instance = ObjectDB.instance;
			if (!((Object)(object)instance == (Object)null) && (!((Object)(object)instance == (Object)(object)source) || instance.m_recipes.Count != sourceRecipes || instance.m_items.Count != sourceItems))
			{
				source = instance;
				sourceRecipes = instance.m_recipes.Count;
				sourceItems = instance.m_items.Count;
				places = Build(instance);
			}
		}

		internal static int Compare(ItemData a, ItemData b)
		{
			Place place = Of(a);
			Place place2 = Of(b);
			int num = place.Family.CompareTo(place2.Family);
			if (num == 0)
			{
				return place.Depth.CompareTo(place2.Depth);
			}
			return num;
		}

		private static Place Of(ItemData item)
		{
			if (places != null && item != null && item.m_shared != null && places.TryGetValue(item.m_shared, out var value))
			{
				return value;
			}
			return new Place
			{
				Family = int.MaxValue,
				Depth = 0
			};
		}

		private static Dictionary<SharedData, Place> Build(ObjectDB db)
		{
			List<Piece> allBuildPieces = db.GetAllBuildPieces(true);
			Dictionary<CraftingStation, int> stations = Stations(allBuildPieces);
			List<Step> steps = Steps(db, allBuildPieces, stations);
			int[] pieceDepth = new int[allBuildPieces.Count];
			Dictionary<SharedData, int> made = new Dictionary<SharedData, int>();
			Settle(allBuildPieces, stations, Producers(steps), pieceDepth, made);
			Dictionary<SharedData, int> dictionary = Depths(made, Uses(steps, allBuildPieces, made, pieceDepth));
			Dictionary<SharedData, SharedData> parents = Families(steps);
			Dictionary<SharedData, Group> dictionary2 = new Dictionary<SharedData, Group>();
			foreach (KeyValuePair<SharedData, int> item in dictionary)
			{
				SharedData key = Find(parents, item.Key);
				if (!dictionary2.TryGetValue(key, out var value))
				{
					value = (dictionary2[key] = new Group());
				}
				value.Note(item.Key, item.Value);
			}
			List<Group> list = new List<Group>(dictionary2.Values);
			list.Sort(CompareGroups);
			Dictionary<SharedData, Place> dictionary3 = new Dictionary<SharedData, Place>();
			for (int i = 0; i < list.Count; i++)
			{
				foreach (SharedData member in list[i].Members)
				{
					dictionary3[member] = new Place
					{
						Family = i,
						Depth = dictionary[member]
					};
				}
			}
			return dictionary3;
		}

		private static Dictionary<CraftingStation, int> Stations(List<Piece> pieces)
		{
			Dictionary<CraftingStation, int> dictionary = new Dictionary<CraftingStation, int>();
			for (int i = 0; i < pieces.Count; i++)
			{
				Piece val = pieces[i];
				if (!((Object)(object)val == (Object)null))
				{
					CraftingStation component = ((Component)val).GetComponent<CraftingStation>();
					if ((Object)(object)component != (Object)null && !dictionary.ContainsKey(component))
					{
						dictionary[component] = i;
					}
				}
			}
			return dictionary;
		}

		private static List<Step> Steps(ObjectDB db, List<Piece> pieces, Dictionary<CraftingStation, int> stations)
		{
			List<Step> list = new List<Step>();
			foreach (Recipe recipe in db.m_recipes)
			{
				if (!((Object)(object)recipe == (Object)null) && recipe.m_enabled && !((Object)(object)recipe.m_item == (Object)null))
				{
					Step step = new Step
					{
						Result = recipe.m_item.m_itemData.m_shared,
						Station = StationPiece(stations, recipe.m_craftingStation),
						Level = Math.Max(0, recipe.m_minStationLevel - 1)
					};
					Requirement[] resources = recipe.m_resources;
					foreach (Requirement val in resources)
					{
						Feed(step.Inputs, val?.m_resItem);
					}
					Keep(list, step);
				}
			}
			for (int j = 0; j < pieces.Count; j++)
			{
				Piece val2 = pieces[j];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Smelter component = ((Component)val2).GetComponent<Smelter>();
				if ((Object)(object)component != (Object)null)
				{
					foreach (ItemConversion item in component.m_conversion)
					{
						if (item != null)
						{
							Converted(list, j, item.m_from, item.m_to);
						}
					}
				}
				CookingStation component2 = ((Component)val2).GetComponent<CookingStation>();
				if ((Object)(object)component2 != (Object)null)
				{
					foreach (ItemConversion item2 in component2.m_conversion)
					{
						if (item2 != null)
						{
							Converted(list, j, item2.m_from, item2.m_to);
						}
					}
				}
				Fermenter component3 = ((Component)val2).GetComponent<Fermenter>();
				if (!((Object)(object)component3 != (Object)null))
				{
					continue;
				}
				foreach (ItemConversion item3 in component3.m_conversion)
				{
					if (item3 != null)
					{
						Converted(list, j, item3.m_from, item3.m_to);
					}
				}
			}
			return list;
		}

		private static void Converted(List<Step> steps, int station, ItemDrop from, ItemDrop to)
		{
			if (!((Object)(object)to == (Object)null))
			{
				Step step = new Step
				{
					Result = to.m_itemData.m_shared,
					Station = station
				};
				Feed(step.Inputs, from);
				Keep(steps, step);
			}
		}

		private static void Feed(List<SharedData> inputs, ItemDrop drop)
		{
			SharedData val = (((Object)(object)drop == (Object)null) ? null : drop.m_itemData.m_shared);
			if (val != null && !inputs.Contains(val))
			{
				inputs.Add(val);
			}
		}

		private static void Keep(List<Step> steps, Step step)
		{
			if (step.Result != null)
			{
				steps.Add(step);
			}
		}

		private static Dictionary<SharedData, List<Step>> Producers(List<Step> steps)
		{
			Dictionary<SharedData, List<Step>> dictionary = new Dictionary<SharedData, List<Step>>();
			foreach (Step step in steps)
			{
				if (!dictionary.TryGetValue(step.Result, out var value))
				{
					value = new List<Step>();
					dictionary[step.Result] = value;
				}
				value.Add(step);
			}
			return dictionary;
		}

		private static void Settle(List<Piece> pieces, Dictionary<CraftingStation, int> stations, Dictionary<SharedData, List<Step>> producers, int[] pieceDepth, Dictionary<SharedData, int> made)
		{
			bool flag = true;
			for (int i = 0; i < 32 && flag; i++)
			{
				flag = false;
				for (int j = 0; j < pieces.Count; j++)
				{
					Piece val = pieces[j];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					int num = StationDepth(stations, pieceDepth, val.m_craftingStation);
					Requirement[] resources = val.m_resources;
					foreach (Requirement val2 in resources)
					{
						if (val2 != null && (Object)(object)val2.m_resItem != (Object)null)
						{
							num = Math.Max(num, Depth(made, val2.m_resItem.m_itemData.m_shared));
						}
					}
					if (num + 1 > pieceDepth[j])
					{
						pieceDepth[j] = num + 1;
						flag = true;
					}
				}
				foreach (KeyValuePair<SharedData, List<Step>> producer in producers)
				{
					int num2 = int.MaxValue;
					foreach (Step item in producer.Value)
					{
						num2 = Math.Min(num2, StepDepth(item, made, pieceDepth));
					}
					if (num2 != int.MaxValue && num2 > Depth(made, producer.Key))
					{
						made[producer.Key] = num2;
						flag = true;
					}
				}
			}
		}

		private static Dictionary<SharedData, int> Uses(List<Step> steps, List<Piece> pieces, Dictionary<SharedData, int> made, int[] pieceDepth)
		{
			Dictionary<SharedData, int> dictionary = new Dictionary<SharedData, int>();
			foreach (Step step in steps)
			{
				int depth = StepDepth(step, made, pieceDepth);
				foreach (SharedData input in step.Inputs)
				{
					Lower(dictionary, input, depth);
				}
			}
			for (int i = 0; i < pieces.Count; i++)
			{
				Piece val = pieces[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Requirement[] resources = val.m_resources;
				foreach (Requirement val2 in resources)
				{
					if (val2 != null && (Object)(object)val2.m_resItem != (Object)null)
					{
						Lower(dictionary, val2.m_resItem.m_itemData.m_shared, pieceDepth[i]);
					}
				}
			}
			return dictionary;
		}

		private static Dictionary<SharedData, int> Depths(Dictionary<SharedData, int> made, Dictionary<SharedData, int> used)
		{
			Dictionary<SharedData, int> dictionary = new Dictionary<SharedData, int>();
			foreach (KeyValuePair<SharedData, int> item in used)
			{
				if (Material(item.Key))
				{
					dictionary[item.Key] = item.Value;
				}
			}
			foreach (KeyValuePair<SharedData, int> item2 in made)
			{
				if (Material(item2.Key) && !dictionary.ContainsKey(item2.Key))
				{
					dictionary[item2.Key] = item2.Value;
				}
			}
			return dictionary;
		}

		private static Dictionary<SharedData, SharedData> Families(List<Step> steps)
		{
			Dictionary<SharedData, SharedData> dictionary = new Dictionary<SharedData, SharedData>();
			foreach (Step step in steps)
			{
				if (!Material(step.Result))
				{
					continue;
				}
				foreach (SharedData input in step.Inputs)
				{
					if (Material(input))
					{
						Union(dictionary, step.Result, input);
					}
				}
			}
			return dictionary;
		}

		private static SharedData Find(Dictionary<SharedData, SharedData> parents, SharedData kind)
		{
			if (!parents.TryGetValue(kind, out var value))
			{
				parents[kind] = kind;
				return kind;
			}
			if (value == kind)
			{
				return kind;
			}
			return parents[kind] = Find(parents, value);
		}

		private static void Union(Dictionary<SharedData, SharedData> parents, SharedData a, SharedData b)
		{
			SharedData val = Find(parents, a);
			SharedData val2 = Find(parents, b);
			if (val != val2)
			{
				parents[val2] = val;
			}
		}

		private static int CompareGroups(Group a, Group b)
		{
			int num = a.Low.CompareTo(b.Low);
			if (num == 0)
			{
				return string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase);
			}
			return num;
		}

		private static int StepDepth(Step step, Dictionary<SharedData, int> made, int[] pieceDepth)
		{
			int num = ((step.Station >= 0) ? (pieceDepth[step.Station] + step.Level) : step.Level);
			foreach (SharedData input in step.Inputs)
			{
				num = Math.Max(num, Depth(made, input));
			}
			return num + 1;
		}

		private static int StationPiece(Dictionary<CraftingStation, int> stations, CraftingStation station)
		{
			if (!((Object)(object)station != (Object)null) || !stations.TryGetValue(station, out var value))
			{
				return -1;
			}
			return value;
		}

		private static int StationDepth(Dictionary<CraftingStation, int> stations, int[] pieceDepth, CraftingStation station)
		{
			int num = StationPiece(stations, station);
			if (num < 0)
			{
				return 0;
			}
			return pieceDepth[num];
		}

		private static int Depth(Dictionary<SharedData, int> depths, SharedData kind)
		{
			if (kind == null || !depths.TryGetValue(kind, out var value))
			{
				return 0;
			}
			return value;
		}

		private static void Lower(Dictionary<SharedData, int> depths, SharedData kind, int depth)
		{
			if (kind != null && (!depths.TryGetValue(kind, out var value) || depth < value))
			{
				depths[kind] = depth;
			}
		}

		private static bool Material(SharedData kind)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if (kind != null)
			{
				return (int)kind.m_itemType == 1;
			}
			return false;
		}

		private static string Label(SharedData kind)
		{
			Localization instance = Localization.instance;
			if (instance == null)
			{
				return kind.m_name;
			}
			return instance.Localize(kind.m_name);
		}
	}
	internal static class NearbyChests
	{
		private sealed class Entry
		{
			public Container Container;

			public Piece Piece;

			public bool Tombstone;
		}

		[HarmonyPatch(typeof(Inventory), "CountItems")]
		private static class CountChests
		{
			private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
			{
				if (InReach && name != null && IsBackpack(__instance))
				{
					__result += InChests(name, quality, matchWorldLevel);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "HaveItem", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		private static class HaveInChests
		{
			private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result)
			{
				if (!__result && InReach && name != null && IsBackpack(__instance))
				{
					__result = InChests(name, -1, matchWorldLevel) > 0;
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		private static class TakeFromChests
		{
			private static void Prefix(Inventory __instance, string name, ref int amount, int itemQuality, bool worldLevelBased)
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				if (!InReach || name == null || !IsBackpack(__instance))
				{
					return;
				}
				int num = Carried(__instance, name, itemQuality, worldLevelBased);
				if (amount <= num)
				{
					return;
				}
				int num2 = amount - num;
				amount = num;
				foreach (Container item in new List<Container>(Find(((Component)Player.m_localPlayer).transform.position, ReachRange)))
				{
					if (num2 <= 0)
					{
						break;
					}
					Inventory inventory = item.GetInventory();
					if (inventory.CountItems(name, itemQuality, worldLevelBased) > 0 && Claim(item))
					{
						int num3 = Mathf.Min(num2, inventory.CountItems(name, itemQuality, worldLevelBased));
						if (num3 > 0)
						{
							inventory.RemoveItem(name, num3, itemQuality, worldLevelBased);
							num2 -= num3;
						}
					}
				}
				counts.Clear();
			}
		}

		private readonly struct CountKey : IEquatable<CountKey>
		{
			private readonly string name;

			private readonly int quality;

			private readonly bool matchWorldLevel;

			public CountKey(string name, int quality, bool matchWorldLevel)
			{
				this.name = name;
				this.quality = quality;
				this.matchWorldLevel = matchWorldLevel;
			}

			public bool Equals(CountKey other)
			{
				if (quality == other.quality && matchWorldLevel == other.matchWorldLevel)
				{
					return string.Equals(name, other.name, StringComparison.Ordinal);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is CountKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((name.GetHashCode() * 397) ^ quality) * 397) ^ (matchWorldLevel ? 1 : 0);
			}
		}

		[HarmonyPatch(typeof(Container), "Awake")]
		private static class Register
		{
			private static void Postfix(Container __instance)
			{
				if (__instance.m_inventory != null)
				{
					Registry.Add(new Entry
					{
						Container = __instance,
						Piece = ((Component)__instance).GetComponentInParent<Piece>(),
						Tombstone = ((Object)(object)((Component)__instance).GetComponent<TombStone>() != (Object)null)
					});
				}
			}
		}

		[HarmonyPatch(typeof(Container), "GetHoverText")]
		private static class HoverText
		{
			private static void Postfix(Container __instance, ref string __result)
			{
				if (AnyTweakOn && IsExcluded(__instance))
				{
					__result += "\n<color=#a0a0a0>Nearby use: off</color>";
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static class PanelButton
		{
			private static readonly TextButton NearbyUse = new TextButton("OMP_NearbyUse", new UnityAction(Toggle));

			private static readonly TextButton ClearFavorites = new TextButton("OMP_ClearFavorites", new UnityAction(ClearFavorited));

			private static string favorites = "";

			private static int revision = -1;

			private static int favoritesCount;

			private static string favoritesTooltip = "";

			private static void Postfix(InventoryGui __instance)
			{
				if (PanelButtons.Closing(__instance))
				{
					return;
				}
				Container currentContainer = __instance.m_currentContainer;
				bool num = (Object)(object)currentContainer != (Object)null && ((Component)__instance.m_container).gameObject.activeSelf;
				int num2 = 0;
				if (num && AnyTweakOn && Eligible(currentContainer) && NearbyUse.Show(__instance))
				{
					NearbyUse.SetLabel(IsExcluded(currentContainer) ? "$omp_nearby_off" : "$omp_nearby_on");
					NearbyUse.SetTooltip("$omp_nearby_topic", "$omp_nearby_tip");
					Button val = (ChestButtons.HidesVanilla ? __instance.m_takeAllButton : null);
					NearbyUse.Place(__instance, val, keepLeft: true, num2);
					if ((Object)(object)val == (Object)null)
					{
						num2++;
					}
				}
				else
				{
					NearbyUse.Hide();
				}
				string text = (num ? ChestFavorites.Marks(currentContainer) : "");
				if (ChestFavorites.Used && text.Length > 0 && ClearFavorites.Show(__instance))
				{
					Describe(currentContainer, text);
					ClearFavorites.SetLabel((favoritesCount == 1) ? "$omp_clear_favourite" : "$omp_clear_favourites", favoritesCount.ToString());
					ClearFavorites.SetTooltip("$omp_favourites_topic", favoritesTooltip);
					Button at = (ChestButtons.HidesVanilla ? __instance.m_stackAllButton : null);
					ClearFavorites.Place(__instance, at, keepLeft: false, num2);
				}
				else
				{
					ClearFavorites.Hide();
				}
			}

			private static void Describe(Container chest, string marks)
			{
				if (!(marks == favorites) || revision != Translations.Revision)
				{
					favorites = marks;
					revision = Translations.Revision;
					favoritesCount = ChestFavorites.Names(chest).Count;
					favoritesTooltip = "$omp_favourites_tip_head\n" + ChestFavorites.Describe(chest) + "\n\n$omp_favourites_tip_foot";
				}
			}

			private static Container Open()
			{
				InventoryGui instance = InventoryGui.instance;
				if (!((Object)(object)instance != (Object)null))
				{
					return null;
				}
				return instance.m_currentContainer;
			}

			private static void Toggle()
			{
				Container val = Open();
				if ((Object)(object)val != (Object)null)
				{
					SetExcluded(val, !IsExcluded(val));
				}
			}

			private static void ClearFavorited()
			{
				Container val = Open();
				if (!((Object)(object)val == (Object)null))
				{
					ChestFavorites.Clear(val);
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer != (Object)null)
					{
						((Character)localPlayer).Message((MessageType)2, "$omp_favourites_cleared", 0, (Sprite)null, false);
					}
				}
			}
		}

		private sealed class TextButton
		{
			private const float Margin = 16f;

			private readonly string name;

			private readonly UnityAction onClick;

			private Button button;

			private UITooltip tip;

			private string label;

			private string tooltip;

			private Component labelText;

			private PropertyInfo labelWidth;

			internal TextButton(string name, UnityAction onClick)
			{
				this.name = name;
				this.onClick = onClick;
			}

			internal bool Show(InventoryGui gui)
			{
				if ((Object)(object)button == (Object)null && !Create(gui))
				{
					return false;
				}
				((Component)button).gameObject.SetActive(true);
				return true;
			}

			internal void Hide()
			{
				if ((Object)(object)button != (Object)null)
				{
					((Component)button).gameObject.SetActive(false);
				}
			}

			internal void Place(InventoryGui gui, Button at, bool keepLeft, int slot)
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: 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_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: 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_006e: Expected O, but got Unknown
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
				//IL_0106: Unknown result type (might be due to invalid IL or missing references)
				//IL_010b: Unknown result type (might be due to invalid IL or missing references)
				//IL_011a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_013d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0127: Unknown result type (might be due to invalid IL or missing references)
				//IL_014e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0153: Unknown result type (might be due to invalid IL or missing references)
				RectTransform val = ((!((Object)(object)gui.m_takeAllButton != (Object)null)) ? ((RectTransform)null) : ((RectTransform)((Component)gui.m_takeAllButton).transform));
				if (!((Object)(object)val == (Object)null))
				{
					Rect rect = val.rect;
					float height = ((Rect)(ref rect)).height;
					rect = val.rect;
					float num = Mathf.Max(((Rect)(ref rect)).width, LabelWidth() + 32f);
					RectTransform val2 = (RectTransform)((Component)button).transform;
					val2.sizeDelta = new Vector2(num, height);
					RectTransform val3 = ((!((Object)(object)at != (Object)null)) ? ((RectTransform)null) : ((RectTransform)((Component)at).transform));
					if ((Object)(object)val3 == (Object)null)
					{
						RectTransform container = gui.m_container;
						PanelButtons.Pin(val2, new Vector2(PanelButtons.ColumnLeft(container) + num * 0.5f, PanelButtons.ColumnTop(container) - height * 0.5f - (float)slot * (height + 6f)));
						return;
					}
					val2.anchorMin = val3.anchorMin;
					val2.anchorMax = val3.anchorMax;
					val2.pivot = val3.pivot;
					rect = val3.rect;
					float num2 = num - ((Rect)(ref rect)).width;
					val2.anchoredPosition = val3.anchoredPosition + new Vector2(keepLeft ? (num2 * (1f - val3.pivot.x)) : ((0f - num2) * val3.pivot.x), 0f);
				}
			}

			private float LabelWidth()
			{
				if ((Object)(object)labelText == (Object)null)
				{
					Transform val = ((Component)button).transform.Find("Text");
					if ((Object)(object)val == (Object)null)
					{
						return 0f;
					}
					Component[] components = ((Component)val).GetComponents<Component>();
					foreach (Component val2 in components)
					{
						PropertyInfo property = ((object)val2).GetType().GetProperty("preferredWidth", typeof(float));
						if (property != null && property.CanRead)
						{
							labelText = val2;
							labelWidth = property;
							break;
						}
					}
				}
				if (!((Object)(object)labelText != (Object)null))
				{
					return 0f;
				}
				return (float)labelWidth.GetValue(labelText, null);
			}

			private bool Create(InventoryGui gui)
			{
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Expected O, but got Unknown
				Button takeAllButton = gui.m_takeAllButton;
				if ((Object)(object)takeAllButton == (Object)null)
				{
					return false;
				}
				GameObject val = Object.Instantiate<GameObject>(((Component)takeAllButton).gameObject, ((Component)takeAllButton).transform.parent);
				((Object)val).name = name;
				button = val.GetComponent<Button>();
				if ((Object)(object)button == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					return false;
				}
				button.onClick = new ButtonClickedEvent();
				((UnityEvent)button.onClick).AddListener(onClick);
				val.transform.SetSiblingIndex(((Component)takeAllButton).transform.GetSiblingIndex());
				tip = PanelButtons.Tooltip(gui, val);
				label = null;
				tooltip = null;
				labelText = null;
				labelWidth = null;
				return true;
			}

			internal void SetLabel(string text, params string[] words)
			{
				if (Localization.instance != null)
				{
					text = Localization.instance.Localize(text, words);
				}
				if (text == label)
				{
					return;
				}
				label = text;
				Component[] componentsInChildren = ((Component)button).GetComponentsInChildren<Component>(true);
				foreach (Component val in componentsInChildren)
				{
					PropertyInfo property = ((object)val).GetType().GetProperty("text", typeof(string));
					if (property != null && property.CanWrite)
					{
						property.SetValue(val, text, null);
					}
				}
			}

			internal void SetTooltip(string topic, string text)
			{
				if (!(text == tooltip) && !((Object)(object)tip == (Object)null))
				{
					tooltip = text;
					tip.m_topic = topic;
					tip.m_text = text;
				}
			}
		}

		private static readonly int ExcludedHash = StringExtensionMethods.GetStableHashCode("OMP_NoNearbyUse");

		private static readonly List<Entry> Registry = new List<Entry>();

		private static readonly List<Container> Found = new List<Container>();

		private static readonly List<float> Reaches = new List<float>();

		private static readonly Dictionary<CountKey, int> counts = new Dictionary<CountKey, int>();

		private static int countsFrame = -1;

		internal static bool AnyTweakOn
		{
			get
			{
				if (!NearbyCrafting.Instance.On && !QuickStack.Instance.On && !NearbyFuel.Instance.On)
				{
					return AddAll.Instance.On;
				}
				return true;
			}
		}

		private static bool InReach => Reaches.Count > 0;

		private static float ReachRange => Reaches[Reaches.Count - 1];

		internal static List<Container> Find(Vector3 origin, float radius)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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)
			Found.Clear();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return Found;
			}
			long playerID = localPlayer.GetPlayerID();
			float num = radius * radius;
			for (int num2 = Registry.Count - 1; num2 >= 0; num2--)
			{
				Entry entry = Registry[num2];
				if ((Object)(object)entry.Container == (Object)null)
				{
					Registry.RemoveAt(num2);
				}
				else
				{
					Vector3 val = ((Component)entry.Container).transform.position - origin;
					if (!(((Vector3)(ref val)).sqrMagnitude > num) && IsInReach(entry, playerID))
					{
						Found.Add(entry.Container);
					}
				}
			}
			Found.Sort(delegate(Container a, Container b)
			{
				//IL_0006: 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)
				//IL_0011: 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_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: 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)
				Vector3 val2 = ((Component)a).transform.position - origin;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				val2 = ((Component)b).transform.position - origin;
				return sqrMagnitude.CompareTo(((Vector3)(ref val2)).sqrMagnitude);
			});
			return Found;
		}

		private static bool IsInReach(Entry entry, long playerId)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Invalid comparison between Unknown and I4
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			Container container = entry.Container;
			if (!Eligible(entry) || container.m_inventory == null)
			{
				return false;
			}
			ZNetView nview = container.m_nview;
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return false;
			}
			if (nview.GetZDO().GetBool(ExcludedHash, false))
			{
				return false;
			}
			InventoryGui instance = InventoryGui.instance;
			if (!((Object)(object)instance != (Object)null) || !((Object)(object)instance.m_currentContainer == (Object)(object)container))
			{
				if (container.IsInUse() || nview.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 1)
				{
					return false;
				}
				if ((Object)(object)container.m_wagon != (Object)null && container.m_wagon.InUse())
				{
					return false;
				}
			}
			if ((int)container.m_privacy != 2 && (Object)(object)container.m_piece == (Object)null)
			{
				return false;
			}
			if (!container.CheckAccess(playerId))
			{
				return false;
			}
			if (container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false))
			{
				return false;
			}
			return true;
		}

		internal static bool Claim(Container chest)
		{
			if ((Object)(object)chest == (Object)null)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			Entry entry = Registry.Find((Entry e) => (Object)(object)e.Container == (Object)(object)chest);
			if (entry == null || !IsInReach(entry, localPlayer.GetPlayerID()))
			{
				return false;
			}
			ZNetView nview = chest.m_nview;
			chest.Load();
			if (!nview.IsOwner())
			{
				nview.ClaimOwnership();
			}
			return nview.IsOwner();
		}

		private static bool Eligible(Container chest)
		{
			return Eligible(Registry.Find((Entry e) => (Object)(object)e.Container == (Object)(object)chest));
		}

		private static bool Eligible(Entry entry)
		{
			if (entry != null && !entry.Tombstone && (Object)(object)entry.Piece != (Object)null)
			{
				return entry.Piece.IsPlacedByPlayer();
			}
			return false;
		}

		internal static bool IsExcluded(Container chest)
		{
			ZNetView val = (((Object)(object)chest != (Object)null) ? chest.m_nview : null);
			if ((Object)(object)val != (Object)null && val.IsValid())
			{
				return val.GetZDO().GetBool(ExcludedHash, false);
			}
			return false;
		}

		private static void SetExcluded(Container chest, bool excluded)
		{
			ZNetView val = (((Object)(object)chest != (Object)null) ? chest.m_nview : null);
			if (!((Object)(object)val == (Object)null) && val.IsValid())
			{
				if (!val.IsOwner())
				{
					val.ClaimOwnership();
				}
				if (val.IsOwner())
				{
					val.GetZDO().Set(ExcludedHash, excluded);
				}
			}
		}

		internal static void EnterReach(float range)
		{
			Reaches.Add(range);
		}

		internal static void LeaveReach()
		{
			if (Reaches.Count > 0)
			{
				Reaches.RemoveAt(Reaches.Count - 1);
			}
		}

		private static bool IsBackpack(Inventory inventory)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return inventory == ((Humanoid)localPlayer).GetInventory();
			}
			return false;
		}

		internal static int Carried(Inventory inventory, string name, int quality, bool matchWorldLevel)
		{
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem.m_shared.m_name == name && (quality < 0 || allItem.m_quality == quality) && (!matchWorldLevel || allItem.m_worldLevel >= Game.m_worldLevel))
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		private static int InChests(string name, int quality, bool matchWorldLevel)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (Time.frameCount != countsFrame)
			{
				counts.Clear();
				countsFrame = Time.frameCount;
			}
			CountKey key = new CountKey(name, quality, matchWorldLevel);
			if (counts.TryGetValue(key, out var value))
			{
				return value;
			}
			foreach (Container item in Find(((Component)Player.m_localPlayer).transform.position, ReachRange))
			{
				value += item.GetInventory().CountItems(name, quality, matchWorldLevel);
			}
			counts[key] = value;
			return value;
		}
	}
	[BepInPlugin("rauschekuh.odinsmissingpatch", "Odin's Missing Patch", "0.3.0")]
	public class OdinsMissingPatchPlugin : BaseUnityPlugin
	{
		public const string GUID = "rauschekuh.odinsmissingpatch";

		public const string NAME = "Odin's Missing Patch";

		public const string VERSION = "0.3.0";

		private static readonly Tweak[] Tweaks = new Tweak[25]
		{
			StationRange.Instance,
			ComfortRange.Instance,
			EndlessFuel.Instance,
			MistClearRange.Instance,
			CombatStamina.Instance,
			InstantComfort.Instance,
			FiresideHealing.Instance,
			FastPortals.Instance,
			KeepGearOnDeath.Instance,
			AreaRepair.Instance,
			NearbyCrafting.Instance,
			QuickStack.Instance,
			NearbyFuel.Instance,
			AddAll.Instance,
			AutoRepair.Instance,
			ChestButtons.Instance,
			InventoryButtons.Instance,
			PowerPicker.Instance,
			EquipWhileRunning.Instance,
			AutoShield.Instance,
			PocketUpgrades.Instance,
			SharedMapTable.Instance,
			AutoPins.Instance,
			PinLooks.Instance,
			DeathPins.Instance
		};

		private void Awake()
		{
			Tweak[] tweaks = Tweaks;
			for (int i = 0; i < tweaks.Length; i++)
			{
				tweaks[i].Setup(((BaseUnityPlugin)this).Config);
			}
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "rauschekuh.odinsmissingpatch");
			string text = string.Join(", ", (from t in Tweaks
				where t.On
				select t.Section).ToArray());
			((BaseUnityPlugin)this).Logger.LogInfo((object)((text.Length > 0) ? ("tweaks on: " + text) : "every tweak is switched off"));
		}
	}
	internal static class PanelButtons
	{
		internal const float Gap = 6f;

		private static readonly Dictionary<string, Sprite> icons = new Dictionary<string, Sprite>();

		private static readonly List<KeyValuePair<int, Button>> column = new List<KeyValuePair<int, Button>>();

		private static MethodInfo loadImage;

		internal static float Size(InventoryGui gui)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			Button val = (((Object)(object)gui != (Object)null) ? gui.m_takeAllButton : null);
			if (!((Object)(object)val != (Object)null))
			{
				return 32f;
			}
			Rect rect = ((RectTransform)((Component)val).transform).rect;
			return ((Rect)(ref rect)).height;
		}

		internal static Button Create(InventoryGui gui, Transform parent, string name, string icon, string title, string tooltip, UnityAction onClick)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_0080: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			Button val = (((Object)(object)gui != (Object)null) ? gui.m_takeAllButton : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent);
			((Object)val2).name = "OMP_" + name;
			Button component = val2.GetComponent<Button>();
			if ((Object)(object)component == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener(onClick);
			((Selectable)component).interactable = true;
			float num = Size(gui);
			((RectTransform)val2.transform).sizeDelta = new Vector2(num, num);
			AddIcon(val2, icon, BlankLabel(val2), num);
			UITooltip val3 = Tooltip(gui, val2);
			if ((Object)(object)val3 != (Object)null)
			{
				val3.m_topic = title;
				val3.m_text = tooltip;
			}
			val2.SetActive(false);
			return component;
		}

		internal static bool Closing(InventoryGui gui)
		{
			Animator val = (((Object)(object)gui != (Object)null) ? gui.m_animator : null);
			if ((Object)(object)val != (Object)null)
			{
				return !val.GetBool("visible");
			}
			return false;
		}

		internal static void Pin(RectTransform rect, Vector2 center)
		{
			//IL_0001: 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)
			//IL_0021: 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)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.zero;
			rect.pivot = new Vector2(0.5f, 0.5f);
			rect.anchoredPosition = center;
		}

		private static Vector2 Overhang(RectTransform panel)
		{
			//IL_0063: 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_002d: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			Transform obj = ((Transform)panel).Find("Bkg");
			RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
			if ((Object)(object)val != (Object)null && val.anchorMin == Vector2.zero && val.anchorMax == Vector2.one)
			{
				return Vector2.Max(Vector2.zero, val.sizeDelta * 0.5f);
			}
			return new Vector2(10f, 10f);
		}

		internal static float ColumnLeft(RectTransform panel)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = panel.rect;
			return ((Rect)(ref rect)).width + Overhang(panel).x + 6f;
		}

		internal static float ColumnTop(RectTransform panel)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = panel.rect;
			return ((Rect)(ref rect)).height + Overhang(panel).y;
		}

		private static RectTransform Box(InventoryGui gui, string field, RectTransform panel, string name)
		{
			FieldInfo field2 = typeof(InventoryGui).GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			Component val = (Component)((field2 != null) ? /*isinst with value type is only supported in some contexts*/: null);
			RectTransform val2 = (RectTransform)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val2 == (Object)null && (Object)(object)panel != (Object)null)
			{
				Transform obj = ((Transform)panel).Find(name);
				val2 = (RectTransform)(object)((obj is RectTransform) ? obj : null);
			}
			return val2;
		}

		private static Rect InPanel(RectTransform panel, RectTransform rect)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_0072: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			Rect rect2 = rect.rect;
			Vector3 val = ((Transform)panel).InverseTransformPoint(((Transform)rect).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect2)).min)));
			rect2 = rect.rect;
			Vector3 val2 = ((Transform)panel).InverseTransformPoint(((Transform)rect).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect2)).max)));
			Vector2 pivot = panel.pivot;
			rect2 = panel.rect;
			Vector2 val3 = Vector2.Scale(pivot, ((Rect)(ref rect2)).size);
			return Rect.MinMaxRect(Mathf.Min(val.x, val2.x) + val3.x, Mathf.Min(val.y, val2.y) + val3.y, Mathf.Max(val.x, val2.x) + val3.x, Mathf.Max(val.y, val2.y) + val3.y);
		}

		internal static void Enlist(Button button, int order)
		{
			column.Add(new KeyValuePair<int, Button>(order, button));
			column.Sort((KeyValuePair<int, Button> a, KeyValuePair<int, Button> b) => a.Key.CompareTo(b.Key));
		}

		internal static void LayoutInventoryColumn(InventoryGui gui)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			RectTransform val = (((Object)(object)gui != (Object)null) ? gui.m_player : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			float num = Size(gui);
			int num2 = 0;
			foreach (KeyValuePair<int, Button> item in column)
			{
				if ((Object)(object)item.Value != (Object)null && ((Component)item.Value).gameObject.activeSelf)
				{
					num2++;
				}
			}
			if (num2 == 0)
			{
				return;
			}
			RectTransform val2 = Box(gui, "m_armor", val, "Armor");
			RectTransform val3 = Box(gui, "m_weight", val, "Weight");
			Rect val4;
			float num3;
			if (!((Object)(object)val2 != (Object)null))
			{
				val4 = val.rect;
				num3 = ((Rect)(ref val4)).height;
			}
			else
			{
				val4 = InPanel(val, val2);
				num3 = ((Rect)(ref val4)).yMin;
			}
			float num4;
			if (!((Object)(object)val3 != (Object)null))
			{
				num4 = 0f;
			}
			else
			{
				val4 = InPanel(val, val3);
				num4 = ((Rect)(ref val4)).yMax;
			}
			float num5 = num4;
			float num6 = (float)num2 * num + (float)(num2 - 1) * 6f;
			float num7 = ColumnLeft(val) + num * 0.5f;
			float num8 = (num3 + num5) * 0.5f + num6 * 0.5f - num * 0.5f;
			foreach (KeyValuePair<int, Button> item2 in column)
			{
				if (!((Object)(object)item2.Value == (Object)null) && ((Component)item2.Value).gameObject.activeSelf)
				{
					RectTransform val5 = (RectTransform)((Component)item2.Value).transform;
					val5.sizeDelta = new Vector2(num, num);
					Pin(val5, new Vector2(num7, num8));
					num8 -= num + 6f;
				}
			}
		}

		internal static void LayoutChestColumn(InventoryGui gui, IList<Button> buttons)
		{
			//IL_0066: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			RectTransform val = (((Object)(object)gui != (Object)null) ? gui.m_container : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			float num = Size(gui);
			float num2 = ColumnLeft(val) + num * 0.5f;
			float num3 = ColumnTop(val) - num * 0.5f;
			foreach (Button button in buttons)
			{
				if (!((Object)(object)button == (Object)null))
				{
					RectTransform val2 = (RectTransform)((Component)button).transform;
					val2.sizeDelta = new Vector2(num, num);
					Pin(val2, new Vector2(num2, num3));
					num3 -= num + 6f;
				}
			}
		}

		internal static Sprite Icon(string name)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			if (icons.TryGetValue(name, out var value))
			{
				return value;
			}
			value = null;
			try
			{
				string text = Path.Combine(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "icons"), name + ".png");
				if (File.Exists(text))
				{
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
					if (LoadPng(val, File.ReadAllBytes(text)))
					{
						((Texture)val).filterMode = (FilterMode)1;
						value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
					}
				}
				else
				{
					Debug.LogWarning((object)("[OdinsMissingPatch] icon missing: " + text));
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[OdinsMissingPatch] could not load icon " + name + ": " + ex.Message));
			}
			icons[name] = value;
			return value;
		}

		private static bool LoadPng(Texture2D texture, byte[] png)
		{
			if (loadImage == null)
			{
				Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
				loadImage = ((type != null) ? type.GetMethod("LoadImage", new Type[2]
				{
					typeof(Texture2D),
					typeof(byte[])
				}) : null);
				if (loadImage == null)
				{
					Debug.LogWarning((object)"[OdinsMissingPatch] ImageConversion.LoadImage not found; icons stay blank");
					return false;
				}
			}
			return (bool)loadImage.Invoke(null, new object[2] { texture, png });
		}

		private static Color BlankLabel(GameObject go)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Color result = Color.white;
			Component[] componentsInChildren = go.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				PropertyInfo property = ((object)val).GetType().GetProperty("text", typeof(string));
				if (!(property == null) && property.CanWrite)
				{
					Graphic val2 = (Graphic)(object)((val is Graphic) ? val : null);
					if (val2 != null)
					{
						result = val2.color;
					}
					property.SetValue(val, "", null);
				}
			}
			return result;
		}

		private static void AddIcon(GameObject go, string icon, Color tint, float size)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("icon", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(go.transform, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			float num = size * 0.2f;
			val2.offsetMin = new Vector2(num, num);
			val2.offsetMax = new Vector2(0f - num, 0f - num);
			Image component = val.GetComponent<Image>();
			component.sprite = Icon(icon);
			((Graphic)component).color = tint;
			component.preserveAspect = true;
			((Graphic)component).raycastTarget = false;
			((Behaviour)component).enabled = (Object)(object)component.sprite != (Object)null;
		}

		internal static UITooltip Tooltip(InventoryGui gui, GameObject go)
		{
			UITooltip val = go.GetComponent<UITooltip>();
			if ((Object)(object)val == (Object)null)
			{
				GameObject val2 = TooltipPrefab(gui);
				if ((Object)(object)val2 == (Object)null)
				{
					return null;
				}
				val = go.AddComponent<UITooltip>();
				val.m_tooltipPrefab = val2;
			}
			else if ((Object)(object)val.m_tooltipPrefab == (Object)null)
			{
				val.m_tooltipPrefab = TooltipPrefab(gui);
			}
			return val;
		}

		private static GameObject TooltipPrefab(InventoryGui gui)
		{
			InventoryGrid playerGrid = gui.m_playerGrid;
			GameObject val = (((Object)(object)playerGrid != (Object)null) ? playerGrid.m_elementPrefab : null);
			InventoryElement val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<InventoryElement>() : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.m_tooltip != (Object)null && (Object)(object)val2.m_tooltip.m_tooltipPrefab != (Object)null)
			{
				return val2.m_tooltip.m_tooltipPrefab;
			}
			UITooltip[] componentsInChildren = ((Component)gui).GetComponentsInChildren<UITooltip>(true);
			foreach (UITooltip val3 in componentsInChildren)
			{
				if ((Object)(object)val3.m_tooltipPrefab != (Object)null)
				{
					return val3.m_tooltipPrefab;
				}
			}
			return null;
		}
	}
	internal static class Translations
	{
		[HarmonyPatch(typeof(Localization), "SetupLanguage")]
		private static class Load
		{
			private static void Postfix(Localization __instance, string language)
			{
				if (__instance == null || !Read() || !Reader())
				{
					return;
				}
				object obj = null;
				try
				{
					obj = textAsset.Invoke(new object[1] { csv });
					loadCsv.Invoke(__instance, new object[2]
					{
						obj,
						Has(language) ? language : "English"
					});
					Revision++;
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("[OdinsMissingPatch] could not load translations.csv: " + ex.Message));
				}
				finally
				{
					Object val = (Object)((obj is Object) ? obj : null);
					if (val != (Object)null)
					{
						Object.Destroy(val);
					}
				}
			}
		}

		private const string FileName = "translations.csv";

		private const string Fallback = "English";

		private static string csv;

		private static string[] languages;

		private static ConstructorInfo textAsset;

		private static MethodInfo loadCsv;

		private static bool looked;

		internal static int Revision { get; private set; }

		private static bool Read()
		{
			if (languages != null)
			{
				return csv != null;
			}
			languages = new string[0];
			try
			{
				string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "translations.csv");
				if (!File.Exists(text))
				{
					Debug.LogWarning((object)("[OdinsMissingPatch] translations.csv missing: " + text));
					return false;
				}
				csv = File.ReadAllText(text);
				using (StringReader stringReader = new StringReader(csv))
				{
					string text2 = stringReader.ReadLine();
					languages = ((text2 != null) ? text2.Split(new char[1] { ',' }) : new string[0]);
				}
				for (int i = 0; i < languages.Length; i++)
				{
					languages[i] = languages[i].Trim().Trim(new char[1] { '"' });
				}
			}
			catch (Exception ex)
			{
				csv = null;
				Debug.LogWarning((object)("[OdinsMissingPatch] could not read translations.csv: " + ex.Message));
			}
			return csv != null;
		}

		private static bool Has(string language)
		{
			string[] array = languages;
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] == language)
				{
					return true;
				}
			}
			return false;
		}

		private static bool Reader()
		{
			if (looked)
			{
				if (loadCsv != null)
				{
					return textAsset != null;
				}
				return false;
			}
			looked = true;
			Type type = Type.GetType("UnityEngine.TextAsset, UnityEngine.CoreModule");
			if (type != null)
			{
				textAsset = type.GetConstructor(new Type[1] { typeof(string) });
				loadCsv = typeof(Localization).GetMethod("LoadCSV", new Type[2]
				{
					type,
					typeof(string)
				});
			}
			if (loadCsv == null || textAsset == null)
			{
				Debug.LogWarning((object)"[OdinsMissingPatch] Localization.LoadCSV not found; the mod's words stay untranslated");
				return false;
			}
			return true;
		}
	}
	internal abstract class Tweak
	{
		private const float MinMultiplier = 0.1f;

		private const float MaxMultiplier = 20f;

		private ConfigEntry<bool> enabled;

		internal abstract string Section { get; }

		protected abstract string Summary { get; }

		internal bool On
		{
			get
			{
				if (enabled != null)
				{
					return enabled.Value;
				}
				return false;
			}
		}

		protected abstract void Bind(ConfigFile config);

		internal void Setup(ConfigFile config)
		{
			enabled = config.Bind<bool>(Section, "Enabled", true, Summary);
			Bind(config);
		}

		protected ConfigEntry<float> BindMultiplier(ConfigFile config, string key, float value, string description)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			return config.Bind<float>(Section, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
		}

		protected void OnSettingChanged(ConfigFile config, Action handler)
		{
			config.SettingChanged += delegate(object sender, SettingChangedEventArgs args)
			{
				if (args.ChangedSetting.Definition.Section == Section)
				{
					handler();
				}
			};
		}
	}
	internal sealed class AddAll : Tweak
	{
		private struct Batch
		{
			public string Name;

			public string Prefab;

			public bool Cheated;

			public int Count;
		}

		private readonly struct Reach : IDisposable
		{
			private readonly bool entered;

			internal Reach(Humanoid user)
			{
				entered = Instance.On && (Object)(object)user != (Object)null && (Object)(object)user == (Object)(object)Player.m_localPlayer;
				if (entered)
				{
					NearbyChests.EnterReach(Instance.range.Value);
				}
			}

			public void Dispose()
			{
				if (entered)
				{
					NearbyChests.LeaveReach();
				}
			}
		}

		[HarmonyPatch(typeof(Fireplace), "Interact")]
		private static class FireUse
		{
			private static bool Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt)
			{
				if (!Wants(user, hold, alt))
				{
					return true;
				}
				PlanFire(__instance, user);
				if (LeaveToGame(user, Plan))
				{
					return true;
				}
				int num = Total(Plan);
				ZNetView nview = __instance.m_nview;
				if (!nview.HasOwner())
				{
					nview.ClaimOwnership();
				}
				Take(user, Plan[0].Name, num);
				nview.InvokeRPC("RPC_AddFuelAmount", new object[1] { (float)num });
				Report(user, Plan);
				return false;
			}
		}

		[HarmonyPatch(typeof(Switch), "Interact")]
		private static class SwitchUse
		{
			private static bool Prefix(Switch __instance, Humanoid character, bool hold, bool alt)
			{
				if (!Wants(character, hold, alt))
				{
					return true;
				}
				Smelter componentInParent = ((Component)__instance).GetComponentInParent<Smelter>();
				if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.m_nview != (Object)null && componentInParent.m_nview.IsValid())
				{
					if ((Object)(object)__instance == (Object)(object)componentInParent.m_addWoodSwitch)
					{
						return !AddSmelterFuel(componentInParent, character);
					}
					if ((Object)(object)__instance == (Object)(object)componentInParent.m_addOreSwitch)
					{
						return !AddSmelterOre(componentInParent, character);
					}
					return true;
				}
				CookingStation componentInParent2 = ((Component)__instance).GetComponentInParent<CookingStation>();
				if ((Object)(object)componentInParent2 != (Object)null && (Object)(object)componentInParent2.m_nview != (Object)null && componentInParent2.m_nview.IsValid())
				{
					if ((Object)(object)__instance == (Object)(object)componentInParent2.m_addFuelSwitch)
					{
						return !AddOvenFuel(componentInParent2, character);
					}
					if ((Object)(object)__instance == (Object)(object)componentInParent2.m_addFoodSwitch)
					{
						return !AddFood(componentInParent2, character);
					}
					return true;
				}
				ShieldGenerator componentInParent3 = ((Component)__instance).GetComponentInParent<ShieldGenerator>();
				if ((Object)(object)componentInParent3 != (Object)null && (Object)(object)componentInParent3.m_nview != (Object)null && componentInParent3.m_nview.IsValid() && (Object)(object)__instance == (Object)(object)componentInParent3.m_addFuelSwitch)
				{
					return !AddShieldFuel(componentInParent3, character);
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(CookingStation), "Interact")]
		private static class StationUse
		{
			private static bool Prefix(CookingStation __instance, Humanoid user, bool hold, bool alt)
			{
				if (!Wants(user, hold, alt) || (Object)(object)__instance.m_addFoodSwitch != (Object)null || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid())
				{
					return true;
				}
				return !AddFood(__instance, user);
			}
		}

		[HarmonyPatch(typeof(Turret), "Interact")]
		private static class BallistaUse
		{
			private static bool Prefix(Turret __instance, Humanoid character, bool hold, bool alt)
			{
				if (!Wants(character, hold, alt))
				{
					return true;
				}
				PlanAmmo(__instance, character);
				if (LeaveToGame(character, Plan))
				{
					return true;
				}
				int num = Total(Plan);
				Batch batch = Plan[0];
				Take(character, batch.Name, num);
				for (int i = 0; i < num; i++)
				{
					Game.instance.IncrementPlayerStat((PlayerStatType)78, 1f, false);
					__instance.m_nview.InvokeRPC("RPC_AddAmmo", new object[1] { batch.Prefab });
				}
				Report(character, Plan);
				return false;
			}
		}

		[HarmonyPatch(typeof(Fireplace), "GetHoverText")]
		private static class FireHover
		{
			private static void Postfix(Fireplace __instance, ref string __result)
			{
				if (Hovering && !string.IsNullOrEmpty(__result))
				{
					PlanFire(__instance, (Humanoid)(object)Player.m_localPlayer);
					__result += HoverLine(Plan);
				}
			}
		}

		[HarmonyPatch(typeof(Switch), "GetHoverText")]
		private static class SwitchHover
		{
			private static void Postfix(Switch __instance, ref string __result)
			{
				if (!Hovering || string.IsNullOrEmpty(__result))
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				Smelter componentInParent = ((Component)__instance).GetComponentInParent<Smelter>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					if ((Object)(object)componentInParent.m_nview == (Object)null || !componentInParent.m_nview.IsValid())
					{
						return;
					}
					if ((Object)(object)__instance == (Object)(object)componentInParent.m_addWoodSwitch)
					{
						PlanSmelterFuel(componentInParent, (Humanoid)(object)localPlayer);
					}
					else
					{
						if (!((Object)(object)__instance == (Object)(object)componentInParent.m_addOreSwitch))
						{
							return;
						}
						PlanSmelterOre(componentInParent, (Humanoid)(object)localPlayer);
					}
					__result += HoverLine(Plan);
					return;
				}
				CookingStation componentInParent2 = ((Component)__instance).GetComponentInParent<CookingStation>();
				if ((Object)(object)componentInParent2 != (Object)null)
				{
					if ((Object)(object)componentInParent2.m_nview == (Object)null || !componentInParent2.m_nview.IsValid())
					{
						return;
					}
					if ((Object)(object)__instance == (Object)(object)componentInParent2.m_addFuelSwitch)
					{
						PlanOvenFuel(componentInParent2, (Humanoid)(object)localPlayer);
					}
					else
					{
						if (!((Object)(object)__instance == (Object)(object)componentInParent2.m_addFoodSwitch))
						{
							return;
						}
						PlanFood(componentInParent2, (Humanoid)(object)localPlayer);
					}
					__result += HoverLine(Plan);
				}
				else
				{
					ShieldGenerator componentInParent3 = ((Component)__instance).GetComponentInParent<ShieldGenerator>();
					if ((Object)(object)componentInParent3 != (Object)null && (Object)(object)componentInParent3.m_nview != (Object)null && componentInParent3.m_nview.IsValid() && (Object)(object)__instance == (Object)(object)componentInParent3.m_addFuelSwitch)
					{
						PlanShieldFuel(componentInParent3, (Humanoid)(object)localPlayer);
						__result += HoverLine(Plan);
					}
				}
			}
		}

		[HarmonyPatch(typeof(CookingStation), "GetHoverText")]
		private static class StationHover
		{
			private static void Postfix(CookingStation __instance, ref string __result)
			{
				if (Hovering && !string.IsNullOrEmpty(__result) && !((Object)(object)__instance.m_addFoodSwitch != (Object)null) && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid())
				{
					PlanFood(__instance, (Humanoid)(object)Player.m_localPlayer);
					__result += HoverLine(Plan);
				}
			}
		}

		[HarmonyPatch(typeof(Turret), "GetHoverText")]
		private static class BallistaHover
		{
			private static void Postfix(Turret __instance, ref string __result)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				if (Hovering && !string.IsNullOrEmpty(__result) && __instance.m_targetEnemies && PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, false, false))
				{
					PlanAmmo(__instance, (Humanoid)(object)Player.m_localPlayer);
					__result += HoverLine(Plan);
				}
			}
		}

		internal static readonly AddAll Instance = new AddAll();

		private ConfigEntry<float> range;

		private static readonly List<Batch> Plan = new List<Batch>();

		private static readonly StringBuilder Text = new StringBuilder();

		internal override string Section => "Add All";

		protected override string Summary => "Shift + Use on a fire, smelter, oven, cooking station, shield generator or ballista adds everything that fits, instead of one item: out of your backpack first and then out of the chests around you.";

		private static bool Hovering
		{
			get
			{
				if (Instance.On)
				{
					return (Object)(object)Player.m_localPlayer != (Object)null;
				}
				return false;
			}
		}

		private AddAll()
		{
		}

		protected override void Bind(ConfigFile config)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			range = config.Bind<float>(Section, "Range", 20f, new ConfigDescription("How far from you a chest may stand, in metres, for a Shift + Use to reach what it holds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
		}

		private static bool Wants(Humanoid user, bool hold, bool alt)
		{
			if (Instance.On && alt && !hold && (Object)(object)user != (Object)null)
			{
				return (Object)(object)user == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		private static int Count(Humanoid user, string name)
		{
			using (new Reach(user))
			{
				return user.GetInventory().CountItems(name, -1, true);
			}
		}

		private static void Take(Humanoid user, string name, int amount)
		{
			using (new Reach(user))
			{
				user.GetInventory().RemoveItem(name, amount, -1, true);
			}
		}

		private static ItemData Sample(Humanoid user, string name)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			ItemData item = user.GetInventory().GetItem(name, -1, false);
			if (item != null || !Instance.On || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return item;
			}
			foreach (Container item2 in NearbyChests.Find(((Component)Player.m_localPlayer).transform.position, Instance.range.Value))
			{
				item = item2.GetInventory().GetItem(name, -1, false);
				if (item != null)
				{
					return item;
				}
			}
			return null;
		}

		private static ItemData Ammo(Turret turret, Humanoid user)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			ItemData val = turret.FindAmmoItem(user.GetInventory(), true);
			if (val != null || !Instance.On || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return val;
			}
			foreach (Container item in NearbyChests.Find(((Component)Player.m_localPlayer).transform.position, Instance.range.Value))
			{
				val = turret.FindAmmoItem(item.GetInventory(), true);
				if (val != null)
				{
					return val;
				}
			}
			return null;
		}

		private static bool LeaveToGame(Humanoid user, List<Batch> plan)
		{
			return Total(plan) switch
			{
				1 => NearbyChests.Carried(user.GetInventory(), plan[0].Name, -1, matchWorldLevel: true) > 0, 
				0 => true, 
				_ => false, 
			};
		}

		private static int FuelRoom(float fuel, int maxFuel)
		{
			if (fuel > (float)(maxFuel - 1))
			{
				return 0;
			}
			return Mathf.FloorToInt((float)(maxFuel - 1) - fuel) + 1;
		}

		private static int Total(List<Batch> plan)
		{
			int num = 0;
			foreach (Batch item in plan)
			{
				num += item.Count;
			}
			return num;
		}

		private static string Describe(List<Batch> plan)
		{
			Text.Length = 0;
			foreach (Batch item in plan)
			{
				if (Text.Length > 0)
				{
					Text.Append(", ");
				}
				Text.Append(item.Count).Append(' ').Append(item.Name);
			}
			return Text.ToString();
		}

		private static string HoverLine(List<Batch> plan)
		{
			if (Total(plan) <= 0)
			{
				return "";
			}
			string text = ((ZInput.IsNonClassicFunctionality() && ZInput.IsGamepadActive()) ? "$KEY_AltKeys" : "$KEY_AltPlace");
			string text2 = Localization.instance.Localize(Describe(plan));
			return Localization.instance.Localize("\n[<color=yellow><b>" + text + " + $KEY_Use</b></color>] $omp_add_all", new string[1] { text2 });
		}

		private static void Report(Humanoid user, List<Batch> plan)
		{
			((Character)user).Message((MessageType)2, "$msg_added " + Describe(plan), 0, (Sprite)null, false);
		}

		private static void PlanFire(Fireplace fire, Humanoid user)
		{
			Plan.Clear();
			ZNetView nview = fire.m_nview;
			if (!((Object)(object)nview == (Object)null) && nview.IsValid() && fire.m_canRefill && !fire.m_infiniteFuel && !((Object)(object)fire.m_fuelItem == (Object)null))
			{
				int num = (int)fire.m_maxFuel - Mathf.CeilToInt(nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f));
				string name = fire.m_fuelItem.m_itemData.m_shared.m_name;
				int num2 = Mathf.Min(num, Count(user, name));
				if (num2 > 0)
				{
					Plan.Add(new Batch
					{
						Name = name,
						Count = num2
					});
				}
			}
		}

		private static void PlanSmelterFuel(Smelter smelter, Humanoid user)
		{
			Plan.Clear();
			if (!((Object)(object)smelter.m_fuelItem == (Object)null))
			{
				int num = FuelRoom(smelter.GetFuel(), smelter.m_maxFuel);
				string name = smelter.m_fuelItem.m_itemData.m_shared.m_name;
				int num2 = Mathf.Min(num, Count(user, name));
				if (num2 > 0)
				{
					Plan.Add(new Batch
					{
						Name = name,
						Count = num2
					});
				}
			}
		}

		private static void PlanSmelterOre(Smelter smelter, Humanoid user)
		{
			Plan.Clear();
			int num = smelter.m_maxOre - smelter.GetQueueSize();
			using (new Reach(user))
			{
				Inventory inventory = user.GetInventory();
				foreach (ItemConversion item in smelter.m_conversion)
				{
					if (num <= 0)
					{
						break;
					}
					if (!((Object)(object)item.m_from == (Object)null))
					{
						string name = item.m_from.m_itemData.m_shared.m_name;
						int num2 = Mathf.Min(num, inventory.CountItems(name, -1, true));
						if (num2 > 0)
						{
							ItemData val = Sample(user, name);
							Plan.Add(new Batch
							{
								Name = name,
								Prefab = ((Object)((Component)item.m_from).gameObject).name,
								Cheated = (val?.m_cheated ?? false),
								Count = num2
							});
							num -= num2;
						}
					}
				}
			}
		}

		private static void PlanOvenFuel(CookingStation station, Humanoid user)
		{
			Plan.Clear();
			if (station.m_useFuel && !((Object)(object)station.m_fuelItem == (Object)null))
			{
				int num = FuelRoom(station.GetFuel(), station.m_maxFuel);
				string name = station.m_fuelItem.m_itemData.m_shared.m_name;
				int num2 = Mathf.Min(num, Count(user, name));
				if (num2 > 0)
				{
					Plan.Add(new Batch
					{
						Name = name,
						Count = num2
					});
				}
			}
		}

		private static void PlanFood(CookingStation station, Humanoid user)
		{
			Plan.Clear();
			ZNetView nview = station.m_nview;
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || station.HaveDoneItem() || (station.m_requireFire && !station.IsFireLit()))
			{
				return;
			}
			int num = 0;
			for (int i = 0; i < station.m_slots.Length; i++)
			{
				if (nview.GetZDO().GetString("slot" + i, "") == "")
				{
					num++;
				}
			}
			using (new Reach(user))
			{
				Inventory inventory = user.GetInventory();
				foreach (ItemConversion item in station.m_conversion)
				{
					if (num <= 0)
					{
						break;
					}
					if (!((Object)(object)item.m_from == (Object)null))
					{
						string name = item.m_from.m_itemData.m_shared.m_name;
						int num2 = Mathf.Min(num, inventory.CountItems(name, -1, true));
						if (num2 > 0)
						{
							ItemData val = Sample(user, name);
							Plan.Add(new Batch
							{
								Name = name,
								Prefab = ((Object)((Component)item.m_from).gameObject).name,
								Cheated = (val?.m_cheated ?? false),
								Count = num2
							});
							num -= num2;
						}
					}
				}
			}
		}

		private static void PlanShieldFuel(ShieldGenerator generator, Humanoid user)
		{
			Plan.Clear();
			int num = FuelRoom(generator.GetFuel(), generator.m_maxFuel);
			foreach (ItemDrop fuelItem in generator.m_fuelItems)
			{
				if (num <= 0)
				{
					break;
				}
				if (!((Object)(object)fuelItem == (Object)null))
				{
					string name = fuelItem.m_itemData.m_shared.m_name;
					int num2 = Mathf.Min(num, Count(user, name));
					if (num2 > 0)
					{
						Plan.Add(new Batch
						{
							Name = name,
							Count = num2
						});
						num -= num2;
					}
				}
			}
		}

		private static void PlanAmmo(Turret turret, Humanoid user)
		{
			Plan.Clear();
			ZNetView nview = turret.m_nview;
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || turret.m_maxAmmo <= 0)
			{
				return;
			}
			int num = turret.m_maxAmmo - turret.GetAmmo();
			ItemData val = Ammo(turret, user);
			if (num > 0 && val != null && !((Object)(object)val.m_dropPrefab == (Object)null))
			{
				string name = val.m_shared.m_name;
				int num2 = Mathf.Min(num, Count(user, name));
				if (num2 > 0)
				{
					Plan.Add(new Batch
					{
						Name = name,
						Prefab = ((Object)val.m_dropPrefab).name,
						Count = num2
					});
				}
			}
		}

		private static bool AddSmelterFuel(Smelter smelter, Humanoid user)
		{
			PlanSmelterFuel(smelter, user);
			if (LeaveToGame(user, Plan))
			{
				return false;
			}
			int num = Total(Plan);
			Take(user, Plan[0].Name, num);
			for (int i = 0; i < num; i++)
			{
				smelter.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
			}
			Report(user, Plan);
			return true;
		}

		private static bool AddSmelterOre(Smelter smelter, Humanoid user)
		{
			PlanSmelterOre(smelter, user);
			if (LeaveToGame(user, Plan))
			{
				return false;
			}
			foreach (Batch item in Plan)
			{
				Take(user, item.Name, item.Count);
				for (int i = 0; i < item.Count; i++)
				{
					smelter.m_nview.InvokeRPC("RPC_AddOre", new object[2] { item.Prefab, item.Cheated });
				}
			}
			smelter.m_addedOreTime = Time.time;
			if (smelter.m_addOreAnimationDuration > 0f)
			{
				smelter.SetAnimation(true);
			}
			Report(user, Plan);
			return true;
		}

		private static bool AddOvenFuel(CookingStation station, Humanoid user)
		{
			PlanOvenFuel(station, user);
			if (LeaveToGame(user, Plan))
			{
				return false;
			}
			int num = Total(Plan);
			Take(user, Plan[0].Name, num);
			for (int i = 0; i < num; i++)
			{
				station.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
			}
			Report(user, Plan);
			return true;
		}

		private static bool AddFood(CookingStation station, Humanoid user)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			PlanFood(station, user);
			if (LeaveToGame(user, Plan))
			{
				return false;
			}
			ZNetView nview = station.m_nview;
			if (!nview.HasOwner())
			{
				nview.ClaimOwnership();
			}
			foreach (Batch item in Plan)
			{
				Take(user, item.Name, item.Count);
				for (int i = 0; i < item.Count; i++)
				{
					nview.InvokeRPC("RPC_AddItem", new object[2] { item.Prefab, item.Cheated });
					if ((int)station.m_skill != 0)
					{
						((Character)Player.m_localPlayer).RaiseSkill(station.m_skill, 0.4f);
					}
				}
			}
			Report(user, Plan);
			return true;
		}

		private static bool AddShieldFuel(ShieldGenerator generator, Humanoid user)
		{
			PlanShieldFuel(generator, user);
			if (LeaveToGame(user, Plan))
			{
				return false;
			}
			foreach (Batch item in Plan)
			{
				Take(user, item.Name, item.Count);
				for (int i = 0; i < item.Count; i++)
				{
					generator.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
				}
			}
			Report(user, Plan);
			return true;
		}
	}
	internal sealed class AreaRepair : Tweak
	{
		[HarmonyPatch(typeof(Player), "Repair")]
		private static class RepairEverythingAround
		{
			private static void Postfix(Player __instance, ItemData toolItem)
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
				//IL_0198: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
				if (!Instance.On || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || toolItem == null || toolItem.m_shared == null || !((Character)__instance).InPlaceMode())
				{
					return;
				}
				KeyCode value = Instance.singleRepairKey.Value;
				if ((int)value != 0 && ZInput.GetKey(value, false))
				{
					return;
				}
				bool placementCostDisabled = __instance.PlacementCostDisabled;
				bool stationFree = placementCostDisabled || ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)27));
				float buildStamina = __instance.GetBuildStamina();
				float attackEitr = toolItem.m_shared.m_attack.m_attackEitr;
				float num = (toolItem.m_shared.m_useDurability ? (toolItem.m_shared.m_useDurabilityDrain * Game.m_durabilityRate) : 0f);
				if (!placementCostDisabled && !CanPayFor(__instance, toolItem, buildStamina, attackEitr, num))
				{
					return;
				}
				Piece hoveringPiece = __instance.GetHoveringPiece();
				Vector3 centre = (((Object)(object)hoveringPiece != (Object)null) ? ((Component)hoveringPiece).transform.position : ((Component)__instance).transform.position);
				int num2 = 0;
				List<KeyValuePair<Piece, float>> list = PiecesInRadius(centre, Instance.radius.Value);
				for (int i = 0; i < list.Count; i++)
				{
					Piece key = list[i].Key;
					WearNTear component = ((Component)key).GetComponent<WearNTear>();
					if (!((Object)(object)component == (Object)null) && CanRepair(__instance, key, stationFree) && component.Repair())
					{
						num2++;
						if (!placementCostDisabled)
						{
							((Character)__instance).UseStamina(buildStamina);
							((Character)__instance).UseEitr(attackEitr);
							toolItem.m_durability -= num;
						}
						if (key.m_placeEffect != null)
						{
							key.m_placeEffect.Create(((Component)key).transform.position, ((Component)key).transform.rotation, (Transform)null, 1f, -1, ((Character)__instance).GetZDOID());
						}
						if (!placementCostDisabled && !CanPayFor(__instance, toolItem, buildStamina, attackEitr, num))
						{
							break;
						}
					}
				}
				StationsInRange.Clear();
				Nearby.Clear();
				if (num2 > 0)
				{
					__instance.FaceLookDirection();
					((Character)__instance).m_zanim.SetTrigger(toolItem.m_shared.m_attack.m_attackAnimation);
					((Character)__instance).Message((MessageType)1, Localization.instance.Localize("$msg_repaired", new string[1] { num2.ToString() }), 0, (Sprite)null, false);
				}
			}

			private static bool CanPayFor(Player player, ItemData toolItem, float stamina, float eitr, float wear)
			{
				if (((Character)player).HaveStamina(stamina) && (eitr <= 0f || ((Character)player).HaveEitr(eitr)))
				{
					return toolItem.m_durability >= wear;
				}
				return false;
			}
		}

		internal static readonly AreaRepair Instance = new AreaRepair();

		private ConfigEntry<float> radius;

		private ConfigEntry<KeyCode> singleRepairKey;

		private static readonly Dictionary<string, bool> StationsInRange = new Dictionary<string, bool>();

		private static readonly List<KeyValuePair<Piece, float>> Nearby = new List<KeyValuePair<Piece, float>>();

		internal override string Section => "Area Repair";

		protected override string Summary => "One swing of the hammer repairs every damaged piece around the one you aim at, instead of that one piece alone.";

		private AreaRepair()
		{
		}

		protected override void Bind(ConfigFile config)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			radius = config.Bind<float>(Section, "Radius", 10f, new ConfigDescription("Metres around the piece you aim at that one swing reaches. Everything inside it is repaired closest first, so a short swing mends what is nearest.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 64f), Array.Empty<object>()));
			singleRepairKey = config.Bind<KeyCode>(Section, "SingleRepairKey", (KeyCode)308, "Hold this while you swing to repair only the piece you aim at, the way the game does. None to always repair the area.");
		}

		private static List<KeyValuePair<Piece, float>> PiecesInRadius(Vector3 centre, float radius)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Nearby.Clear();
			foreach (Piece s_allPiece in Piece.s_allPieces)
			{
				if (!((Object)(object)s_allPiece == (Object)null) && ((Component)s_allPiece).gameObject.layer != Piece.s_ghostLayer)
				{
					float num = Vector3.Distance(centre, ((Component)s_allPiece).transform.position);
					if (num <= radius)
					{
						Nearby.Add(new KeyValuePair<Piece, float>(s_allPiece, num));
					}
				}
			}
			Nearby.Sort((KeyValuePair<Piece, float> a, KeyValuePair<Piece, float> b) => a.Value.CompareTo(b.Value));
			return Nearby;
		}

		private static bool CanRepair(Player player, Piece piece, bool stationFree)
		{
			//IL_005a: 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)
			if (!stationFree && (Object)(object)piece.m_craftingStation != (Object)null)
			{
				string name = piece.m_craftingStation.m_name;
				if (!StationsInRange.TryGetValue(name, out var value))
				{
					value = Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(name, ((Component)player).transform.position));
					StationsInRange[name] = value;
				}
				if (!value)
				{
					return false;
				}
			}
			return PrivateArea.CheckAccess(((Component)piece).transform.position, 0f, true, false);
		}
	}
	internal sealed class AutoPins : Tweak
	{
		private sealed class Site
		{
			public string PrefabName;

			public bool GameIcon;

			public Teleport Entrance;

			public PlaceKind Kind;

			public string KindName;
		}

		internal enum PlaceKind
		{
			None,
			Treasure,
			Generated,
			Tar
		}

		internal enum MinedOut
		{
			Tick,
			Remove,
			Keep
		}

		[HarmonyPatch(typeof(Player), "Update")]
		private static class Sweep
		{
			private static void Postfix(Player __instance)
			{
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: 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)
				if (!Instance.On || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || Time.time < nextSweep)
				{
					return;
				}
				nextSweep = Time.time + 3f;
				Minimap instance = Minimap.instance;
				Vector3 position = ((Component)__instance).transform.position;
				if (!((Object)(object)instance == (Object)null) && !Character.InInterior(position))
				{
					if (Instance.dungeons.Value || Instance.places.Value)
					{
						Instance.SweepLocations(position);
					}
					if (Instance.minedOut.Value != MinedOut.Keep)
					{
						Instance.SweepMinedOut(instance, position);
					}
				}
			}
		}

		[HarmonyPatch(typeof(MineRock5), "Damage")]
		private static class StrikeMineRock5
		{
			private static void Postfix(MineRock5 __instance, HitData hit)
			{