Decompiled source of MimirsWell v1.0.0

plugins/MimirsWell/MimirsWell.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace MimirsWell;

internal static class ChestUpgrade
{
	private static readonly Dictionary<string, string> Steps = new Dictionary<string, string>
	{
		{ "piece_chest_wood", "MW_RuneChest_Wood" },
		{ "piece_chest", "MW_RuneChest_Iron" },
		{ "piece_chest_blackmetal", "MW_RuneChest_Blackmetal" }
	};

	internal const string ChiselPrefab = "MW_RuneChisel";

	private static readonly FieldInfo RightItemField = AccessTools.Field(typeof(Humanoid), "m_rightItem");

	internal static bool HasChisel()
	{
		Player localPlayer = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)localPlayer))
		{
			return false;
		}
		foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
		{
			if (IsChisel(allItem))
			{
				return true;
			}
		}
		return false;
	}

	internal static bool WieldsChisel()
	{
		Player localPlayer = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)localPlayer))
		{
			return false;
		}
		if (IsChisel(((Humanoid)localPlayer).GetCurrentWeapon()))
		{
			return true;
		}
		if (RightItemField != null && IsChisel((ItemData)/*isinst with value type is only supported in some contexts*/))
		{
			return true;
		}
		foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
		{
			if (allItem.m_equipped && IsChisel(allItem))
			{
				return true;
			}
		}
		return false;
	}

	private static bool IsChisel(ItemData item)
	{
		if (item == null)
		{
			return false;
		}
		if (item.m_shared.m_name == "$mw_chisel")
		{
			return true;
		}
		if (Object.op_Implicit((Object)(object)item.m_dropPrefab))
		{
			return ((Object)item.m_dropPrefab).name == "MW_RuneChisel";
		}
		return false;
	}

	internal static void LogState(Container chest)
	{
		Player localPlayer = Player.m_localPlayer;
		ItemData val = (Object.op_Implicit((Object)(object)localPlayer) ? ((Humanoid)localPlayer).GetCurrentWeapon() : null);
		object? obj = RightItemField?.GetValue(localPlayer);
		ItemData val2 = (ItemData)((obj is ItemData) ? obj : null);
		MimirsWellPlugin.Log.LogDebug((object)("Chest interact: " + CleanName(Object.op_Implicit((Object)(object)chest) ? ((Object)((Component)chest).gameObject).name : "none") + ", upgrade target " + (Find(chest) ?? "none") + ", current weapon '" + ((val != null) ? val.m_shared.m_name : "none") + "', right hand '" + ((val2 != null) ? val2.m_shared.m_name : "none") + "', " + $"carries chisel {HasChisel()}, wields chisel {WieldsChisel()}"));
	}

	internal static string Find(Container chest)
	{
		if (!Object.op_Implicit((Object)(object)chest))
		{
			return null;
		}
		if (!Steps.TryGetValue(CleanName(((Object)((Component)chest).gameObject).name), out var value))
		{
			return null;
		}
		return value;
	}

	internal static string HoverText(Container chest)
	{
		string text = Find(chest);
		if (text == null)
		{
			return string.Empty;
		}
		GameObject prefab = PrefabManager.Instance.GetPrefab(text);
		Piece val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Piece>() : null);
		string text2 = (Object.op_Implicit((Object)(object)val) ? val.m_name : text);
		if (WieldsChisel())
		{
			return Localization.instance.Localize("\n<color=#8fc7ff>[<b>$KEY_Use</b>] $mw_upgrade_to " + text2 + "</color>");
		}
		if (!HasChisel())
		{
			return Localization.instance.Localize("\n<color=#9a8f80>$mw_upgrade_to " + text2 + ": $mw_upgrade_needs_chisel</color>");
		}
		return Localization.instance.Localize("\n<color=#9a8f80>$mw_upgrade_to " + text2 + ": $mw_upgrade_hold_chisel</color>");
	}

	internal static bool Upgrade(Container chest)
	{
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		string text = Find(chest);
		Player localPlayer = Player.m_localPlayer;
		if (text == null || !Object.op_Implicit((Object)(object)localPlayer))
		{
			return false;
		}
		if (!WieldsChisel())
		{
			Message(HasChisel() ? "$mw_upgrade_hold_chisel" : "$mw_upgrade_needs_chisel");
			return true;
		}
		ZNetView component = ((Component)chest).GetComponent<ZNetView>();
		if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
		{
			return false;
		}
		if (chest.IsInUse() || RuneChest.IsLockedByOther(chest, localPlayer.GetPlayerID()))
		{
			Message("$mw_chest_busy");
			return true;
		}
		if (!PrivateArea.CheckAccess(((Component)chest).transform.position, 0f, true, false))
		{
			return true;
		}
		GameObject prefab = PrefabManager.Instance.GetPrefab(text);
		if (!Object.op_Implicit((Object)(object)prefab))
		{
			MimirsWellPlugin.Log.LogWarning((object)("Upgrade target " + text + " is not available"));
			return true;
		}
		component.ClaimOwnership();
		if (!component.IsOwner())
		{
			Message("$mw_upgrade_failed");
			return true;
		}
		List<ItemData> list = new List<ItemData>();
		foreach (ItemData allItem in chest.GetInventory().GetAllItems())
		{
			list.Add(allItem.Clone());
		}
		Vector3 position = ((Component)chest).transform.position;
		Quaternion rotation = ((Component)chest).transform.rotation;
		Piece component2 = ((Component)chest).GetComponent<Piece>();
		GameObject val = Object.Instantiate<GameObject>(prefab, position, rotation);
		Container component3 = val.GetComponent<Container>();
		Piece component4 = val.GetComponent<Piece>();
		if (!Object.op_Implicit((Object)(object)component3))
		{
			Object.Destroy((Object)(object)val);
			MimirsWellPlugin.Log.LogWarning((object)("Upgrade target " + text + " has no container"));
			return true;
		}
		Inventory inventory = component3.GetInventory();
		foreach (ItemData item in list)
		{
			if (!inventory.AddItem(item, item.m_gridPos))
			{
				inventory.AddItem(item);
			}
		}
		CopyCreator(component2, component4);
		component.Destroy();
		if (Object.op_Implicit((Object)(object)component4) && component4.m_placeEffect != null)
		{
			component4.m_placeEffect.Create(position, rotation, (Transform)null, 1f, -1, ZDOID.None);
		}
		Message("$mw_upgrade_done");
		return true;
	}

	private static void CopyCreator(Piece from, Piece to)
	{
		if (!Object.op_Implicit((Object)(object)from) || !Object.op_Implicit((Object)(object)to))
		{
			return;
		}
		string[] array = new string[2] { "m_creator", "m_creatorPlatformUserIDIndex" };
		foreach (string text in array)
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(Piece), text);
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(to, fieldInfo.GetValue(from));
			}
		}
	}

	private static string CleanName(string name)
	{
		int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
		if (num < 0)
		{
			return name;
		}
		return name.Substring(0, num);
	}

	private static void Message(string token)
	{
		if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize(token), 0, (Sprite)null, false);
		}
	}
}
internal enum ItemFilter
{
	All,
	Materials,
	Food,
	Weapons,
	Armor,
	Tools,
	Misc
}
internal enum SortMode
{
	Name,
	Amount,
	Weight
}
public class HoardContainer : MonoBehaviour
{
	private class SlotState
	{
		public string Key;

		public int Expected;
	}

	private static readonly List<HoardContainer> Open = new List<HoardContainer>();

	private static readonly FieldInfo DragItemField = AccessTools.Field(typeof(InventoryGui), "m_dragItem");

	private static readonly FieldInfo DragInventoryField = AccessTools.Field(typeof(InventoryGui), "m_dragInventory");

	private static readonly FieldInfo DragAmountField = AccessTools.Field(typeof(InventoryGui), "m_dragAmount");

	private static readonly FieldInfo CurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer");

	private static readonly MethodInfo SetupDragItemMethod = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null);

	private static readonly FieldInfo ItemsField = AccessTools.Field(typeof(Inventory), "m_inventory");

	private static readonly MethodInfo UpdateWeightMethod = AccessTools.Method(typeof(Inventory), "UpdateTotalWeight", (Type[])null, (Type[])null);

	private Dictionary<ItemData, SlotState> m_slots = new Dictionary<ItemData, SlotState>();

	private readonly Dictionary<string, Vector2i> m_positions = new Dictionary<string, Vector2i>();

	internal Container Container;

	internal MimirsWellStation Well;

	private bool m_open;

	private float m_nextPoll;

	private float m_lastChange;

	private bool m_needsRelayout;

	private string m_search = string.Empty;

	private ItemFilter m_filter;

	private SortMode m_sort;

	private int m_totalRows;

	private const int MaxRows = 64;

	private static float s_nextFullMessage;

	internal static bool AnyOpen => Open.Count > 0;

	internal bool IsOpen => m_open;

	internal int TotalRows => m_totalRows;

	private static int MinRows => Mathf.Max(1, MimirsWellPlugin.HoardRows.Value);

	internal SortMode Sort => m_sort;

	internal ItemFilter Filter => m_filter;

	private Inventory Mirror
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)Container))
			{
				return null;
			}
			return Container.GetInventory();
		}
	}

	private static List<ItemData> SlotsOf(Inventory inventory)
	{
		return ItemsField?.GetValue(inventory) as List<ItemData>;
	}

	internal static bool IsMirror(Inventory inventory)
	{
		if (inventory == null)
		{
			return false;
		}
		foreach (HoardContainer item in Open)
		{
			if (Object.op_Implicit((Object)(object)item) && item.Mirror == inventory)
			{
				return true;
			}
		}
		return false;
	}

	private void Awake()
	{
		Container = ((Component)this).GetComponent<Container>();
		Well = ((Component)this).GetComponent<MimirsWellStation>();
	}

	private void OnDestroy()
	{
		Open.Remove(this);
		if (m_open)
		{
			EndSession(writeBack: false);
		}
	}

	internal static void CloseAll()
	{
		for (int num = Open.Count - 1; num >= 0; num--)
		{
			Open[num].EndSession(writeBack: true);
		}
	}

	internal void BeginSession()
	{
		if (!m_open && Object.op_Implicit((Object)(object)Container) && Object.op_Implicit((Object)(object)Well))
		{
			m_open = true;
			m_search = string.Empty;
			Open.Add(this);
			StorageSession.Begin(Well);
			Sync();
			HoardControls.Show(this);
		}
	}

	private void EndSession(bool writeBack)
	{
		if (m_open)
		{
			m_open = false;
			Open.Remove(this);
			if (writeBack)
			{
				Sync();
			}
			Inventory mirror = Mirror;
			if (mirror != null)
			{
				mirror.RemoveAll();
			}
			m_slots.Clear();
			StorageSession.End();
			HoardControls.Hide();
		}
	}

	private void Update()
	{
		if (!m_open)
		{
			return;
		}
		StorageSession current = StorageSession.Current;
		InventoryGui instance = InventoryGui.instance;
		if (current == null || !Object.op_Implicit((Object)(object)instance) || (Object)(object)CurrentContainer(instance) != (Object)(object)Container || !InventoryGui.IsVisible())
		{
			EndSession(writeBack: true);
			return;
		}
		current.Update();
		ClampDrag(instance);
		if (Time.time < m_nextPoll)
		{
			return;
		}
		m_nextPoll = Time.time + 0.1f;
		if (IsDragging())
		{
			return;
		}
		if (m_needsRelayout && !ModifierHeld() && Time.time > m_lastChange + 0.4f)
		{
			m_needsRelayout = false;
			Relayout();
		}
		else if (HasChanged() || current.Dirty)
		{
			if (ModifierHeld())
			{
				WriteThrough(current);
			}
			else
			{
				Sync();
			}
		}
	}

	private bool HasChanged()
	{
		Inventory mirror = Mirror;
		if (mirror == null)
		{
			return false;
		}
		List<ItemData> allItems = mirror.GetAllItems();
		if (allItems.Count != m_slots.Count)
		{
			return true;
		}
		foreach (ItemData item in allItems)
		{
			if (!m_slots.TryGetValue(item, out var value) || value.Expected != item.m_stack)
			{
				return true;
			}
		}
		return false;
	}

	internal void Sync()
	{
		StorageSession current = StorageSession.Current;
		if (current != null)
		{
			WriteBack(current);
			SplitOversizedStacks(current);
			Rebuild(current);
			current.Dirty = false;
		}
	}

	private void WriteThrough(StorageSession session)
	{
		WriteBack(session);
		SplitOversizedStacks(session);
		Inventory mirror = Mirror;
		if (mirror == null)
		{
			return;
		}
		Dictionary<ItemData, SlotState> dictionary = new Dictionary<ItemData, SlotState>();
		foreach (ItemData allItem in mirror.GetAllItems())
		{
			if (m_slots.TryGetValue(allItem, out var value))
			{
				value.Expected = allItem.m_stack;
			}
			else
			{
				value = new SlotState
				{
					Key = MatchKey(allItem),
					Expected = allItem.m_stack
				};
			}
			dictionary[allItem] = value;
		}
		int num = Mathf.Max(1, mirror.GetWidth());
		int height = mirror.GetHeight();
		if (mirror.GetAllItems().Count > (height - 1) * num && height < 64)
		{
			mirror.SetHeight(height + 1);
			m_totalRows = height + 1;
		}
		m_slots = dictionary;
		session.Dirty = false;
		m_lastChange = Time.time;
		m_needsRelayout = true;
	}

	private static bool ModifierHeld()
	{
		if (!ZInput.GetKey((KeyCode)306, false) && !ZInput.GetKey((KeyCode)305, false) && !ZInput.GetKey((KeyCode)304, false))
		{
			return ZInput.GetKey((KeyCode)303, false);
		}
		return true;
	}

	private void WriteBack(StorageSession session)
	{
		Inventory mirror = Mirror;
		if (mirror == null)
		{
			return;
		}
		HashSet<ItemData> hashSet = new HashSet<ItemData>();
		int num = 0;
		int num2 = 0;
		foreach (ItemData item in new List<ItemData>(mirror.GetAllItems()))
		{
			if (!m_slots.TryGetValue(item, out var value))
			{
				StoreOrGiveBack(session, item, item.m_stack);
				num += item.m_stack;
				continue;
			}
			hashSet.Add(item);
			int num3 = item.m_stack - value.Expected;
			if (num3 > 0)
			{
				StoreOrGiveBack(session, item, num3);
				num += num3;
			}
			else if (num3 < 0)
			{
				num2 += RemoveByKey(session, value.Key, -num3);
			}
		}
		foreach (KeyValuePair<ItemData, SlotState> slot in m_slots)
		{
			if (!hashSet.Contains(slot.Key))
			{
				num2 += RemoveByKey(session, slot.Value.Key, slot.Value.Expected);
			}
		}
		if (num > 0 || num2 > 0)
		{
			MimirsWellPlugin.Log.LogDebug((object)$"Well write-back: {num2} taken out, {num} put in");
		}
	}

	private static int RemoveByKey(StorageSession session, string key, int amount)
	{
		int num = 0;
		foreach (RuneChest chest in session.Chests)
		{
			if (amount <= 0)
			{
				break;
			}
			if (!Object.op_Implicit((Object)(object)chest) || !chest.IsUsable)
			{
				continue;
			}
			Inventory inventory = chest.Inventory;
			if (inventory == null)
			{
				continue;
			}
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (amount <= 0)
				{
					break;
				}
				if (!(MatchKey(item) != key))
				{
					int num2 = Mathf.Min(amount, item.m_stack);
					inventory.RemoveItem(item, num2);
					amount -= num2;
					num += num2;
				}
			}
		}
		if (amount > 0)
		{
			MimirsWellPlugin.Log.LogWarning((object)$"Well write-back could not find {amount} of {key} in the bound chests");
		}
		return num;
	}

	internal static bool AcceptDrop(Inventory mirror, Inventory from, ItemData item, int amount, int x, int y)
	{
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		if (from == null || item == null)
		{
			return false;
		}
		List<ItemData> list = SlotsOf(mirror);
		if (list == null)
		{
			return false;
		}
		amount = Mathf.Clamp(amount, 1, item.m_stack);
		StorageSession current = StorageSession.Current;
		if (current == null)
		{
			return false;
		}
		amount = current.CapacityFor(item, amount);
		if (amount <= 0)
		{
			return false;
		}
		ItemData val = null;
		foreach (ItemData item2 in list)
		{
			if (item2.m_gridPos.x == x && item2.m_gridPos.y == y)
			{
				val = item2;
				break;
			}
		}
		if (val != null && MatchKey(val) == MatchKey(item))
		{
			ItemData obj = val;
			obj.m_stack += amount;
		}
		else
		{
			Vector2i val2 = (Vector2i)((val == null) ? new Vector2i(x, y) : TakeFreeSlot(mirror, list));
			if (val2.x < 0)
			{
				int num = current.StoreIntoChests(item, amount);
				if (num <= 0)
				{
					return false;
				}
				from.RemoveItem(item, num);
				return true;
			}
			ItemData val3 = item.Clone();
			val3.m_stack = amount;
			val3.m_equipped = false;
			val3.m_gridPos = val2;
			list.Add(val3);
		}
		from.RemoveItem(item, amount);
		return true;
	}

	private static Vector2i TakeFreeSlot(Inventory mirror, List<ItemData> slots)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//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_0011: 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_0021: Unknown result type (might be due to invalid IL or missing references)
		Vector2i val = FreeSlot(mirror, slots);
		if (val.x >= 0)
		{
			return val;
		}
		int height = mirror.GetHeight();
		if (height >= 64)
		{
			return new Vector2i(-1, -1);
		}
		mirror.SetHeight(height + 1);
		return new Vector2i(0, height);
	}

	private static Vector2i FreeSlot(Inventory mirror, List<ItemData> slots)
	{
		//IL_007e: 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)
		for (int i = 0; i < mirror.GetHeight(); i++)
		{
			for (int j = 0; j < mirror.GetWidth(); j++)
			{
				bool flag = false;
				foreach (ItemData slot in slots)
				{
					if (slot.m_gridPos.x == j && slot.m_gridPos.y == i)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					return new Vector2i(j, i);
				}
			}
		}
		return new Vector2i(-1, -1);
	}

	private static string MatchKey(ItemData item)
	{
		string text = item.m_shared.m_name + "|" + item.m_quality + "|" + item.m_variant + "|" + item.m_worldLevel;
		if (item.m_shared.m_maxStackSize > 1)
		{
			return text;
		}
		return text + "|" + item.m_durability.ToString("F1") + "|" + item.m_crafterName;
	}

	private static void StoreOrGiveBack(StorageSession session, ItemData item, int amount)
	{
		if (amount > 0)
		{
			int num = session.StoreIntoChests(item, amount);
			int num2 = amount - num;
			if (num2 > 0)
			{
				GiveBack(session, item, num2, tryChestsFirst: false);
			}
		}
	}

	private static void GiveBack(StorageSession session, ItemData template, int amount, bool tryChestsFirst)
	{
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		if (amount <= 0)
		{
			return;
		}
		if (tryChestsFirst)
		{
			amount -= session.StoreIntoChests(template, amount);
			if (amount <= 0)
			{
				return;
			}
		}
		Player localPlayer = Player.m_localPlayer;
		int num = Mathf.Max(1, template.m_shared.m_maxStackSize);
		while (amount > 0 && Object.op_Implicit((Object)(object)localPlayer))
		{
			int num2 = Mathf.Min(amount, num);
			ItemData val = template.Clone();
			val.m_stack = num2;
			val.m_equipped = false;
			if (!((Humanoid)localPlayer).GetInventory().CanAddItem(val, num2) || !((Humanoid)localPlayer).GetInventory().AddItem(val))
			{
				break;
			}
			amount -= num2;
		}
		if (amount <= 0)
		{
			Message("$mw_msg_hoardfull");
		}
		else if (Object.op_Implicit((Object)(object)localPlayer))
		{
			ItemData obj = template.Clone();
			obj.m_stack = amount;
			obj.m_equipped = false;
			ItemDrop.DropItem(obj, amount, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward + Vector3.up, Quaternion.identity);
			Message("$mw_msg_dropped");
		}
	}

	private static void SplitOversizedStacks(StorageSession session)
	{
		Player localPlayer = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)localPlayer))
		{
			return;
		}
		Inventory inventory = ((Humanoid)localPlayer).GetInventory();
		foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
		{
			int maxStackSize = item.m_shared.m_maxStackSize;
			if (maxStackSize <= 1 || item.m_stack <= maxStackSize)
			{
				continue;
			}
			int num = item.m_stack - maxStackSize;
			item.m_stack = maxStackSize;
			ItemData val = item.Clone();
			int i;
			int num2;
			for (i = 0; i < num; i += num2)
			{
				num2 = Mathf.Min(num - i, maxStackSize);
				ItemData val2 = val.Clone();
				val2.m_stack = num2;
				val2.m_equipped = false;
				if (!inventory.CanAddItem(val2, num2) || !inventory.AddItem(val2))
				{
					break;
				}
			}
			if (i < num)
			{
				GiveBack(session, val, num - i, tryChestsFirst: true);
			}
		}
	}

	private void Rebuild(StorageSession session)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_0278: Unknown result type (might be due to invalid IL or missing references)
		Inventory mirror = Mirror;
		if (mirror == null)
		{
			return;
		}
		List<HoardEntry> list = BuildGroups(session);
		list.Sort(CompareGroups);
		int num = Mathf.Max(1, mirror.GetWidth());
		List<ItemData> list2 = SlotsOf(mirror);
		if (list2 == null)
		{
			return;
		}
		Dictionary<HoardEntry, Vector2i> dictionary = new Dictionary<HoardEntry, Vector2i>();
		HashSet<int> hashSet = new HashSet<int>();
		foreach (HoardEntry item2 in list)
		{
			if (m_positions.TryGetValue(item2.Key, out var value))
			{
				int item = value.y * num + value.x;
				if (value.x < num && hashSet.Add(item))
				{
					dictionary[item2] = value;
				}
			}
		}
		int i = 0;
		foreach (HoardEntry item3 in list)
		{
			if (!dictionary.ContainsKey(item3))
			{
				for (; hashSet.Contains(i); i++)
				{
				}
				hashSet.Add(i);
				dictionary[item3] = new Vector2i(i % num, i / num);
			}
		}
		int num2 = 0;
		int num3 = -1;
		foreach (KeyValuePair<HoardEntry, Vector2i> item4 in dictionary)
		{
			num2 = Mathf.Max(num2, item4.Value.y);
			num3 = Mathf.Max(num3, item4.Value.y * num + item4.Value.x);
		}
		m_totalRows = Mathf.Max(MinRows, num2 + 2);
		int totalRows = m_totalRows;
		list2.Clear();
		m_slots.Clear();
		m_positions.Clear();
		mirror.SetHeight(totalRows);
		foreach (KeyValuePair<HoardEntry, Vector2i> item5 in dictionary)
		{
			HoardEntry key = item5.Key;
			if (key.Total > 0)
			{
				ItemData val = key.Sample.Clone();
				val.m_equipped = false;
				val.m_stack = key.Total;
				val.m_gridPos = item5.Value;
				list2.Add(val);
				m_slots[val] = new SlotState
				{
					Key = key.Key,
					Expected = key.Total
				};
				m_positions[key.Key] = item5.Value;
			}
		}
		UpdateWeightMethod?.Invoke(mirror, null);
		m_needsRelayout = num3 + 1 > dictionary.Count;
		m_lastChange = Time.time;
		UpdateTitle(session, list.Count);
		HoardControls.Refresh();
	}

	private List<HoardEntry> BuildGroups(StorageSession session)
	{
		List<HoardEntry> list = new List<HoardEntry>();
		Dictionary<string, HoardEntry> dictionary = new Dictionary<string, HoardEntry>();
		foreach (RuneChest chest in session.Chests)
		{
			Inventory inventory = chest.Inventory;
			if (inventory == null)
			{
				continue;
			}
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (Matches(allItem))
				{
					string key = MatchKey(allItem);
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = new HoardEntry
						{
							Key = key,
							Sample = allItem
						};
						list.Add(value);
						dictionary[key] = value;
					}
					if (allItem.m_shared.m_maxStackSize <= 1 && value.Total > 0)
					{
						value = new HoardEntry
						{
							Key = key,
							Sample = allItem
						};
						list.Add(value);
					}
					value.Total += allItem.m_stack;
				}
			}
		}
		return list;
	}

	private bool Matches(ItemData item)
	{
		//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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Invalid comparison between Unknown and I4
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Invalid comparison between Unknown and I4
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Invalid comparison between Unknown and I4
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Invalid comparison between Unknown and I4
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Invalid comparison between Unknown and I4
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Invalid comparison between Unknown and I4
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Invalid comparison between Unknown and I4
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Invalid comparison between Unknown and I4
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Invalid comparison between Unknown and I4
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Invalid comparison between Unknown and I4
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Invalid comparison between Unknown and I4
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Invalid comparison between Unknown and I4
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Invalid comparison between Unknown and I4
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Invalid comparison between Unknown and I4
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Invalid comparison between Unknown and I4
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Invalid comparison between Unknown and I4
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Invalid comparison between Unknown and I4
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Invalid comparison between Unknown and I4
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Invalid comparison between Unknown and I4
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Invalid comparison between Unknown and I4
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Invalid comparison between Unknown and I4
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Invalid comparison between Unknown and I4
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Invalid comparison between Unknown and I4
		if (m_search.Length > 0 && Localization.instance.Localize(item.m_shared.m_name).IndexOf(m_search, StringComparison.CurrentCultureIgnoreCase) < 0)
		{
			return false;
		}
		ItemType itemType = item.m_shared.m_itemType;
		switch (m_filter)
		{
		case ItemFilter.Materials:
			if ((int)itemType != 1 && (int)itemType != 9)
			{
				return (int)itemType == 23;
			}
			return true;
		case ItemFilter.Food:
			if ((int)itemType != 2)
			{
				return (int)itemType == 21;
			}
			return true;
		case ItemFilter.Weapons:
			if ((int)itemType != 3 && (int)itemType != 14 && (int)itemType != 22 && (int)itemType != 4 && (int)itemType != 5)
			{
				return (int)itemType == 15;
			}
			return true;
		case ItemFilter.Armor:
			if ((int)itemType != 6 && (int)itemType != 7 && (int)itemType != 11 && (int)itemType != 17 && (int)itemType != 12 && (int)itemType != 18)
			{
				return (int)itemType == 24;
			}
			return true;
		case ItemFilter.Tools:
			return (int)itemType == 19;
		case ItemFilter.Misc:
			if ((int)itemType != 16 && (int)itemType != 13 && (int)itemType != 10)
			{
				return (int)itemType == 0;
			}
			return true;
		default:
			return true;
		}
	}

	private int CompareGroups(HoardEntry a, HoardEntry b)
	{
		switch (m_sort)
		{
		case SortMode.Amount:
			return b.Total.CompareTo(a.Total);
		case SortMode.Weight:
			return (b.Sample.m_shared.m_weight * (float)b.Total).CompareTo(a.Sample.m_shared.m_weight * (float)a.Total);
		default:
		{
			int num = string.Compare(Localization.instance.Localize(a.Sample.m_shared.m_name), Localization.instance.Localize(b.Sample.m_shared.m_name), StringComparison.CurrentCultureIgnoreCase);
			if (num == 0)
			{
				return b.Total.CompareTo(a.Total);
			}
			return num;
		}
		}
	}

	private void UpdateTitle(StorageSession session, int shown)
	{
		Container.m_name = ((session.Denied > 0) ? $"$mw_well_name <color=#d08a8a>({session.Denied} $mw_ui_busy)</color>" : "$mw_well_name");
	}

	internal void SetSearch(string search)
	{
		search = search ?? string.Empty;
		if (!(m_search == search))
		{
			m_search = search;
			Relayout();
		}
	}

	private void Relayout()
	{
		m_positions.Clear();
		Sync();
	}

	internal void SetFilter(ItemFilter filter)
	{
		if (m_filter != filter)
		{
			m_filter = filter;
			Relayout();
		}
	}

	internal void CycleFilter()
	{
		m_filter = (ItemFilter)((int)(m_filter + 1) % 7);
		Relayout();
	}

	internal void CycleSort()
	{
		m_sort = (SortMode)((int)(m_sort + 1) % 3);
		Relayout();
	}

	private void ClampDrag(InventoryGui gui)
	{
		if (DragItemField == null || DragInventoryField == null || DragAmountField == null)
		{
			return;
		}
		object? value = DragItemField.GetValue(gui);
		ItemData val = (ItemData)((value is ItemData) ? value : null);
		if (val == null)
		{
			return;
		}
		object? value2 = DragInventoryField.GetValue(gui);
		Inventory val2 = (Inventory)((value2 is Inventory) ? value2 : null);
		if (val2 != null && val2 == Mirror)
		{
			int num = Mathf.Max(1, val.m_shared.m_maxStackSize);
			if (DragAmountField.GetValue(gui) is int num2 && num2 > num)
			{
				DragAmountField.SetValue(gui, num);
			}
		}
	}

	private static bool IsDragging()
	{
		if (!Object.op_Implicit((Object)(object)InventoryGui.instance) || DragItemField == null)
		{
			return false;
		}
		return DragItemField.GetValue(InventoryGui.instance) != null;
	}

	internal static ItemData DragItem(InventoryGui gui)
	{
		object? obj = DragItemField?.GetValue(gui);
		return (ItemData)((obj is ItemData) ? obj : null);
	}

	internal static Inventory DragInventory(InventoryGui gui)
	{
		object? obj = DragInventoryField?.GetValue(gui);
		return (Inventory)((obj is Inventory) ? obj : null);
	}

	internal static int DragAmount(InventoryGui gui)
	{
		object obj = DragAmountField?.GetValue(gui);
		if (obj is int)
		{
			return (int)obj;
		}
		return 0;
	}

	internal static void ReportFull()
	{
		if (!(Time.time < s_nextFullMessage))
		{
			s_nextFullMessage = Time.time + 1f;
			Message("$mw_msg_hoardfull");
		}
	}

	internal static void ClearDrag(InventoryGui gui)
	{
		SetupDragItemMethod?.Invoke(gui, new object[3] { null, null, 0 });
	}

	private static Container CurrentContainer(InventoryGui gui)
	{
		if (!(CurrentContainerField != null))
		{
			return null;
		}
		object? value = CurrentContainerField.GetValue(gui);
		return (Container)((value is Container) ? value : null);
	}

	private static void Message(string token)
	{
		if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize(token), 0, (Sprite)null, false);
		}
	}
}
internal class HoardControls : MonoBehaviour
{
	private const float ControlHeight = 28f;

	private const float Inset = 10f;

	private const float MinimumGap = 90f;

	private static readonly FieldInfo ContainerGridField = AccessTools.Field(typeof(InventoryGui), "m_containerGrid");

	private static HoardControls s_instance;

	private HoardContainer m_hoard;

	private InputField m_search;

	private Button m_filterButton;

	private Button m_sortButton;

	private GameObject m_searchGo;

	private GameObject m_filterGo;

	private GameObject m_sortGo;

	private bool m_searchFocused;

	internal static void Show(HoardContainer hoard)
	{
		if (EnsureCreated())
		{
			s_instance.m_hoard = hoard;
			((Component)s_instance).gameObject.SetActive(true);
			s_instance.m_search.text = string.Empty;
			s_instance.Dock();
			s_instance.UpdateLabels();
		}
	}

	internal static void Hide()
	{
		if (Object.op_Implicit((Object)(object)s_instance))
		{
			s_instance.m_hoard = null;
			s_instance.SetSearchFocus(focused: false);
			s_instance.Undock();
			((Component)s_instance).gameObject.SetActive(false);
		}
	}

	internal static void Refresh()
	{
		if (Object.op_Implicit((Object)(object)s_instance) && ((Component)s_instance).gameObject.activeSelf)
		{
			s_instance.UpdateLabels();
		}
	}

	private static bool EnsureCreated()
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		if (Object.op_Implicit((Object)(object)s_instance))
		{
			return true;
		}
		if (GUIManager.Instance == null || !Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront))
		{
			return false;
		}
		GameObject val = new GameObject("MW_HoardControls", new Type[1] { typeof(RectTransform) });
		val.transform.SetParent(GUIManager.CustomGUIFront.transform, false);
		s_instance = val.AddComponent<HoardControls>();
		try
		{
			s_instance.Build();
		}
		catch (Exception arg)
		{
			MimirsWellPlugin.Log.LogError((object)$"Building the well controls failed: {arg}");
			Object.Destroy((Object)(object)val);
			s_instance = null;
			return false;
		}
		val.SetActive(false);
		return true;
	}

	private void Build()
	{
		//IL_0018: 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_002c: 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_00b2: Expected O, but got Unknown
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Expected O, but got Unknown
		Transform transform = ((Component)this).transform;
		m_searchGo = GUIManager.Instance.CreateInputField(transform, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, (ContentType)0, Localization.instance.Localize("$mw_ui_search"), 15, 160f, 28f);
		m_search = m_searchGo.GetComponent<InputField>();
		((UnityEvent<string>)(object)m_search.onValueChanged).AddListener((UnityAction<string>)delegate(string value)
		{
			m_hoard?.SetSearch(value);
		});
		m_filterGo = CreateButton(transform, out m_filterButton);
		((UnityEvent)m_filterButton.onClick).AddListener((UnityAction)delegate
		{
			m_hoard?.CycleFilter();
			UpdateLabels();
		});
		m_sortGo = CreateButton(transform, out m_sortButton);
		((UnityEvent)m_sortButton.onClick).AddListener((UnityAction)delegate
		{
			m_hoard?.CycleSort();
			UpdateLabels();
		});
	}

	private static GameObject CreateButton(Transform parent, out Button button)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = GUIManager.Instance.CreateButton(string.Empty, parent, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, 120f, 28f);
		button = val.GetComponent<Button>();
		Text componentInChildren = ((Component)button).GetComponentInChildren<Text>();
		if (Object.op_Implicit((Object)(object)componentInChildren))
		{
			componentInChildren.resizeTextForBestFit = false;
			componentInChildren.fontSize = 14;
			componentInChildren.alignment = (TextAnchor)4;
			componentInChildren.horizontalOverflow = (HorizontalWrapMode)1;
		}
		return val;
	}

	private void Dock()
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: 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_0042: 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_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: 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)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: 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_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: 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_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		InventoryGui instance = InventoryGui.instance;
		if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance.m_container))
		{
			return;
		}
		RectTransform container = instance.m_container;
		RectTransform val = (RectTransform)((Component)this).transform;
		((Transform)val).SetParent((Transform)(object)container, false);
		val.anchorMin = Vector2.zero;
		val.anchorMax = Vector2.one;
		val.offsetMin = Vector2.zero;
		val.offsetMax = Vector2.zero;
		((Transform)val).SetAsLastSibling();
		Rect val2 = LocalRect((!Object.op_Implicit((Object)(object)instance.m_takeAllButton)) ? ((RectTransform)null) : ((RectTransform)((Component)instance.m_takeAllButton).transform), container);
		Rect rect = container.rect;
		float xMin = ((Rect)(ref rect)).xMin;
		rect = container.rect;
		float xMax = ((Rect)(ref rect)).xMax;
		float num;
		if (!(((Rect)(ref val2)).height > 1f))
		{
			rect = container.rect;
			num = ((Rect)(ref rect)).yMax - 34f;
		}
		else
		{
			num = ((Rect)(ref val2)).center.y;
		}
		float centreY = num;
		float num2 = xMax - xMin - 40f;
		MimirsWellPlugin.Log.LogDebug((object)$"Well window title row: {num2:0} px between the vanilla buttons");
		if (num2 < 90f)
		{
			m_searchGo.SetActive(false);
			m_sortGo.SetActive(false);
			m_filterGo.SetActive(false);
			return;
		}
		float num3 = Mathf.Clamp(num2 * 0.27f, 90f, 140f);
		bool flag = num2 >= 90f + num3 * 2f + 20f;
		float num4 = num2 - (flag ? (num3 * 2f + 20f) : (num3 + 10f));
		Rect rect2 = container.rect;
		float num5 = xMin + 20f;
		Place(m_searchGo, rect2, num5, centreY, num4);
		num5 += num4 + 10f;
		if (flag)
		{
			Place(m_sortGo, rect2, num5, centreY, num3);
			num5 += num3 + 10f;
		}
		else
		{
			m_sortGo.SetActive(false);
		}
		Place(m_filterGo, rect2, num5, centreY, num3);
		ScrollToTop(instance);
	}

	private static void ScrollToTop(InventoryGui gui)
	{
		object? obj = ContainerGridField?.GetValue(gui);
		InventoryGrid val = (InventoryGrid)((obj is InventoryGrid) ? obj : null);
		if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.m_scrollbar))
		{
			val.m_scrollbar.value = 1f;
		}
	}

	private static void Place(GameObject go, Rect space, float x, float centreY, float width)
	{
		//IL_000e: 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_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: 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)
		go.SetActive(true);
		RectTransform component = go.GetComponent<RectTransform>();
		component.anchorMin = Vector2.zero;
		component.anchorMax = Vector2.zero;
		component.pivot = new Vector2(0f, 0.5f);
		component.sizeDelta = new Vector2(width, 28f);
		component.anchoredPosition = new Vector2(x - ((Rect)(ref space)).xMin, centreY - ((Rect)(ref space)).yMin);
	}

	private static Rect LocalRect(RectTransform target, RectTransform space)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: 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_0039: 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_0043: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: 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_006a: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)target) || !Object.op_Implicit((Object)(object)space))
		{
			return default(Rect);
		}
		Vector3[] array = (Vector3[])(object)new Vector3[4];
		target.GetWorldCorners(array);
		Vector3 val = ((Transform)space).InverseTransformPoint(array[0]);
		Vector3 val2 = ((Transform)space).InverseTransformPoint(array[2]);
		return new Rect(val.x, val.y, val2.x - val.x, val2.y - val.y);
	}

	private void Undock()
	{
		if (Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront))
		{
			((Component)this).transform.SetParent(GUIManager.CustomGUIFront.transform, false);
		}
	}

	private void Update()
	{
		if (!Object.op_Implicit((Object)(object)m_hoard) || !m_hoard.IsOpen)
		{
			Hide();
			return;
		}
		bool flag = Object.op_Implicit((Object)(object)m_search) && m_search.isFocused;
		if (flag != m_searchFocused)
		{
			SetSearchFocus(flag);
		}
	}

	private void OnDisable()
	{
		SetSearchFocus(focused: false);
	}

	private void SetSearchFocus(bool focused)
	{
		m_searchFocused = focused;
		GUIManager.BlockInput(focused);
	}

	private void UpdateLabels()
	{
		if (!((Object)(object)m_hoard == (Object)null))
		{
			Text val = (Object.op_Implicit((Object)(object)m_filterButton) ? ((Component)m_filterButton).GetComponentInChildren<Text>() : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				val.text = Localization.instance.Localize(FilterToken(m_hoard.Filter));
			}
			Text val2 = (Object.op_Implicit((Object)(object)m_sortButton) ? ((Component)m_sortButton).GetComponentInChildren<Text>() : null);
			if (Object.op_Implicit((Object)(object)val2))
			{
				val2.text = Localization.instance.Localize(SortToken(m_hoard.Sort));
			}
		}
	}

	private static string FilterToken(ItemFilter filter)
	{
		return filter switch
		{
			ItemFilter.Materials => "$mw_ui_materials", 
			ItemFilter.Food => "$mw_ui_food", 
			ItemFilter.Weapons => "$mw_ui_weapons", 
			ItemFilter.Armor => "$mw_ui_armor", 
			ItemFilter.Tools => "$mw_ui_tools", 
			ItemFilter.Misc => "$mw_ui_misc", 
			_ => "$mw_ui_all", 
		};
	}

	private static string SortToken(SortMode sort)
	{
		return sort switch
		{
			SortMode.Amount => "$mw_ui_sort_amount", 
			SortMode.Weight => "$mw_ui_sort_weight", 
			_ => "$mw_ui_sort_name", 
		};
	}
}
[BepInPlugin("benka.MimirsWell", "Mimir's Well", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[SynchronizationMode(/*Could not decode attribute arguments.*/)]
internal class MimirsWellPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "benka.MimirsWell";

	public const string PluginName = "Mimir's Well";

	public const string PluginVersion = "1.0.0";

	public const string PieceCategory = "Mimir";

	public const string PieceTable = "Hammer";

	internal static MimirsWellPlugin Instance;

	internal static ManualLogSource Log;

	internal static ConfigEntry<float> NetworkRadius;

	internal static ConfigEntry<bool> RuneGlow;

	internal static ConfigEntry<int> HoardWidth;

	internal static ConfigEntry<int> HoardRows;

	private void Awake()
	{
		//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_004f: Expected O, but got Unknown
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Expected O, but got Unknown
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Expected O, but got Unknown
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Expected O, but got Unknown
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		NetworkRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Network", "Radius", 20f, new ConfigDescription("Range in meters within which rune chests are bound to Mímir's Well. Chests further away than the loaded area cannot be reached anyway.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 40f), new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		HoardWidth = ((BaseUnityPlugin)this).Config.Bind<int>("Window", "Columns", 8, new ConfigDescription("Slots per row in the well window.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(4, 12), Array.Empty<object>()));
		HoardRows = ((BaseUnityPlugin)this).Config.Bind<int>("Window", "MaxRows", 10, new ConfigDescription("Most rows the well window may grow to. Stacks beyond that stay in their chests and are counted in the title.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 16), Array.Empty<object>()));
		RuneGlow = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "RuneGlow", true, "Rune chests glow softly while bound to a well.");
		Translations.Register();
		PrefabManager.OnVanillaPrefabsAvailable += AddPieces;
		new Harmony("benka.MimirsWell").PatchAll();
		Log.LogInfo((object)"Mimir's Well 1.0.0 loaded");
	}

	private void AddPieces()
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			PieceManager.Instance.AddPieceCategory("Mimir");
			AddWell();
			AddRuneChest("MW_RuneChest_Wood", "piece_chest_wood", "$mw_runechest_wood", "$mw_runechest_wood_desc", "piece_workbench", (RequirementConfig[])(object)new RequirementConfig[3]
			{
				Req("Wood", 10),
				Req("FineWood", 4),
				Req("GreydwarfEye", 2)
			});
			AddRuneChest("MW_RuneChest_Iron", "piece_chest", "$mw_runechest_iron", "$mw_runechest_iron_desc", "piece_workbench", (RequirementConfig[])(object)new RequirementConfig[3]
			{
				Req("FineWood", 10),
				Req("Iron", 2),
				Req("ElderBark", 4)
			});
			AddRuneChest("MW_RuneChest_Blackmetal", "piece_chest_blackmetal", "$mw_runechest_blackmetal", "$mw_runechest_blackmetal_desc", "forge", (RequirementConfig[])(object)new RequirementConfig[4]
			{
				Req("BlackMetal", 6),
				Req("FineWood", 10),
				Req("Tar", 2),
				Req("SurtlingCore", 1)
			});
			AddChisel();
		}
		finally
		{
			PrefabManager.OnVanillaPrefabsAvailable -= AddPieces;
		}
	}

	private void AddChisel()
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Expected O, but got Unknown
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Expected O, but got Unknown
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = PrefabManager.Instance.CreateClonedPrefab("MW_RuneChisel", "Hammer");
		if (!Object.op_Implicit((Object)(object)val))
		{
			Log.LogError((object)"Could not clone Hammer, the rune chisel is not available");
			return;
		}
		ItemDrop component = val.GetComponent<ItemDrop>();
		if (Object.op_Implicit((Object)(object)component))
		{
			SharedData shared = component.m_itemData.m_shared;
			shared.m_name = "$mw_chisel";
			shared.m_description = "$mw_chisel_desc";
			shared.m_itemType = (ItemType)19;
			shared.m_maxStackSize = 1;
			shared.m_useDurability = false;
			shared.m_buildPieces = null;
		}
		ItemManager instance = ItemManager.Instance;
		ItemConfig val2 = new ItemConfig();
		val2.Name = "$mw_chisel";
		val2.Description = "$mw_chisel_desc";
		val2.Amount = 1;
		val2.CraftingStation = "piece_workbench";
		val2.Icon = RenderIcon(val);
		val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[4]
		{
			Req("FineWood", 10),
			Req("Bronze", 3),
			Req("GreydwarfEye", 10),
			Req("SurtlingCore", 1)
		};
		bool flag = instance.AddItem(new CustomItem(val, false, val2));
		Log.LogDebug((object)$"Rune chisel registered: {flag}, prefab '{((Object)val).name}', item name '{component?.m_itemData.m_shared.m_name}'");
	}

	private static Sprite RenderIcon(GameObject prefab)
	{
		//IL_0006: 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_000c: 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_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		try
		{
			return RenderManager.Instance.Render(new RenderRequest(prefab)
			{
				Rotation = RenderManager.IsometricRotation,
				UseCache = true,
				TargetPlugin = ((BaseUnityPlugin)Instance).Info.Metadata
			});
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not render an icon for " + ((Object)prefab).name + ": " + ex.Message));
			return null;
		}
	}

	private static Sprite ChestBackground()
	{
		GameObject prefab = PrefabManager.Instance.GetPrefab("piece_chest_wood");
		Container val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Container>() : null);
		if (!Object.op_Implicit((Object)(object)val))
		{
			return null;
		}
		return val.m_bkg;
	}

	private static RequirementConfig Req(string item, int amount)
	{
		//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_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		return new RequirementConfig
		{
			Item = item,
			Amount = amount,
			Recover = true
		};
	}

	private void AddWell()
	{
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Expected O, but got Unknown
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Expected O, but got Unknown
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Expected O, but got Unknown
		GameObject val = PrefabManager.Instance.CreateClonedPrefab("MW_MimirsWell", "guard_stone");
		if (!Object.op_Implicit((Object)(object)val))
		{
			Log.LogError((object)"Could not clone guard_stone, Mímir's Well is not available");
			return;
		}
		MimirsWellStation mimirsWellStation = val.AddComponent<MimirsWellStation>();
		PrivateArea component = val.GetComponent<PrivateArea>();
		float hoverOffset = 1f;
		MeshRenderer val2 = null;
		if (Object.op_Implicit((Object)(object)component))
		{
			mimirsWellStation.m_areaMarker = component.m_areaMarker;
			val2 = component.m_model;
			hoverOffset = component.m_hoverOffset;
			if (Object.op_Implicit((Object)(object)component.m_enabledEffect))
			{
				Object.DestroyImmediate((Object)(object)component.m_enabledEffect);
			}
			Object.DestroyImmediate((Object)(object)component);
		}
		WellModel.Apply(val, val2);
		mimirsWellStation.m_model = val2;
		Container obj = val.AddComponent<Container>();
		obj.m_name = "$mw_well_name";
		obj.m_width = HoardWidth.Value;
		obj.m_height = HoardRows.Value;
		obj.m_privacy = (PrivacySetting)2;
		obj.m_checkGuardStone = true;
		obj.m_autoDestroyEmpty = false;
		obj.m_defaultItems = new DropTable();
		obj.m_hoverOffset = hoverOffset;
		obj.m_bkg = ChestBackground();
		val.AddComponent<HoardContainer>();
		PieceManager instance = PieceManager.Instance;
		PieceConfig val3 = new PieceConfig();
		val3.Name = "$mw_well_name";
		val3.Description = "$mw_well_desc";
		val3.PieceTable = "Hammer";
		val3.Category = "Mimir";
		val3.Icon = RenderIcon(val);
		val3.CraftingStation = "piece_workbench";
		val3.Requirements = (RequirementConfig[])(object)new RequirementConfig[4]
		{
			Req("Stone", 20),
			Req("FineWood", 10),
			Req("GreydwarfEye", 10),
			Req("SurtlingCore", 2)
		};
		instance.AddPiece(new CustomPiece(val, false, val3));
	}

	private void AddRuneChest(string name, string basePrefab, string displayName, string description, string station, RequirementConfig[] requirements)
	{
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: 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_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Expected O, but got Unknown
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Expected O, but got Unknown
		GameObject val = PrefabManager.Instance.CreateClonedPrefab(name, basePrefab);
		if (!Object.op_Implicit((Object)(object)val))
		{
			Log.LogError((object)("Could not clone " + basePrefab + ", " + name + " is not available"));
			return;
		}
		Container component = val.GetComponent<Container>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.m_name = displayName;
		}
		val.AddComponent<RuneChest>();
		PieceManager.Instance.AddPiece(new CustomPiece(val, false, new PieceConfig
		{
			Name = displayName,
			Description = description,
			PieceTable = "Hammer",
			Category = "Mimir",
			Icon = RenderIcon(val),
			CraftingStation = station,
			Requirements = requirements
		}));
	}
}
public class MimirsWellStation : MonoBehaviour
{
	internal static readonly List<MimirsWellStation> All = new List<MimirsWellStation>();

	public GameObject m_glow;

	public CircleProjector m_areaMarker;

	public MeshRenderer m_model;

	private ZNetView m_nview;

	public static float Radius => MimirsWellPlugin.NetworkRadius.Value;

	private void Awake()
	{
		m_nview = ((Component)this).GetComponent<ZNetView>();
		if (Object.op_Implicit((Object)(object)m_nview) && m_nview.GetZDO() != null)
		{
			All.Add(this);
			if (Object.op_Implicit((Object)(object)m_areaMarker))
			{
				m_areaMarker.m_radius = Radius;
				((Component)m_areaMarker).gameObject.SetActive(false);
			}
			((MonoBehaviour)this).InvokeRepeating("UpdateAreaMarker", 0.2f, 0.2f);
		}
	}

	private void OnDestroy()
	{
		All.Remove(this);
	}

	private void UpdateAreaMarker()
	{
		if (Object.op_Implicit((Object)(object)m_areaMarker))
		{
			bool flag = false;
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer))
			{
				GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
				flag = Object.op_Implicit((Object)(object)hoverObject) && (Object)(object)hoverObject.GetComponentInParent<MimirsWellStation>() == (Object)(object)this;
			}
			if (flag)
			{
				m_areaMarker.m_radius = Radius;
			}
			if (((Component)m_areaMarker).gameObject.activeSelf != flag)
			{
				((Component)m_areaMarker).gameObject.SetActive(flag);
			}
		}
	}

	internal List<RuneChest> GetChestsInRange()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: 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_0058: Unknown result type (might be due to invalid IL or missing references)
		float num = Radius * Radius;
		Vector3 position = ((Component)this).transform.position;
		List<RuneChest> list = new List<RuneChest>();
		foreach (RuneChest item in RuneChest.All)
		{
			if (Object.op_Implicit((Object)(object)item) && item.IsUsable)
			{
				Vector3 val = ((Component)item).transform.position - position;
				if (((Vector3)(ref val)).sqrMagnitude <= num)
				{
					list.Add(item);
				}
			}
		}
		return list;
	}

	internal static MimirsWellStation FindWellFor(Vector3 position)
	{
		//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_0040: 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)
		MimirsWellStation result = null;
		float num = float.MaxValue;
		float num2 = Radius * Radius;
		foreach (MimirsWellStation item in All)
		{
			if (Object.op_Implicit((Object)(object)item))
			{
				Vector3 val = ((Component)item).transform.position - position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude <= num2 && sqrMagnitude < num)
				{
					result = item;
					num = sqrMagnitude;
				}
			}
		}
		return result;
	}
}
internal static class ObjLoader
{
	private static readonly char[] Space = new char[2] { ' ', '\t' };

	public static Mesh Load(string path, out List<string> groups)
	{
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Expected O, but got Unknown
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		groups = new List<string>();
		List<Vector3> list = new List<Vector3>();
		List<Vector3> list2 = new List<Vector3>();
		List<Vector2> list3 = new List<Vector2>();
		List<Vector3> list4 = new List<Vector3>();
		List<Vector3> list5 = new List<Vector3>();
		List<Vector2> list6 = new List<Vector2>();
		Dictionary<string, int> lookup = new Dictionary<string, int>();
		List<List<int>> list7 = new List<List<int>>();
		List<int> list8 = null;
		foreach (string item in File.ReadLines(path))
		{
			string text = item.Trim();
			if (text.Length == 0 || text[0] == '#')
			{
				continue;
			}
			string[] array = text.Split(Space, StringSplitOptions.RemoveEmptyEntries);
			switch (array[0])
			{
			case "v":
				list.Add(new Vector3(0f - Float(array[1]), Float(array[2]), Float(array[3])));
				break;
			case "vn":
				list2.Add(new Vector3(0f - Float(array[1]), Float(array[2]), Float(array[3])));
				break;
			case "vt":
				list3.Add(new Vector2(Float(array[1]), (array.Length > 2) ? Float(array[2]) : 0f));
				break;
			case "usemtl":
				groups.Add((array.Length > 1) ? array[1] : "default");
				list8 = new List<int>();
				list7.Add(list8);
				break;
			case "f":
				if (list8 == null)
				{
					groups.Add("default");
					list8 = new List<int>();
					list7.Add(list8);
				}
				AddFace(array, list, list2, list3, list4, list5, list6, lookup, list8);
				break;
			}
		}
		Mesh val = new Mesh
		{
			name = Path.GetFileNameWithoutExtension(path)
		};
		if (list4.Count > 65000)
		{
			val.indexFormat = (IndexFormat)1;
		}
		val.SetVertices(list4);
		if (list6.Count == list4.Count)
		{
			val.SetUVs(0, list6);
		}
		val.subMeshCount = list7.Count;
		for (int i = 0; i < list7.Count; i++)
		{
			val.SetTriangles(list7[i], i);
		}
		if (list5.Count == list4.Count)
		{
			val.SetNormals(list5);
		}
		else
		{
			val.RecalculateNormals();
		}
		val.RecalculateTangents();
		val.RecalculateBounds();
		return val;
	}

	private static void AddFace(string[] parts, List<Vector3> positions, List<Vector3> normals, List<Vector2> uvs, List<Vector3> vertices, List<Vector3> vertexNormals, List<Vector2> vertexUvs, Dictionary<string, int> lookup, List<int> triangles)
	{
		//IL_0052: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
		List<int> list = new List<int>(parts.Length - 1);
		for (int i = 1; i < parts.Length; i++)
		{
			string text = parts[i];
			if (!lookup.TryGetValue(text, out var value))
			{
				string[] array = text.Split(new char[1] { '/' });
				value = vertices.Count;
				vertices.Add(positions[Index(array[0], positions.Count)]);
				if (array.Length > 1 && array[1].Length > 0 && uvs.Count > 0)
				{
					vertexUvs.Add(uvs[Index(array[1], uvs.Count)]);
				}
				if (array.Length > 2 && array[2].Length > 0 && normals.Count > 0)
				{
					vertexNormals.Add(normals[Index(array[2], normals.Count)]);
				}
				lookup[text] = value;
			}
			list.Add(value);
		}
		for (int j = 1; j < list.Count - 1; j++)
		{
			triangles.Add(list[0]);
			triangles.Add(list[j + 1]);
			triangles.Add(list[j]);
		}
	}

	private static int Index(string value, int count)
	{
		int num = int.Parse(value, CultureInfo.InvariantCulture);
		if (num <= 0)
		{
			return count + num;
		}
		return num - 1;
	}

	private static float Float(string value)
	{
		return float.Parse(value, CultureInfo.InvariantCulture);
	}
}
[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
internal static class InventoryGridAmountPatch
{
	private static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements");

	private static void Postfix(InventoryGrid __instance)
	{
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		Inventory inventory = __instance.GetInventory();
		if (!HoardContainer.IsMirror(inventory) || !(ElementsField?.GetValue(__instance) is IEnumerable enumerable))
		{
			return;
		}
		foreach (object item in enumerable)
		{
			InventoryElement val = (InventoryElement)((item is InventoryElement) ? item : null);
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.m_amount) && ((Behaviour)val.m_amount).enabled)
			{
				ItemData val2 = ItemAt(inventory, val.Position);
				if (val2 != null)
				{
					val.m_amount.text = val2.m_stack.ToString();
				}
			}
		}
	}

	private static ItemData ItemAt(Inventory inventory, Vector2i position)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		foreach (ItemData allItem in inventory.GetAllItems())
		{
			if (allItem.m_gridPos == position)
			{
				return allItem;
			}
		}
		return null;
	}
}
[HarmonyPatch(typeof(Hud), "Awake")]
internal static class HudAwakePatch
{
	private static void Postfix(Hud __instance)
	{
		GameObject prefab = PrefabManager.Instance.GetPrefab("MW_MimirsWell");
		Piece val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Piece>() : null);
		int num = ((__instance.m_pieceCategoryTabs != null) ? __instance.m_pieceCategoryTabs.Length : (-1));
		MimirsWellPlugin.Log.LogDebug((object)string.Format("Build menu has {0} category tabs, the well sits in category {1}", num, Object.op_Implicit((Object)(object)val) ? ((object)Unsafe.As<PieceCategory, PieceCategory>(ref val.m_category)/*cast due to .constrained prefix*/).ToString() : "unknown"));
	}
}
[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
{
	typeof(Inventory),
	typeof(ItemData),
	typeof(int),
	typeof(int),
	typeof(int)
})]
internal static class InventoryMoveItemToThisPatch
{
	private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item, int amount, int x, int y, ref bool __result)
	{
		if (!HoardContainer.IsMirror(__instance))
		{
			return true;
		}
		__result = HoardContainer.AcceptDrop(__instance, fromInventory, item, amount, x, y);
		if (!__result)
		{
			HoardContainer.ReportFull();
		}
		return false;
	}
}
[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
internal static class InventoryGuiSelectedItemPatch
{
	private static bool Prefix(InventoryGui __instance, InventoryGrid grid, Vector2i pos)
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)grid) || !HoardContainer.IsMirror(grid.GetInventory()))
		{
			return true;
		}
		ItemData val = HoardContainer.DragItem(__instance);
		Inventory val2 = HoardContainer.DragInventory(__instance);
		if (val == null || val2 == null || HoardContainer.IsMirror(val2))
		{
			return true;
		}
		int amount = HoardContainer.DragAmount(__instance);
		if (HoardContainer.AcceptDrop(grid.GetInventory(), val2, val, amount, pos.x, pos.y))
		{
			HoardContainer.ClearDrag(__instance);
			return false;
		}
		HoardContainer.ReportFull();
		return false;
	}
}
[HarmonyPatch(typeof(InventoryGui), "SetupDragItem")]
internal static class InventoryGuiSetupDragItemPatch
{
	private static void Prefix(ItemData item, Inventory inventory, ref int amount)
	{
		if (item != null && HoardContainer.IsMirror(inventory))
		{
			amount = Mathf.Min(amount, Mathf.Max(1, item.m_shared.m_maxStackSize));
		}
	}
}
[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
internal static class InventoryGuiUpdateContainerPatch
{
	private static bool s_hidden;

	private static void Postfix(InventoryGui __instance)
	{
		if (HoardContainer.AnyOpen)
		{
			if (Object.op_Implicit((Object)(object)__instance.m_containerName))
			{
				((Behaviour)__instance.m_containerName).enabled = false;
			}
			SetActive(__instance.m_takeAllButton, active: false);
			SetActive(__instance.m_stackAllButton, active: false);
			s_hidden = true;
		}
	}

	internal static void Restore(InventoryGui gui)
	{
		if (s_hidden && Object.op_Implicit((Object)(object)gui))
		{
			s_hidden = false;
			if (Object.op_Implicit((Object)(object)gui.m_containerName))
			{
				((Behaviour)gui.m_containerName).enabled = true;
			}
			SetActive(gui.m_takeAllButton, active: true);
			SetActive(gui.m_stackAllButton, active: true);
		}
	}

	private static void SetActive(Button button, bool active)
	{
		if (Object.op_Implicit((Object)(object)button) && ((Component)button).gameObject.activeSelf != active)
		{
			((Component)button).gameObject.SetActive(active);
		}
	}
}
[HarmonyPatch(typeof(InventoryGui), "UpdateContainerWeight")]
internal static class InventoryGuiContainerWeightPatch
{
	private static void Postfix(InventoryGui __instance)
	{
		if (!Object.op_Implicit((Object)(object)__instance.m_containerWeight))
		{
			return;
		}
		Transform parent = __instance.m_containerWeight.transform.parent;
		if (Object.op_Implicit((Object)(object)parent))
		{
			bool flag = !HoardContainer.AnyOpen;
			if (((Component)parent).gameObject.activeSelf != flag)
			{
				((Component)parent).gameObject.SetActive(flag);
			}
		}
	}
}
[HarmonyPatch(typeof(InventoryGui), "Show")]
internal static class InventoryGuiShowPatch
{
	private static void Prefix(InventoryGui __instance, Container container)
	{
		HoardContainer hoardContainer = (Object.op_Implicit((Object)(object)container) ? ((Component)container).GetComponent<HoardContainer>() : null);
		if (Object.op_Implicit((Object)(object)hoardContainer))
		{
			hoardContainer.BeginSession();
		}
		else
		{
			InventoryGuiUpdateContainerPatch.Restore(__instance);
		}
	}
}
[HarmonyPatch(typeof(InventoryGui), "Hide")]
internal static class InventoryGuiHidePatch
{
	private static void Postfix()
	{
		HoardContainer.CloseAll();
	}
}
[HarmonyPatch(typeof(Container), "Save")]
internal static class ContainerSavePatch
{
	private static bool Prefix(Container __instance)
	{
		return !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<HoardContainer>());
	}
}
[HarmonyPatch(typeof(Container), "AddDefaultItems")]
internal static class ContainerAddDefaultItemsPatch
{
	private static bool Prefix(Container __instance)
	{
		return !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<HoardContainer>());
	}
}
[HarmonyPatch(typeof(Container), "Load")]
internal static class ContainerLoadPatch
{
	private static bool Prefix(Container __instance, ref bool __result)
	{
		if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<HoardContainer>()))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Container), "GetHoverText")]
internal static class ContainerHoverTextPatch
{
	private static void Postfix(Container __instance, ref string __result)
	{
		MimirsWellStation component = ((Component)__instance).GetComponent<MimirsWellStation>();
		if (Object.op_Implicit((Object)(object)component))
		{
			__result += Localization.instance.Localize($"\n<color=#8fc7ff>$mw_well_bound: {component.GetChestsInRange().Count}</color>");
			return;
		}
		RuneChest component2 = ((Component)__instance).GetComponent<RuneChest>();
		if (!Object.op_Implicit((Object)(object)component2))
		{
			__result += ChestUpgrade.HoverText(__instance);
			return;
		}
		long playerID = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Player.m_localPlayer.GetPlayerID() : 0);
		if (RuneChest.IsLockedByOther(__instance, playerID))
		{
			__result += Localization.instance.Localize("\n<color=#d08a8a>$mw_chest_busy</color>");
			return;
		}
		__result += (component2.IsLinked ? Localization.instance.Localize("\n<color=#8fc7ff>$mw_chest_linked</color>") : Localization.instance.Localize("\n<color=#9a8f80>$mw_chest_unlinked</color>"));
		__result += ChestUpgrade.HoverText(__instance);
	}
}
[HarmonyPatch(typeof(Container), "Interact")]
internal static class ContainerInteractPatch
{
	private static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt, ref bool __result)
	{
		if (!hold && (Object)(object)character == (Object)(object)Player.m_localPlayer && ChestUpgrade.Find(__instance) != null)
		{
			ChestUpgrade.LogState(__instance);
			if (ChestUpgrade.WieldsChisel())
			{
				__result = ChestUpgrade.Upgrade(__instance);
				return false;
			}
		}
		if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<RuneChest>()))
		{
			return true;
		}
		long playerID = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Player.m_localPlayer.GetPlayerID() : 0);
		if (!RuneChest.IsLockedByOther(__instance, playerID))
		{
			return true;
		}
		if ((Object)(object)character == (Object)(object)Player.m_localPlayer && Object.op_Implicit((Object)(object)Player.m_localPlayer))
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$mw_chest_busy"), 0, (Sprite)null, false);
		}
		__result = true;
		return false;
	}
}
[HarmonyPatch(typeof(Container), "RPC_RequestOpen")]
internal static class ContainerRequestOpenPatch
{
	private static bool Prefix(Container __instance, long playerID)
	{
		return !RuneChest.IsLockedByOther(__instance, playerID);
	}
}
[HarmonyPatch(typeof(Container), "RPC_RequestStack")]
internal static class ContainerRequestStackPatch
{
	private static bool Prefix(Container __instance, long playerID)
	{
		return !RuneChest.IsLockedByOther(__instance, playerID);
	}
}
[HarmonyPatch(typeof(Container), "RPC_RequestTakeAll")]
internal static class ContainerRequestTakeAllPatch
{
	private static bool Prefix(Container __instance, long playerID)
	{
		return !RuneChest.IsLockedByOther(__instance, playerID);
	}
}
public class RuneChest : MonoBehaviour
{
	internal static readonly List<RuneChest> All = new List<RuneChest>();

	private const string LockOwnerKey = "MW_lockBy";

	private const string LockTimeKey = "MW_lockAt";

	private const double LockTimeout = 15.0;

	private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null);

	internal Container Container;

	private ZNetView m_nview;

	private Light m_glow;

	private bool m_linked;

	private bool m_awaitingOwnership;

	private float m_awaitingUntil;

	internal bool IsLocked { get; private set; }

	internal bool IsLinked => m_linked;

	internal Inventory Inventory
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)Container))
			{
				return null;
			}
			return Container.GetInventory();
		}
	}

	internal bool IsUsable
	{
		get
		{
			if (Object.op_Implicit((Object)(object)this) && Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid() && Object.op_Implicit((Object)(object)Container))
			{
				return Container.GetInventory() != null;
			}
			return false;
		}
	}

	private static double NetTime
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return 0.0;
			}
			return ZNet.instance.GetTimeSeconds();
		}
	}

	private static long LocalPlayerID
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return 0L;
			}
			return Player.m_localPlayer.GetPlayerID();
		}
	}

	private void Awake()
	{
		m_nview = ((Component)this).GetComponent<ZNetView>();
		Container = ((Component)this).GetComponent<Container>();
		if (Object.op_Implicit((Object)(object)m_nview) && m_nview.GetZDO() != null && Object.op_Implicit((Object)(object)Container))
		{
			m_nview.Register<long>("MW_RequestLock", (Action<long, long>)RPC_RequestLock);
			m_nview.Register<bool>("MW_LockResponse", (Action<long, bool>)RPC_LockResponse);
			All.Add(this);
			CreateGlow();
			((MonoBehaviour)this).InvokeRepeating("UpdateLink", Random.Range(0.4f, 1.4f), 1f);
		}
	}

	private void OnDestroy()
	{
		All.Remove(this);
		StorageSession.Current?.OnChestLost(this);
	}

	private void CreateGlow()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_003f: 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)
		if (MimirsWellPlugin.RuneGlow.Value)
		{
			GameObject val = new GameObject("MW_RuneGlow");
			val.transform.SetParent(((Component)this).transform, false);
			val.transform.localPosition = new Vector3(0f, 0.6f, 0f);
			m_glow = val.AddComponent<Light>();
			m_glow.type = (LightType)2;
			m_glow.color = new Color(0.45f, 0.72f, 1f);
			m_glow.range = 2.2f;
			m_glow.intensity = 0f;
			m_glow.shadows = (LightShadows)0;
		}
	}

	private void UpdateLink()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		m_linked = (Object)(object)MimirsWellStation.FindWellFor(((Component)this).transform.position) != (Object)null;
		UpdateGlow();
	}

	private void UpdateGlow()
	{
		if (Object.op_Implicit((Object)(object)m_glow))
		{
			m_glow.intensity = ((!m_linked) ? 0f : (IsLocked ? 1.3f : 0.45f));
		}
	}

	internal bool IsAccessible()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)Container) || !Container.m_checkGuardStone)
		{
			return true;
		}
		return PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false);
	}

	internal void RequestLock()
	{
		StorageSession current = StorageSession.Current;
		if (!IsUsable || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
		{
			current?.OnLockResult(this, granted: false);
		}
		else if (m_nview.IsOwner())
		{
			if (Container.IsInUse() || IsLockedByOther(Container, LocalPlayerID))
			{
				current?.OnLockResult(this, granted: false);
				return;
			}
			Lock();
			current?.OnLockResult(this, granted: true);
		}
		else
		{
			m_awaitingOwnership = false;
			m_nview.InvokeRPC("MW_RequestLock", new object[1] { Player.m_localPlayer.GetPlayerID() });
		}
	}

	private void RPC_RequestLock(long sender, long playerID)
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		if (m_nview.IsOwner())
		{
			bool flag = !Container.IsInUse() && !IsLockedByOther(Container, playerID) && HasAccess(playerID);
			if (flag)
			{
				ZDO zDO = m_nview.GetZDO();
				ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid);
				zDO.SetOwner(sender);
			}
			m_nview.InvokeRPC(sender, "MW_LockResponse", new object[1] { flag });
		}
	}

	private void RPC_LockResponse(long sender, bool granted)
	{
		StorageSession current = StorageSession.Current;
		if (current != null && current.IsPending(this))
		{
			if (!granted)
			{
				current.OnLockResult(this, granted: false);
			}
			else if (m_nview.IsOwner())
			{
				Lock();
				current.OnLockResult(this, granted: true);
			}
			else
			{
				m_awaitingOwnership = true;
				m_awaitingUntil = Time.time + 2f;
			}
		}
	}

	private void Update()
	{
		if (m_awaitingOwnership)
		{
			StorageSession current = StorageSession.Current;
			if (current == null || !current.IsPending(this))
			{
				m_awaitingOwnership = false;
			}
			else if (IsUsable && m_nview.IsOwner())
			{
				m_awaitingOwnership = false;
				Lock();
				current.OnLockResult(this, granted: true);
			}
			else if (Time.time > m_awaitingUntil)
			{
				m_awaitingOwnership = false;
				current.OnLockResult(this, granted: false);
			}
		}
	}

	private void Lock()
	{
		IsLocked = true;
		WriteLock(LocalPlayerID);
		UpdateGlow();
	}

	internal void Unlock()
	{
		IsLocked = false;
		if (IsUsable && m_nview.IsOwner())
		{
			WriteLock(0L);
		}
		UpdateGlow();
	}

	internal void RefreshLock()
	{
		if (IsLocked && IsUsable && m_nview.IsOwner())
		{
			WriteLock(LocalPlayerID);
		}
	}

	private void WriteLock(long playerID)
	{
		ZDO zDO = m_nview.GetZDO();
		if (zDO != null)
		{
			zDO.Set("MW_lockBy", playerID);
			zDO.Set("MW_lockAt", (playerID == 0L) ? 0 : ((long)NetTime));
		}
	}

	internal static bool IsLockedByOther(Container container, long playerID)
	{
		if (!Object.op_Implicit((Object)(object)container))
		{
			return false;
		}
		ZNetView component = ((Component)container).GetComponent<ZNetView>();
		ZDO val = ((Object.op_Implicit((Object)(object)component) && component.IsValid()) ? component.GetZDO() : null);
		if (val == null)
		{
			return false;
		}
		long num = val.GetLong("MW_lockBy", 0L);
		if (num == 0L || num == playerID)
		{
			return false;
		}
		return NetTime - (double)val.GetLong("MW_lockAt", 0L) < 15.0;
	}

	private bool HasAccess(long playerID)
	{
		if (CheckAccessMethod == null)
		{
			return true;
		}
		try
		{
			return (bool)CheckAccessMethod.Invoke(Container, new object[1] { playerID });
		}
		catch
		{
			return true;
		}
	}
}
internal class HoardEntry
{
	public string Key;

	public ItemData Sample;

	public int Total;
}
internal class StorageSession
{
	public readonly MimirsWellStation Well;

	private readonly List<RuneChest> m_locked = new List<RuneChest>();

	private readonly Dictionary<RuneChest, float> m_pending = new Dictionary<RuneChest, float>();

	private float m_nextHeartbeat;

	public static StorageSession Current { get; private set; }

	public int Denied { get; private set; }

	public bool Dirty { get; set; } = true;

	public int PendingCount => m_pending.Count;

	public List<RuneChest> Chests => m_locked;

	private StorageSession(MimirsWellStation well)
	{
		Well = well;
	}

	public static StorageSession Begin(MimirsWellStation well)
	{
		End();
		StorageSession storageSession = (Current = new StorageSession(well));
		foreach (RuneChest item in well.GetChestsInRange())
		{
			if (!item.IsAccessible())
			{
				storageSession.Denied++;
				continue;
			}
			storageSession.m_pending[item] = Time.time + 3f;
			item.RequestLock();
		}
		MimirsWellPlugin.Log.LogDebug((object)($"Well opened: {well.GetChestsInRange().Count} rune chests in range, " + $"{storageSession.m_locked.Count} bound, {storageSession.m_pending.Count} pending, {storageSession.Denied} denied " + $"(radius {MimirsWellStation.Radius}m, {RuneChest.All.Count} rune chests loaded)"));
		return storageSession;
	}

	public static void End()
	{
		StorageSession current = Current;
		Current = null;
		if (current == null)
		{
			return;
		}
		foreach (RuneChest item in current.m_locked)
		{
			if (Object.op_Implicit((Object)(object)item))
			{
				item.Unlock();
			}
		}
		current.m_locked.Clear();
		current.m_pending.Clear();
	}

	public bool IsPending(RuneChest chest)
	{
		return m_pending.ContainsKey(chest);
	}

	public void OnLockResult(RuneChest chest, bool granted)
	{
		if (m_pending.Remove(chest))
		{
			if (granted)
			{
				m_locked.Add(chest);
			}
			else
			{
				Denied++;
			}
			Dirty = true;
		}
	}

	public void OnChestLost(RuneChest chest)
	{
		m_pending.Remove(chest);
		if (m_locked.Remove(chest))
		{
			Dirty = true;
		}
	}

	public void Update()
	{
		if (m_pending.Count > 0)
		{
			List<RuneChest> list = null;
			foreach (KeyValuePair<RuneChest, float> item in m_pending)
			{
				if (Time.time > item.Value)
				{
					(list ?? (list = new List<RuneChest>())).Add(item.Key);
				}
			}
			if (list != null)
			{
				foreach (RuneChest item2 in list)
				{
					OnLockResult(item2, granted: false);
				}
			}
		}
		for (int num = m_locked.Count - 1; num >= 0; num--)
		{
			if (!Object.op_Implicit((Object)(object)m_locked[num]) || !m_locked[num].IsUsable)
			{
				m_locked.RemoveAt(num);
				Dirty = true;
			}
		}
		if (!(Time.time >= m_nextHeartbeat))
		{
			return;
		}
		m_nextHeartbeat = Time.time + 3f;
		foreach (RuneChest item3 in m_locked)
		{
			item3.RefreshLock();
		}
	}

	public int StoreIntoChests(ItemData item, int amount)
	{
		if (item == null || amount <= 0)
		{
			return 0;
		}
		List<RuneChest> list = new List<RuneChest>(m_locked);
		list.Sort((RuneChest a, RuneChest b) => Holds(b, item).CompareTo(Holds(a, item)));
		int num = 0;
		foreach (RuneChest item2 in list)
		{
			if (amount <= 0)
			{
				break;
			}
			if (!Object.op_Implicit((Object)(object)item2) || !item2.IsUsable || !item2.IsLocked)
			{
				continue;
			}
			Inventory inventory = item2.Inventory;
			if (inventory == null)
			{
				continue;
			}
			int num2 = FitAmount(inventory, item, amount);
			if (num2 > 0)
			{
				ItemData val = item.Clone();
				val.m_stack = num2;
				val.m_equipped = false;
				if (inventory.AddItem(val))
				{
					amount -= num2;
					num += num2;
				}
			}
		}
		if (num > 0)
		{
			Dirty = true;
		}
		return num;
	}

	public int CapacityFor(ItemData item, int amount)
	{
		if (item == null || amount <= 0)
		{
			return 0;
		}
		int num = 0;
		foreach (RuneChest item2 in m_locked)
		{
			if (num >= amount)
			{
				break;
			}
			if (Object.op_Implicit((Object)(object)item2) && item2.IsUsable && item2.IsLocked)
			{
				Inventory inventory = item2.Inventory;
				if (inventory != null)
				{
					num += FitAmount(inventory, item, amount - num);
				}
			}
		}
		return Mathf.Min(num, amount);
	}

	private static int Holds(RuneChest chest, ItemData item)
	{
		if (!Object.op_Implicit((Object)(object)chest))
		{
			return 0;
		}
		Inventory inventory = chest.Inventory;
		if (inventory == null)
		{
			return 0;
		}
		return (inventory.CountItems(item.m_shared.m_name, -1, false) > 0) ? 1 : 0;
	}

	private static int FitAmount(Inventory inventory, ItemData item, int want)
	{
		if (want <= 0)
		{
			return 0;
		}
		if (inventory.CanAddItem(item, want))
		{
			return want;
		}
		int num = 0;
		int num2 = want;
		while (num < num2)
		{
			int num3 = (num + num2 + 1) / 2;
			if (inventory.CanAddItem(item, num3))
			{
				num = num3;
			}
			else
			{
				num2 = num3 - 1;
			}
		}
		return num;
	}
}
internal static class Translations
{
	public static void Register()
	{
		CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
		string text = "English";
		localization.AddTranslation(ref text, new Dictionary<string, string>
		{
			{ "jotunn_cat_mimir", "Mímir" },
			{ "mw_well_name", "Mímir's Well" },
			{ "mw_well_desc", "A rune stone bound to the well of wisdom. Look into it to see everything stored in the rune chests around it." },
			{ "mw_well_use", "Look into the well" },
			{ "mw_well_bound", "Bound rune chests" },
			{ "mw_runechest_wood", "Rune chest" },
			{ "mw_runechest_wood_desc", "A wooden chest carved with binding runes. Mímir's Well can see into it." },
			{ "mw_runechest_iron", "Bound rune chest" },
			{ "mw_runechest_iron_desc", "An iron-bound chest carved with binding runes. Mímir's Well can see into it." },
			{ "mw_runechest_blackmetal", "Blackmetal rune chest" },
			{ "mw_runechest_blackmetal_desc", "A blackmetal chest carved with binding runes. Mímir's Well can see into it." },
			{ "mw_chisel", "Rune chisel" },
			{ "mw_chisel_desc", "Carved from fine wood and bronze, its edge knows the binding runes. Carry it and marking a chest costs nothing." },
			{ "mw_upgrade_to", "Carve into a" },
			{ "mw_upgrade_needs_chisel", "needs the rune chisel" },
			{ "mw_upgrade_hold_chisel", "hold the rune chisel" },
			{ "mw_upgrade_done", "The runes take hold" },
			{ "mw_upgrade_failed", "The chest does not answer" },
			{ "mw_chest_linked", "Bound to Mímir's Well" },
			{ "mw_chest_unlinked", "No well in reach, the runes are silent" },
			{ "mw_chest_busy", "Someone is looking into this chest" },
			{ "mw_ui_title", "Mímir's Well" },
			{ "mw_ui_search", "Search..." },
			{ "mw_ui_network", "Hoard" },
			{ "mw_ui_chests", "chests" },
			{ "mw_ui_slots", "slots" },
			{ "mw_ui_busy", "in use" },
			{ "mw_ui_waiting", "binding..." },
			{ "mw_ui_inventory", "Your inventory" },
			{ "mw_ui_all", "All" },
			{ "mw_ui_materials", "Materials" },
			{ "mw_ui_food", "Food" },
			{ "mw_ui_weapons", "Weapons" },
			{ "mw_ui_armor", "Armor" },
			{ "mw_ui_tools", "Tools" },
			{ "mw_ui_misc", "Other" },
			{ "mw_ui_sort_name", "Sort: Name" },
			{ "mw_ui_sort_amount", "Sort: Amount" },
			{ "mw_ui_sort_weight", "Sort: Weight" },
			{ "mw_ui_quickstack", "Sort in" },
			{ "mw_ui_storeall", "Store all" },
			{ "mw_ui_close", "Close" },
			{ "mw_ui_hint", "Left click: stack · Shift: all · Right click: one" },
			{ "mw_ui_empty", "The well is quiet. Build rune chests nearby." },
			{ "mw_ui_hidden", "more stacks" },
			{ "mw_ui_stacks", "stacks" },
			{ "mw_msg_full", "Your inventory is full" },
			{ "mw_msg_hoardfull", "The rune chests are full" },
			{ "mw_msg_dropped", "The rune chests are full, dropped at your feet" },
			{ "mw_msg_stored", "Stored" }
		});
		text = "German";
		localization.AddTranslation(ref text, new Dictionary<string, string>
		{
			{ "jotunn_cat_mimir", "Mímir" },
			{ "mw_well_name", "Mímirs Brunnen" },
			{ "mw_well_desc", "Ein Runenstein, gebunden an den Brunnen der Weisheit. Blick hinein und sieh alles, was in den Runentruhen ringsum lagert." },
			{ "mw_well_use", "In den Brunnen blicken" },
			{ "mw_well_bound", "Gebundene Runentruhen" },
			{ "mw_runechest_wood", "Runentruhe" },
			{ "mw_runechest_wood_desc", "Eine Holztruhe mit eingeritzten Bindungsrunen. Mímirs Brunnen kann hineinsehen." },
			{ "mw_runechest_iron", "Beschlagene Runentruhe" },
			{ "mw_runechest_iron_desc", "Eine eisenbeschlagene Truhe mit Bindungsrunen. Mímirs Brunnen kann hineinsehen." },
			{ "mw_runechest_blackmetal", "Schwarzmetall-Runentruhe" },
			{ "mw_runechest_blackmetal_desc", "Eine Schwarzmetalltruhe mit Bindungsrunen. Mímirs Brunnen kann hineinsehen." },
			{ "mw_chisel", "Runenmeißel" },
			{ "mw_chisel_desc", "Aus Feinholz und Bronze gefertigt, seine Schneide kennt die Bindungsrunen. Wer ihn trägt, zeichnet Truhen ohne Kosten." },
			{ "mw_upgrade_to", "Verwandeln in" },
			{ "mw_upgrade_needs_chisel", "braucht den Runenmeißel" },
			{ "mw_upgrade_hold_chisel", "Runenmeißel in die Hand nehmen" },
			{ "mw_upgrade_done", "Die Runen greifen" },
			{ "mw_upgrade_failed", "Die Truhe antwortet nicht" },
			{ "mw_chest_linked", "Gebunden an Mímirs Brunnen" },
			{ "mw_chest_unlinked", "Kein Brunnen in Reichweite, die Runen schweigen" },
			{ "mw_chest_busy", "Jemand blickt gerade in diese Truhe" },
			{ "mw_ui_title", "Mímirs Brunnen" },
			{ "mw_ui_search", "Suchen..." },
			{ "mw_ui_network", "Hort" },
			{ "mw_ui_chests", "Truhen" },
			{ "mw_ui_slots", "Plätze" },
			{ "mw_ui_busy", "belegt" },
			{ "mw_ui_waiting", "binde..." },
			{ "mw_ui_inventory", "Dein Inventar" },
			{ "mw_ui_all", "Alle" },
			{ "mw_ui_materials", "Material" },
			{ "mw_ui_food", "Nahrung" },
			{ "mw_ui_weapons", "Waffen" },
			{ "mw_ui_armor", "Rüstung" },
			{ "mw_ui_tools", "Werkzeug" },
			{ "mw_ui_misc", "Sonst." },
			{ "mw_ui_sort_name", "Sort.: Name" },
			{ "mw_ui_sort_amount", "Sort.: Anzahl" },
			{ "mw_ui_sort_weight", "Sort.: Gewicht" },
			{ "mw_ui_quickstack", "Einsortieren" },
			{ "mw_ui_storeall", "Alles einlagern" },
			{ "mw_ui_close", "Schließen" },
			{ "mw_ui_hint", "Linksklick: Stapel · Shift: alles · Rechtsklick: eins" },
			{ "mw_ui_empty", "Der Brunnen ist still. Baue Runentruhen in der Nähe." },
			{ "mw_ui_hidden", "weitere Stapel" },
			{ "mw_ui_stacks", "Stapel" },
			{ "mw_msg_full", "Dein Inventar ist voll" },
			{ "mw_msg_hoardfull", "Die Runentruhen sind voll" },
			{ "mw_msg_dropped", "Runentruhen voll, vor deinen Füßen abgelegt" },
			{ "mw_msg_stored", "Eingelagert" }
		});
	}
}
internal static class WellModel
{
	private const string ModelFile = "MimirsWell.obj";

	private static readonly string[] StoneDonors = new string[4] { "blackmarble_post01", "piece_blackmarble_wall_2x2", "guard_stone", "piece_stonecutter" };

	private static readonly string[] MetalDonors = new string[4] { "piece_chest_blackmetal", "forge", "piece_artisanstation", "piece_cartographytable" };

	public static void Apply(GameObject prefab, MeshRenderer renderer)
	{
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)renderer))
		{
			MimirsWellPlugin.Log.LogWarning((object)"The well prefab has no renderer to put the model on, keeping the guard stone look");
			return;
		}
		string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "MimirsWell.obj");
		if (!File.Exists(text))
		{
			MimirsWellPlugin.Log.LogWarning((object)("Model " + text + " not found, keeping the guard stone look"));
			return;
		}
		Mesh val;
		List<string> groups;
		try
		{
			val = ObjLoader.Load(text, out groups);
		}
		catch (Exception arg)
		{
			MimirsWellPlugin.Log.LogError((object)string.Format("Could not read {0}: {1}", "MimirsWell.obj", arg));
			return;
		}
		MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>();
		if (!Object.op_Implicit((Object)(object)component))
		{
			MimirsWellPlugin.Log.LogWarning((object)"The well renderer has no mesh filter, keeping the guard stone look");
			return;
		}
		Material val2 = FindMaterial(StoneDonors) ?? ((Renderer)renderer).sharedMaterial;
		Material val3 = CreateMetalMaterial(FindMaterial(MetalDonors) ?? val2);
		Material[] array = (Material[])(object)new Material[groups.Count];
		for (int i = 0; i < groups.Count; i++)
		{
			string text2 = groups[i];
			if (!(text2 == "metal"))
			{
				if (text2 == "glow")
				{
					array[i] = CreateGlowMaterial(val2);
				}
				else
				{
					array[i] = val2;
				}
			}
			else
			{
				array[i] = val3;
			}
		}
		component.sharedMesh = val;
		((Renderer)renderer).sharedMaterials = array;
		((Component)renderer).transform.localPosition = Vector3.zero;
		((Component)renderer).transform.localRotation = Quaternion.identity;
		((Component)renderer).transform.localScale = Vector3.one;
		((Renderer)renderer).shadowCastingMode = (ShadowCastingMode)1;
		((Renderer)renderer).receiveShadows = true;
		ReplaceColliders(prefab);
		RemoveDonorEffects(prefab);
		AddPoolLight(prefab);
		LogLeftovers(prefab, (Renderer)(object)renderer);
		ManualLogSource log = MimirsWellPlugin.Log;
		string text3 = string.Format("Well model loaded: {0} vertices, {1} groups ({2}), ", val.vertexCount, val.subMeshCount, string.Join(", ", groups.ToArray()));
		string arg2 = ((val2 != null) ? ((Object)val2).name : null);
		string arg3 = ((val3 != null) ? ((Object)val3).name : null);
		Bounds bounds = val.bounds;
		log.LogDebug((object)(text3 + $"stone material '{arg2}', metal material '{arg3}', bounds {((Bounds)(ref bounds)).size}"));
	}

	private static void AddPoolLight(GameObject prefab)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("MW_PoolLight");
		val.transform.SetParent(prefab.transform, false);
		val.transform.localPosition = new Vector3(0f, 0.75f, 0f);
		Light obj = val.AddComponent<Light>();
		obj.type = (LightType)2;
		obj.color = new Color(0.3f, 0.6f, 1f);
		obj.range = 4f;
		obj.intensity = 0.95f;
		obj.shadows = (LightShadows)0;
	}

	private static void RemoveDonorEffects(GameObject prefab)
	{
		ParticleSystem[] componentsInChildren = prefab.GetComponentsInChildren<ParticleSystem>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Object.DestroyImmediate((Object)(object)((Component)componentsInChildren[i]).gameObject);
		}
	}

	private static void LogLeftovers(GameObject prefab, Renderer keep)
	{
		List<string> list = new List<string>();
		Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)(object)keep))
			{
				list.Add($"{((Object)val).name} ({((object)val).GetType().Name}, active {((Component)val).gameObject.activeSelf})");
			}
		}
		ParticleSystem[] componentsInChildren2 = prefab.GetComponentsInChildren<ParticleSystem>(true);
		foreach (ParticleSystem val2 in componentsInChildren2)
		{
			list.Add(((Object)val2).name + " (ParticleSystem)");
		}
		if (list.Count > 0)
		{
			MimirsWellPlugin.Log.LogDebug((object)("Well prefab also carries: " + string.Join(", ", list.ToArray())));
		}
	}

	private static void ReplaceColliders(GameObject prefab)
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: 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)
		Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true);
		foreach (Collider val in componentsInChildren)
		{
			if (!val.isTrigger)
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}
		BoxCollider obj = prefab.AddComponent<BoxCollider>();
		obj.center = new Vector3(0f, 0.4f, 0f);
		obj.size = new Vector3(1.75f, 0.8f, 1.75f);
		BoxCollider obj2 = prefab.AddComponent<BoxCollider>();
		obj2.center = new Vector3(0f, 1.2f, 0.5f);
		obj2.size = new Vector3(0.95f, 1.7f, 0.45f);
	}

	private static bool IsStaticShader(Material material)
	{
		if (!Object.op_Implicit((Object)(object)material) || !Object.op_Implicit((Object)(object)material.shader))
		{
			return false;
		}
		string text = ((Object)material.shader).name.ToLowerInvariant();
		if (text.Contains("veget") || text.Contains("grass") || text.Contains("cloth") || text.Contains("wind") || text.Contains("water") || text.Contains("particle") || text.Contains("tar") || text.Contains("yggdrasil"))
		{
			return false;
		}
		if (!text.Contains("piece") && !text.Contains("static") && !text.Contains("standard") && !text.Contains("creature"))
		{
			return text.Contains("rock");
		}
		return true;
	}

	private static Material FindMaterial(string[] donors)
	{
		foreach (string text in donors)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(text);
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				continue;
			}
			MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true);
			for (int j = 0; j < componentsInChildren.Length; j++)
			{
				Material sharedMaterial = ((Renderer)componentsInChildren[j]).sharedMaterial;
				if (Object.op_Implicit((Object)(object)sharedMaterial))
				{
					if (IsStaticShader(sharedMaterial))
					{
						MimirsWellPlugin.Log.LogDebug((object)("Using material '" + ((Object)sharedMaterial).name + "' from " + text + " (shader '" + ((Object)sharedMaterial.shader).name + "')"));
						return sharedMaterial;
					}
					MimirsWellPlugin.Log.LogDebug((object)("Skipping material '" + ((Object)sharedMaterial).name