Decompiled source of OdinStorage v0.9.1

OdinStorage.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using MultiUserChest;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("OdinStorage")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.9.1.0")]
[assembly: AssemblyInformationalVersion("0.9.1+edc40185618c27011aa3f32a774c917b660673b2")]
[assembly: AssemblyProduct("OdinStorage")]
[assembly: AssemblyTitle("OdinStorage")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.9.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace OdinStorage
{
	public static class DevTools
	{
		private static readonly (string Prefab, int Amount)[] Loadout = new(string, int)[29]
		{
			("Silver", 500),
			("Obsidian", 200),
			("Crystal", 100),
			("FreezeGland", 100),
			("WolfPelt", 200),
			("WolfFang", 100),
			("TrophyWolf", 20),
			("Iron", 300),
			("Bronze", 200),
			("DragonTear", 50),
			("DragonEgg", 3),
			("ArrowFrost", 200),
			("ArrowObsidian", 200),
			("ArrowNeedle", 200),
			("WolfMeatSkewer", 40),
			("SerpentStew", 30),
			("Eyescream", 40),
			("Cloudberry", 100),
			("Blueberries", 100),
			("Onion", 80),
			("MeadFrostResist", 30),
			("MeadHealthMedium", 30),
			("MeadStaminaMedium", 30),
			("DustEpic", 500),
			("EssenceEpic", 500),
			("ReagentEpic", 500),
			("ShardEpic", 999),
			("RunestoneEpic", 200),
			("Coins", 9999)
		};

		private static readonly (string Prefab, string[] Effects)[] MagicGear = new(string, string[])[7]
		{
			("AxeIron", new string[6] { "Executioner", "LifeSteal", "ChainLightning", "ModifyPhysicalDamage", "ModifyStaggerDamage", "ModifyAttackSpeed" }),
			("BowDraugrFang", new string[6] { "Executioner", "TripleBowShot", "ChainLightning", "ModifyPhysicalDamage", "LifeSteal", "ExplosiveArrows" }),
			("ShieldSerpentscale", new string[6] { "ModifyBlockPower", "ModifyBlockForce", "ModifyParry", "ModifyParryWindow", "Immovable", "AvoidDamageTaken" }),
			("ArmorWolfChest", new string[6] { "ModifyArmor", "BulkUp", "IncreaseHealth", "ReflectDamage", "AvoidDamageTaken", "AddPhysicalResistancePercentage" }),
			("ArmorWolfLegs", new string[6] { "ModifyArmor", "BulkUp", "ModifyMovementSpeed", "ModifySprintStaminaUse", "ModifyDodgeStaminaUse", "DoubleJump" }),
			("HelmetDrake", new string[6] { "ModifyArmor", "ModifyHealthRegen", "AddElementalResistancePercentage", "AddPhysicalResistancePercentage", "QuickLearner", "ModifyDiscoveryRadius" }),
			("CapeWolf", new string[6] { "ModifyArmor", "AddCarryWeight", "IncreaseHealth", "ModifyHealthRegen", "ModifyEitrRegen", "AddElementalResistancePercentage" })
		};

		private static readonly Vector2i AutoSlot = new Vector2i(-1, -1);

		private static readonly List<GameObject> Spawned = new List<GameObject>();

		public static void SpawnTestStorage()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_0089: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_009e: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Dev: ZNetScene not ready yet.");
				return;
			}
			GameObject prefab = instance.GetPrefab("piece_chest_wood");
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Dev: prefab 'piece_chest_wood' not found.");
				return;
			}
			Transform transform = ((Component)localPlayer).transform;
			Vector3 val = transform.forward;
			val.y = 0f;
			val = ((((Vector3)(ref val)).sqrMagnitude > 0.001f) ? ((Vector3)(ref val)).normalized : Vector3.forward);
			Vector3 val2 = Vector3.Cross(Vector3.up, val);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			Vector3 val3 = transform.position + val * 2f;
			Quaternion val4 = Quaternion.LookRotation(val);
			List<Container> list = new List<Container>();
			int num = 0;
			for (int i = 0; i < 8; i++)
			{
				for (int j = 0; j < 2; j++)
				{
					Vector3 val5 = val3 + val * ((float)i * 1.2f) + normalized * (((float)j - 0.5f) * 1.2f);
					GameObject val6 = Object.Instantiate<GameObject>(prefab, val5, val4);
					Spawned.Add(val6);
					Container component = val6.GetComponent<Container>();
					if ((Object)(object)component != (Object)null)
					{
						list.Add(component);
					}
					num++;
				}
			}
			int num2 = FillLoadout(list);
			int num3 = FillMagicGear(list);
			Plugin.Log.LogInfo((object)$"Dev: spawned {num} chests, filled with {num2} loadout item types, {num3} test gear pieces");
		}

		private static int FillLoadout(List<Container> containers)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || containers.Count == 0)
			{
				return 0;
			}
			int num = 0;
			int num2 = 0;
			(string, int)[] loadout = Loadout;
			for (int i = 0; i < loadout.Length; i++)
			{
				(string, int) tuple = loadout[i];
				string item = tuple.Item1;
				int item2 = tuple.Item2;
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				int num3 = Mathf.Max(1, item2);
				int maxStack = Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize);
				bool flag = false;
				while (num3 > 0 && num < containers.Count)
				{
					Inventory val2 = (((Object)(object)containers[num] != (Object)null) ? containers[num].GetInventory() : null);
					int num4 = ((val2 != null) ? FitAmount(val2, val, maxStack, num3) : 0);
					if (num4 <= 0)
					{
						num++;
						continue;
					}
					val2.AddItem(itemPrefab, num4);
					num3 -= num4;
					flag = true;
				}
				if (flag)
				{
					num2++;
				}
				if (num3 > 0)
				{
					Plugin.Log.LogWarning((object)$"Dev: ran out of chest space, {num3} of {item} not placed.");
				}
			}
			return num2;
		}

		private static int FitAmount(Inventory inv, ItemDrop drop, int maxStack, int want)
		{
			string name = drop.m_itemData.m_shared.m_name;
			List<ItemData> allItems = inv.GetAllItems();
			int num = 0;
			foreach (ItemData item in allItems)
			{
				if (item?.m_shared != null && item.m_shared.m_name == name && item.m_stack < maxStack)
				{
					num += maxStack - item.m_stack;
				}
			}
			int num2 = inv.GetWidth() * inv.GetHeight();
			int num3 = Mathf.Max(0, num2 - allItems.Count);
			num += num3 * maxStack;
			return Mathf.Min(want, num);
		}

		private static int FillMagicGear(List<Container> containers)
		{
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			if (!EpicLootMagic.Available)
			{
				Plugin.Log.LogInfo((object)"Dev: EpicLoot not present — skipping magic test gear.");
				return 0;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null || containers.Count == 0)
			{
				return 0;
			}
			int num = 0;
			List<string> list = new List<string>();
			(string, string[])[] magicGear = MagicGear;
			for (int i = 0; i < magicGear.Length; i++)
			{
				(string, string[]) tuple = magicGear[i];
				string item = tuple.Item1;
				string[] item2 = tuple.Item2;
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)("Dev: gear prefab '" + item + "' unknown in this version — skipped."));
					continue;
				}
				ItemData val2 = val.m_itemData.Clone();
				val2.m_stack = 1;
				val2.m_quality = val2.m_shared.m_maxQuality;
				val2.m_durability = val2.GetMaxDurability();
				val2.m_crafterName = "Dev";
				if (!EpicLootMagic.TryForceEffects(val2, item2, out string rarityName, out List<string> skipped))
				{
					Plugin.Log.LogWarning((object)("Dev: could not build test gear '" + item + "', skipped."));
					continue;
				}
				foreach (string item3 in skipped)
				{
					list.Add(item + ": " + item3);
				}
				bool flag = false;
				foreach (Container container in containers)
				{
					Inventory val3 = (((Object)(object)container != (Object)null) ? container.GetInventory() : null);
					if (val3 != null && val3.CanAddItem(val2, 1))
					{
						Inventory val4 = new Inventory("dev_gear", (Sprite)null, 1, 1);
						val4.AddItem(val2);
						ContainerHandler.AddItemToChest(container, val2, val4, AutoSlot, ZDOID.None, val2.m_stack);
						flag = true;
						num++;
						break;
					}
				}
				if (flag)
				{
					int num2 = item2.Length - skipped.Count;
					Plugin.Log.LogInfo((object)$"Dev: placed {rarityName} test gear '{item}' ({num2}/{item2.Length} effects).");
				}
				else
				{
					Plugin.Log.LogWarning((object)("Dev: no chest space for test gear '" + item + "'."));
				}
			}
			if (list.Count > 0)
			{
				Plugin.Log.LogWarning((object)string.Format("Dev: {0} effect(s) skipped (not allowed for slot): {1}", list.Count, string.Join(", ", list)));
			}
			return num;
		}

		public static void ClearTestStorage()
		{
			ZNetScene instance = ZNetScene.instance;
			int num = 0;
			foreach (GameObject item in Spawned)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ZNetView component = item.GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.IsValid())
				{
					component.ClaimOwnership();
					if ((Object)(object)instance != (Object)null)
					{
						instance.Destroy(item);
						num++;
						continue;
					}
				}
				Object.Destroy((Object)(object)item);
				num++;
			}
			Spawned.Clear();
			Plugin.Log.LogInfo((object)$"Dev: removed {num} test chests");
		}
	}
	public static class EpicLootMagic
	{
		private static bool _probed;

		private static bool _available;

		private static ConstructorInfo? _magicItemCtor;

		private static ConstructorInfo? _effectCtor;

		private static FieldInfo? _rarityField;

		private static FieldInfo? _effectsField;

		private static MethodInfo? _saveMagicItem;

		private static MethodInfo? _getDefinition;

		private static MethodInfo? _getAvailableEffects;

		private static FieldInfo? _valuesPerRarityField;

		private static Type? _valuesPerRarityType;

		private static FieldInfo? _valueDefMaxField;

		private static PropertyInfo? _definitionTypeProp;

		private static object? _rarityMythic;

		private static object? _rarityLegendary;

		private static bool _useMythicResolved;

		private static bool _useMythic;

		public static bool Available
		{
			get
			{
				Probe();
				return _available;
			}
		}

		private static void Probe()
		{
			if (_probed)
			{
				return;
			}
			_probed = true;
			try
			{
				Type type = FindType("EpicLoot.MagicItem");
				Type type2 = FindType("EpicLoot.MagicItemEffect");
				Type type3 = FindType("EpicLoot.ItemRarity");
				Type type4 = FindType("EpicLoot.ItemDataExtensions");
				Type type5 = FindType("EpicLoot.MagicItemEffectDefinition");
				Type type6 = FindType("EpicLoot.MagicItemEffectDefinitions");
				if (type == null || type2 == null || type3 == null || type4 == null || type5 == null || type6 == null)
				{
					Plugin.Log.LogInfo((object)"EpicLoot not detected — magic test gear disabled.");
					return;
				}
				_magicItemCtor = type.GetConstructor(Type.EmptyTypes);
				_effectCtor = type2.GetConstructor(new Type[2]
				{
					typeof(string),
					typeof(float)
				});
				_rarityField = type.GetField("Rarity", BindingFlags.Instance | BindingFlags.Public);
				_effectsField = type.GetField("Effects", BindingFlags.Instance | BindingFlags.Public);
				_saveMagicItem = type4.GetMethod("SaveMagicItem", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
				{
					typeof(ItemData),
					type
				}, null);
				_getDefinition = type6.GetMethod("Get", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
				_getAvailableEffects = type6.GetMethod("GetAvailableEffects", BindingFlags.Static | BindingFlags.Public, null, new Type[6]
				{
					typeof(ItemData),
					type,
					typeof(int),
					typeof(bool),
					typeof(bool),
					typeof(bool)
				}, null);
				_valuesPerRarityField = type5.GetField("ValuesPerRarity", BindingFlags.Instance | BindingFlags.Public);
				_valuesPerRarityType = _valuesPerRarityField?.FieldType;
				_valueDefMaxField = (_valuesPerRarityType?.GetField("Mythic", BindingFlags.Instance | BindingFlags.Public)?.FieldType)?.GetField("MaxValue", BindingFlags.Instance | BindingFlags.Public);
				_definitionTypeProp = type5.GetProperty("Type", BindingFlags.Instance | BindingFlags.Public);
				_rarityMythic = Enum.ToObject(type3, 4);
				_rarityLegendary = Enum.ToObject(type3, 3);
				_available = _magicItemCtor != null && _effectCtor != null && _rarityField != null && _effectsField != null && _saveMagicItem != null && _getDefinition != null && _valuesPerRarityField != null && _valuesPerRarityType != null && _valueDefMaxField != null;
				if (!_available)
				{
					Plugin.Log.LogWarning((object)"EpicLoot present but API shape unexpected — magic test gear disabled.");
				}
			}
			catch (Exception ex)
			{
				_available = false;
				Plugin.Log.LogWarning((object)("EpicLoot probe failed — magic test gear disabled (" + ex.Message + ")."));
			}
		}

		public static bool TryForceEffects(ItemData item, IList<string> effectTypes, out string rarityName, out List<string> skipped)
		{
			rarityName = string.Empty;
			skipped = new List<string>();
			Probe();
			if (!_available || item == null || effectTypes == null)
			{
				return false;
			}
			try
			{
				bool flag = UseMythic();
				object value = (flag ? _rarityMythic : _rarityLegendary);
				rarityName = (flag ? "Mythic" : "Legendary");
				object obj = _magicItemCtor.Invoke(null);
				_rarityField.SetValue(obj, value);
				IList list = (IList)_effectsField.GetValue(obj);
				list.Clear();
				HashSet<string> allowedEffectTypes = GetAllowedEffectTypes(item, obj);
				foreach (string effectType in effectTypes)
				{
					if (allowedEffectTypes.Count > 0 && !allowedEffectTypes.Contains(effectType))
					{
						Plugin.Log.LogWarning((object)("Dev: effect '" + effectType + "' not allowed for this item slot — skipped."));
						skipped.Add(effectType);
						continue;
					}
					float num = MaxValueFor(effectType, rarityName);
					object value2 = _effectCtor.Invoke(new object[2] { effectType, num });
					list.Add(value2);
				}
				if (list.Count == 0)
				{
					rarityName = string.Empty;
					return false;
				}
				_saveMagicItem.Invoke(null, new object[2] { item, obj });
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("EpicLoot force-effects failed (" + ex.Message + ")."));
				rarityName = string.Empty;
				return false;
			}
		}

		private static bool UseMythic()
		{
			if (_useMythicResolved)
			{
				return _useMythic;
			}
			_useMythicResolved = true;
			_useMythic = false;
			try
			{
				FieldInfo fieldInfo = _valuesPerRarityType?.GetField("Mythic", BindingFlags.Instance | BindingFlags.Public);
				string[] array = new string[3] { "ModifyArmor", "ModifyDurability", "ModifyPhysicalDamage" };
				foreach (string text in array)
				{
					object obj = _getDefinition.Invoke(null, new object[1] { text });
					if (obj != null)
					{
						object value = _valuesPerRarityField.GetValue(obj);
						if (value != null)
						{
							_useMythic = fieldInfo?.GetValue(value) != null;
							break;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogInfo((object)("EpicLoot mythic probe failed, using Legendary (" + ex.Message + ")."));
				_useMythic = false;
			}
			return _useMythic;
		}

		private static float MaxValueFor(string effectType, string rarityName)
		{
			try
			{
				object obj = _getDefinition.Invoke(null, new object[1] { effectType });
				if (obj == null)
				{
					return 0f;
				}
				object value = _valuesPerRarityField.GetValue(obj);
				if (value == null)
				{
					return 0f;
				}
				object obj2 = _valuesPerRarityType.GetField(rarityName, BindingFlags.Instance | BindingFlags.Public)?.GetValue(value);
				if (obj2 == null)
				{
					obj2 = _valuesPerRarityType.GetField("Legendary", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value);
					if (obj2 == null)
					{
						return 0f;
					}
				}
				return (_valueDefMaxField.GetValue(obj2) is float num) ? num : 0f;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogInfo((object)("EpicLoot value lookup for '" + effectType + "' failed (" + ex.Message + ")."));
				return 0f;
			}
		}

		private static HashSet<string> GetAllowedEffectTypes(ItemData item, object magic)
		{
			HashSet<string> hashSet = new HashSet<string>();
			if (_getAvailableEffects == null || _definitionTypeProp == null)
			{
				return hashSet;
			}
			try
			{
				if (_getAvailableEffects.Invoke(null, new object[6] { item, magic, -1, true, false, false }) is IEnumerable enumerable)
				{
					foreach (object item3 in enumerable)
					{
						if (_definitionTypeProp.GetValue(item3) is string item2)
						{
							hashSet.Add(item2);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogInfo((object)("EpicLoot availability check unavailable (" + ex.Message + "); no slot-filter applied."));
				hashSet.Clear();
			}
			return hashSet;
		}

		private static Type? FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType(fullName, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}
	}
	[BepInPlugin("com.nicolai.odinstorage", "OdinStorage", "0.9.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <RefreshSoonCo>d__20 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RefreshSoonCo>d__20(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(0.2f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					StorageTerminalUI.Refresh();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string MucGuid = "com.maxsch.valheim.MultiUserChest";

		public const string QssGuid = "goldenrevolver.quick_stack_store";

		public const string PluginGuid = "com.nicolai.odinstorage";

		public const string PluginName = "OdinStorage";

		public const string PluginVersion = "0.9.1";

		private readonly Harmony _harmony = new Harmony("com.nicolai.odinstorage");

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static ConfigEntry<KeyboardShortcut> Hotkey;

		internal static ConfigEntry<float> Radius;

		internal static ConfigEntry<bool> VerboseLogging;

		internal static ConfigEntry<bool> DevTools;

		internal static ConfigEntry<KeyboardShortcut> SpawnKey;

		internal static ConfigEntry<KeyboardShortcut> ClearKey;

		internal static ConfigEntry<bool> MarkerEnabled;

		internal static ConfigEntry<float> MarkerDuration;

		private void Awake()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Hotkey", new KeyboardShortcut((KeyCode)111, Array.Empty<KeyCode>()), "Key that triggers the chest scan.");
			Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 20f, "Range in meters.");
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "If enabled, logs every Container.Awake (very verbose).");
			DevTools = ((BaseUnityPlugin)this).Config.Bind<bool>("Dev", "DevTools", false, "Enables the developer keys (spawn/clear test chests).");
			SpawnKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Dev", "SpawnKey", new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>()), "Spawn and fill test chests (only when DevTools is enabled).");
			ClearKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Dev", "ClearKey", new KeyboardShortcut((KeyCode)108, Array.Empty<KeyCode>()), "Remove spawned test chests (only when DevTools is enabled).");
			MarkerEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Marker", "MarkerEnabled", true, "\"Find item\": marks chests in the world (local visual aid).");
			MarkerDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Marker", "MarkerDuration", 30f, "How long the find marker stays visible after closing the terminal (seconds).");
			Log.LogInfo((object)"OdinStorage 0.9.1 loaded.");
			PrefabManager.OnVanillaPrefabsAvailable += TerminalPiece.Register;
			GUIManager.OnCustomGUIAvailable += StorageTerminalUI.Create;
			_harmony.PatchAll();
		}

		private void Update()
		{
			//IL_0013: 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_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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			KeyboardShortcut value = Hotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				StorageScanner.Scan();
			}
			if (StorageTerminalUI.IsOpen && Input.GetKeyDown((KeyCode)27))
			{
				StorageTerminalUI.Close();
			}
			if (DevTools.Value)
			{
				value = SpawnKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					OdinStorage.DevTools.SpawnTestStorage();
				}
				value = ClearKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					OdinStorage.DevTools.ClearTestStorage();
				}
			}
		}

		internal void StartCleanup(Vector3 center)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			((MonoBehaviour)this).StartCoroutine(StorageCleanup.Run(center, Radius.Value));
		}

		internal void RefreshSoon()
		{
			((MonoBehaviour)this).StartCoroutine(RefreshSoonCo());
		}

		[IteratorStateMachine(typeof(<RefreshSoonCo>d__20))]
		private static IEnumerator RefreshSoonCo()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RefreshSoonCo>d__20(0);
		}
	}
	public static class QssFavorites
	{
		private static bool _resolved;

		private static bool _available;

		private static MethodInfo? _getPlayerConfig;

		private static MethodInfo? _isFavorited;

		public static bool Available
		{
			get
			{
				Resolve();
				return _available;
			}
		}

		private static void Resolve()
		{
			if (_resolved)
			{
				return;
			}
			_resolved = true;
			try
			{
				Type type = AppDomain.CurrentDomain.GetAssemblies().Select(delegate(Assembly a)
				{
					try
					{
						return a.GetType("QuickStackStore.UserConfig", throwOnError: false);
					}
					catch
					{
						return null;
					}
				}).FirstOrDefault((Type t) => t != null);
				if (type == null)
				{
					Plugin.Log.LogInfo((object)"QSS not found — favorite protection uses fallback (equipment + hotbar).");
					return;
				}
				_getPlayerConfig = type.GetMethod("GetPlayerConfig", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(long) }, null);
				_isFavorited = type.GetMethod("IsItemNameOrSlotFavorited", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null);
				_available = _getPlayerConfig != null && _isFavorited != null;
				if (_available)
				{
					Plugin.Log.LogInfo((object)"QSS detected — favorites are protected when depositing.");
				}
				else
				{
					Plugin.Log.LogWarning((object)"QSS found, but favorites API not readable — fallback active.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("QSS reflection failed (" + ex.Message + ") — fallback active."));
				_available = false;
			}
		}

		public static object? GetLocalConfig()
		{
			Resolve();
			if (!_available)
			{
				return null;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return null;
			}
			try
			{
				return _getPlayerConfig.Invoke(null, new object[1] { localPlayer.GetPlayerID() });
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("QSS GetPlayerConfig failed (" + ex.Message + ")."));
				return null;
			}
		}

		public static bool IsFavorited(object? config, ItemData item)
		{
			if (config == null || _isFavorited == null || item == null)
			{
				return false;
			}
			try
			{
				return (bool)_isFavorited.Invoke(config, new object[1] { item });
			}
			catch
			{
				return false;
			}
		}
	}
	public static class StorageCleanup
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass10_0
		{
			public string token;

			public Func<Container, bool> <>9__0;

			public Func<Container, int> <>9__1;

			internal bool <Run>b__0(Container c)
			{
				if (IsValid(c))
				{
					return CountInChest(c, token) > 0;
				}
				return false;
			}

			internal int <Run>b__1(Container c)
			{
				return CountInChest(c, token);
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass10_1
		{
			public Container source;

			public ItemData item;

			internal bool <Run>b__2(Container h)
			{
				if ((Object)(object)h != (Object)(object)source)
				{
					return CapacityFor(h, item) > 0;
				}
				return false;
			}

			internal bool <Run>b__3(Container c)
			{
				if ((Object)(object)c != (Object)(object)source && IsValid(c))
				{
					return CapacityFor(c, item) > 0;
				}
				return false;
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass11_0
		{
			public string token;

			internal bool <MoveViaTransit>b__0(ItemData i)
			{
				if (i?.m_shared != null)
				{
					return i.m_shared.m_name == token;
				}
				return false;
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass12_0
		{
			public ItemData item;

			internal bool <FlushTransit>b__0(Container c)
			{
				if (IsValid(c))
				{
					return CapacityFor(c, item) > 0;
				}
				return false;
			}
		}

		[CompilerGenerated]
		private sealed class <FlushTransit>d__12 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Inventory transit;

			public List<Container> chests;

			private List<ItemData>.Enumerator <>7__wrap1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FlushTransit>d__12(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap1 = default(List<ItemData>.Enumerator);
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>7__wrap1 = transit.GetAllItems().ToList().GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					}
					while (<>7__wrap1.MoveNext())
					{
						<>c__DisplayClass12_0 CS$<>8__locals0 = new <>c__DisplayClass12_0
						{
							item = <>7__wrap1.Current
						};
						if (CS$<>8__locals0.item?.m_shared == null)
						{
							continue;
						}
						Container val = ((IEnumerable<Container>)chests).FirstOrDefault((Func<Container, bool>)((Container c) => IsValid(c) && CapacityFor(c, CS$<>8__locals0.item) > 0));
						if ((Object)(object)val != (Object)null)
						{
							try
							{
								ContainerHandler.AddItemToChest(val, CS$<>8__locals0.item, transit, AutoSlot, ZDOID.None, CS$<>8__locals0.item.m_stack);
							}
							catch (Exception ex)
							{
								Plugin.Log.LogWarning((object)("Consolidate: flush to chest failed (" + ex.Message + ")."));
							}
							<>2__current = null;
							<>1__state = 1;
							return true;
						}
					}
					<>m__Finally1();
					<>7__wrap1 = default(List<ItemData>.Enumerator);
					Inventory val2 = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null);
					foreach (ItemData item in transit.GetAllItems().ToList())
					{
						if (item?.m_shared != null)
						{
							Plugin.Log.LogWarning((object)$"Consolidate: {item.m_stack}x {item.m_shared.m_name} found no chest space.");
							if (val2 != null)
							{
								val2.AddItem(item);
							}
						}
					}
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap1).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <MoveViaTransit>d__11 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string token;

			public Container source;

			public Container sink;

			public Inventory transit;

			public ItemData item;

			public int amt;

			private <>c__DisplayClass11_0 <>8__1;

			private int <transitBefore>5__2;

			private int <waited>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <MoveViaTransit>d__11(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_007d: 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_0141: Unknown result type (might be due to invalid IL or missing references)
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				ItemData val;
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass11_0();
					<>8__1.token = token;
					if (!IsValid(source) || !IsValid(sink))
					{
						return false;
					}
					<transitBefore>5__2 = TotalStacks(transit);
					try
					{
						ContainerHandler.RemoveItemFromChest(source, item, transit, AutoSlot, ZDOID.None, amt, (ItemData)null);
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Consolidate: removing from chest failed (" + ex.Message + ")."));
						return false;
					}
					<waited>5__3 = 0;
					goto IL_00ef;
				case 1:
					<>1__state = -1;
					goto IL_00ef;
				case 2:
					{
						<>1__state = -1;
						return false;
					}
					IL_00ef:
					if (TotalStacks(transit) <= <transitBefore>5__2 && <waited>5__3 < 60)
					{
						<waited>5__3++;
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					val = ((IEnumerable<ItemData>)transit.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i?.m_shared != null && i.m_shared.m_name == <>8__1.token));
					if (val == null)
					{
						return false;
					}
					try
					{
						ContainerHandler.AddItemToChest(sink, val, transit, AutoSlot, ZDOID.None, val.m_stack);
						_moved = true;
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogWarning((object)("Consolidate: adding to chest failed (" + ex2.Message + ")."));
					}
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <Run>d__10 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Vector3 center;

			public float radius;

			private <>c__DisplayClass10_0 <>8__1;

			private List<Container> <chests>5__2;

			private Dictionary<string, int> <before>5__3;

			private Inventory <transit>5__4;

			private int <moves>5__5;

			private List<string>.Enumerator <>7__wrap5;

			private int <guard>5__7;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Run>d__10(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 1) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>8__1 = null;
				<chests>5__2 = null;
				<before>5__3 = null;
				<transit>5__4 = null;
				<>7__wrap5 = default(List<string>.Enumerator);
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b9: Expected O, but got Unknown
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						if (_busy)
						{
							return false;
						}
						_busy = true;
						<chests>5__2 = StorageScanner.NearbyChests(center, radius).ToList();
						if (<chests>5__2.Count < 2)
						{
							Plugin.Log.LogInfo((object)"Consolidate: fewer than two chests within range — nothing to do.");
							_busy = false;
							StorageTerminalUI.Refresh();
							return false;
						}
						<before>5__3 = CountByToken(<chests>5__2);
						LogSlotUsage(<chests>5__2);
						<transit>5__4 = new Inventory("odin_cleanup_transit", (Sprite)null, 8, 6);
						<moves>5__5 = 0;
						<>7__wrap5 = <before>5__3.Keys.ToList().GetEnumerator();
						<>1__state = -3;
						goto IL_0320;
					case 1:
						<>1__state = -3;
						if (_moved)
						{
							<moves>5__5++;
							if (<moves>5__5 % 4 == 0)
							{
								<>2__current = null;
								<>1__state = 2;
								return true;
							}
							goto IL_02ee;
						}
						goto IL_0319;
					case 2:
						<>1__state = -3;
						goto IL_02ee;
					case 3:
						{
							<>1__state = -1;
							Dictionary<string, int> after = CountByToken(<chests>5__2);
							bool flag = Verify(<before>5__3, after, <transit>5__4, <moves>5__5);
							_busy = false;
							Player localPlayer = Player.m_localPlayer;
							if ((Object)(object)localPlayer != (Object)null)
							{
								((Character)localPlayer).Message((MessageType)2, flag ? $"Storage consolidated ({<moves>5__5} moves)" : "Consolidate: WARNING — item count mismatch!", 0, (Sprite)null);
							}
							StorageTerminalUI.Refresh();
							return false;
						}
						IL_02ee:
						if (<moves>5__5 < 5000 && <guard>5__7++ < 1000)
						{
							<>c__DisplayClass10_1 CS$<>8__locals0 = new <>c__DisplayClass10_1();
							List<Container> list = (from c in <chests>5__2
								where IsValid(c) && CountInChest(c, <>8__1.token) > 0
								orderby CountInChest(c, <>8__1.token) descending
								select c).ToList();
							if (list.Count > 1)
							{
								CS$<>8__locals0.source = list[list.Count - 1];
								CS$<>8__locals0.item = FirstItemOfToken(CS$<>8__locals0.source, <>8__1.token);
								if (CS$<>8__locals0.item != null)
								{
									Container val = ((IEnumerable<Container>)list).FirstOrDefault((Func<Container, bool>)((Container h) => (Object)(object)h != (Object)(object)CS$<>8__locals0.source && CapacityFor(h, CS$<>8__locals0.item) > 0));
									if ((Object)(object)val == (Object)null)
									{
										val = ((IEnumerable<Container>)<chests>5__2).FirstOrDefault((Func<Container, bool>)((Container c) => (Object)(object)c != (Object)(object)CS$<>8__locals0.source && IsValid(c) && CapacityFor(c, CS$<>8__locals0.item) > 0));
									}
									if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)CS$<>8__locals0.source))
									{
										int num = Mathf.Min(CS$<>8__locals0.item.m_stack, CapacityFor(val, CS$<>8__locals0.item));
										if (num > 0)
										{
											_moved = false;
											<>2__current = MoveViaTransit(CS$<>8__locals0.source, val, <>8__1.token, CS$<>8__locals0.item, num, <transit>5__4);
											<>1__state = 1;
											return true;
										}
									}
								}
							}
						}
						goto IL_0319;
						IL_0320:
						if (<>7__wrap5.MoveNext())
						{
							<>8__1 = new <>c__DisplayClass10_0();
							<>8__1.token = <>7__wrap5.Current;
							<guard>5__7 = 0;
							goto IL_02ee;
						}
						<>m__Finally1();
						<>7__wrap5 = default(List<string>.Enumerator);
						<>2__current = FlushTransit(<transit>5__4, <chests>5__2);
						<>1__state = 3;
						return true;
						IL_0319:
						<>8__1 = null;
						goto IL_0320;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap5).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static readonly Vector2i AutoSlot = new Vector2i(-1, -1);

		private const int MoveCap = 5000;

		private const int PerTokenGuard = 1000;

		private const int BatchYield = 4;

		private const int ArriveWaitFrames = 60;

		private static bool _busy;

		private static bool _moved;

		public static bool Busy => _busy;

		public static int EstimateMoves(Vector3 center, float radius)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
			foreach (Container item in StorageScanner.NearbyChests(center, radius))
			{
				Inventory inventory = item.GetInventory();
				List<ItemData> list = ((inventory != null) ? inventory.GetAllItems() : null);
				if (list == null)
				{
					continue;
				}
				Dictionary<string, int> dictionary3 = new Dictionary<string, int>();
				foreach (ItemData item2 in list)
				{
					if (item2?.m_shared != null)
					{
						string name = item2.m_shared.m_name;
						dictionary3.TryGetValue(name, out var value);
						dictionary3[name] = value + item2.m_stack;
						dictionary.TryGetValue(name, out var value2);
						dictionary[name] = value2 + item2.m_stack;
					}
				}
				foreach (KeyValuePair<string, int> item3 in dictionary3)
				{
					dictionary2.TryGetValue(item3.Key, out var value3);
					if (item3.Value > value3)
					{
						dictionary2[item3.Key] = item3.Value;
					}
				}
			}
			int num = 0;
			foreach (KeyValuePair<string, int> item4 in dictionary)
			{
				dictionary2.TryGetValue(item4.Key, out var value4);
				num += item4.Value - value4;
			}
			return num;
		}

		[IteratorStateMachine(typeof(<Run>d__10))]
		public static IEnumerator Run(Vector3 center, float radius)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Run>d__10(0)
			{
				center = center,
				radius = radius
			};
		}

		[IteratorStateMachine(typeof(<MoveViaTransit>d__11))]
		private static IEnumerator MoveViaTransit(Container source, Container sink, string token, ItemData item, int amt, Inventory transit)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <MoveViaTransit>d__11(0)
			{
				source = source,
				sink = sink,
				token = token,
				item = item,
				amt = amt,
				transit = transit
			};
		}

		[IteratorStateMachine(typeof(<FlushTransit>d__12))]
		private static IEnumerator FlushTransit(Inventory transit, List<Container> chests)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FlushTransit>d__12(0)
			{
				transit = transit,
				chests = chests
			};
		}

		private static bool Verify(Dictionary<string, int> before, Dictionary<string, int> after, Inventory transit, int moves)
		{
			bool flag = true;
			foreach (string item in before.Keys.Union(after.Keys))
			{
				before.TryGetValue(item, out var value);
				after.TryGetValue(item, out var value2);
				if (value2 != value)
				{
					flag = false;
					Plugin.Log.LogError((object)$"CONSOLIDATE SAFETY NET: '{item}' before {value}, after {value2} (diff {value2 - value})!");
				}
			}
			int num = TotalStacks(transit);
			if (num > 0)
			{
				flag = false;
				Plugin.Log.LogError((object)$"CONSOLIDATE SAFETY NET: {num} item(s) stuck in transit!");
			}
			if (flag)
			{
				Plugin.Log.LogInfo((object)$"Consolidate done: {moves} moves, item counts match.");
			}
			else
			{
				Plugin.Log.LogError((object)"Consolidate: item counts differ — please check storage! (diffs above)");
			}
			return flag;
		}

		private static bool IsValid(Container c)
		{
			if ((Object)(object)c != (Object)null && (Object)(object)c.m_nview != (Object)null)
			{
				return c.m_nview.IsValid();
			}
			return false;
		}

		private static void LogSlotUsage(List<Container> chests)
		{
			int num = 0;
			int num2 = 0;
			foreach (Container chest in chests)
			{
				if (IsValid(chest))
				{
					Inventory inventory = chest.GetInventory();
					if (inventory != null)
					{
						int num3 = inventory.GetWidth() * inventory.GetHeight();
						num += num3;
						num2 += num3 - inventory.GetEmptySlots();
					}
				}
			}
			Plugin.Log.LogInfo((object)$"Storage: {num2} / {num} slots used");
		}

		private static Dictionary<string, int> CountByToken(List<Container> chests)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (Container chest in chests)
			{
				if (!IsValid(chest))
				{
					continue;
				}
				Inventory inventory = chest.GetInventory();
				List<ItemData> list = ((inventory != null) ? inventory.GetAllItems() : null);
				if (list == null)
				{
					continue;
				}
				foreach (ItemData item in list)
				{
					if (item?.m_shared != null)
					{
						dictionary.TryGetValue(item.m_shared.m_name, out var value);
						dictionary[item.m_shared.m_name] = value + item.m_stack;
					}
				}
			}
			return dictionary;
		}

		private static int CountInChest(Container chest, string token)
		{
			Inventory inventory = chest.GetInventory();
			List<ItemData> list = ((inventory != null) ? inventory.GetAllItems() : null);
			if (list == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData item in list)
			{
				if (item?.m_shared != null && item.m_shared.m_name == token)
				{
					num += item.m_stack;
				}
			}
			return num;
		}

		private static ItemData? FirstItemOfToken(Container chest, string token)
		{
			string token2 = token;
			Inventory inventory = chest.GetInventory();
			return ((inventory != null) ? inventory.GetAllItems() : null)?.FirstOrDefault((Func<ItemData, bool>)((ItemData it) => it?.m_shared != null && it.m_shared.m_name == token2 && it.m_stack > 0));
		}

		private static bool IsMergeable(ItemData item)
		{
			if (item?.m_shared != null && item.m_shared.m_maxStackSize > 1)
			{
				if (item.m_customData != null)
				{
					return item.m_customData.Count == 0;
				}
				return true;
			}
			return false;
		}

		private static bool CanMerge(ItemData a, ItemData b)
		{
			if (IsMergeable(a) && IsMergeable(b) && a.m_shared.m_name == b.m_shared.m_name && a.m_quality == b.m_quality)
			{
				return a.m_variant == b.m_variant;
			}
			return false;
		}

		private static int CapacityFor(Container chest, ItemData sample)
		{
			Inventory inventory = chest.GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			int emptySlots = inventory.GetEmptySlots();
			if (!IsMergeable(sample))
			{
				return emptySlots;
			}
			int num = Mathf.Max(1, sample.m_shared.m_maxStackSize);
			int num2 = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem != null && CanMerge(allItem, sample))
				{
					num2 += num - allItem.m_stack;
				}
			}
			return num2 + emptySlots * num;
		}

		private static int TotalStacks(Inventory inv)
		{
			int num = 0;
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (allItem != null)
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}
	}
	public static class StorageDeposit
	{
		private class ChestModel
		{
			public Container Chest;

			public HashSet<string> Tokens = new HashSet<string>();

			public int EmptySlots;

			public Dictionary<string, int> PartialFree = new Dictionary<string, int>();

			public int CapacityFor(string token, int maxStack)
			{
				PartialFree.TryGetValue(token, out var value);
				return value + EmptySlots * maxStack;
			}

			public void Reserve(string token, int amount, int maxStack)
			{
				PartialFree.TryGetValue(token, out var value);
				int num = Mathf.Min(amount, value);
				value -= num;
				int num2 = amount - num;
				if (num2 > 0 && EmptySlots > 0)
				{
					EmptySlots--;
					value += maxStack - num2;
				}
				PartialFree[token] = value;
				Tokens.Add(token);
			}
		}

		private static readonly Vector2i AutoSlot = new Vector2i(-1, -1);

		public static int Deposit(Vector3 center, float radius, out bool leftover)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			leftover = false;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			object localConfig = QssFavorites.GetLocalConfig();
			bool flag = localConfig != null;
			List<ChestModel> list = new List<ChestModel>();
			foreach (Container item in StorageScanner.NearbyChests(center, radius))
			{
				Inventory inventory2 = item.GetInventory();
				if (inventory2 == null)
				{
					continue;
				}
				ChestModel chestModel = new ChestModel
				{
					Chest = item,
					EmptySlots = inventory2.GetEmptySlots()
				};
				List<ItemData> allItems = inventory2.GetAllItems();
				if (allItems != null)
				{
					foreach (ItemData item2 in allItems)
					{
						if (item2?.m_shared != null)
						{
							string name = item2.m_shared.m_name;
							chestModel.Tokens.Add(name);
							int num = Mathf.Max(1, item2.m_shared.m_maxStackSize) - item2.m_stack;
							if (num > 0)
							{
								chestModel.PartialFree.TryGetValue(name, out var value);
								chestModel.PartialFree[name] = value + num;
							}
						}
					}
				}
				list.Add(chestModel);
			}
			if (list.Count == 0)
			{
				return 0;
			}
			int deposited = 0;
			foreach (ItemData item3 in new List<ItemData>(inventory.GetAllItems()))
			{
				if (item3?.m_shared == null || item3.m_equipped)
				{
					continue;
				}
				if (flag)
				{
					if (QssFavorites.IsFavorited(localConfig, item3))
					{
						continue;
					}
				}
				else if (item3.m_gridPos.y == 0)
				{
					continue;
				}
				string name2 = item3.m_shared.m_name;
				int maxStack = Mathf.Max(1, item3.m_shared.m_maxStackSize);
				int stack = item3.m_stack;
				stack -= DepositIntoChests(item3, name2, maxStack, stack, inventory, list, requireToken: true, ref deposited);
				if (stack > 0)
				{
					stack -= DepositIntoChests(item3, name2, maxStack, stack, inventory, list, requireToken: false, ref deposited);
				}
				if (stack > 0)
				{
					leftover = true;
				}
			}
			return deposited;
		}

		private static int DepositIntoChests(ItemData item, string token, int maxStack, int remaining, Inventory playerInv, List<ChestModel> models, bool requireToken, ref int deposited)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (ChestModel model in models)
			{
				if (remaining - num <= 0)
				{
					break;
				}
				if (requireToken && !model.Tokens.Contains(token))
				{
					continue;
				}
				Container chest = model.Chest;
				if ((Object)(object)chest == (Object)null || (Object)(object)chest.m_nview == (Object)null || !chest.m_nview.IsValid())
				{
					continue;
				}
				int num2 = model.CapacityFor(token, maxStack);
				if (num2 <= 0)
				{
					continue;
				}
				int num3 = Mathf.Min(remaining - num, num2);
				if (num3 > 0)
				{
					try
					{
						ContainerHandler.AddItemToChest(chest, item, playerInv, AutoSlot, ZDOID.None, num3);
						model.Reserve(token, num3, maxStack);
						num += num3;
						deposited += num3;
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Deposit: adding to chest failed (" + ex.Message + ")."));
					}
				}
			}
			return num;
		}
	}
	public static class StorageMarkers
	{
		private const float BeamHeight = 40f;

		private static readonly List<GameObject> _active = new List<GameObject>();

		private static Material? _beamMat;

		private static readonly Color CyanCore = new Color(0.45f, 0.85f, 1f, 0.95f);

		private static readonly Color CyanTop = new Color(0.45f, 0.85f, 1f, 0.1f);

		public static void Show(List<Vector3> chestPositions, Sprite? icon, float duration)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			Clear();
			if (chestPositions == null || chestPositions.Count == 0)
			{
				return;
			}
			Vector3 viewer = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero);
			foreach (Vector3 chestPosition in chestPositions)
			{
				GameObject val = new GameObject("OdinFindMarker");
				val.transform.position = chestPosition;
				BuildBeam(val, chestPosition);
				BuildIcon(val, chestPosition, viewer, icon);
				val.AddComponent<MarkerLifetime>().Init(duration);
				_active.Add(val);
			}
		}

		public static void Clear()
		{
			foreach (GameObject item in _active)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			_active.Clear();
		}

		public static void StartTimers()
		{
			foreach (GameObject item in _active)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.GetComponent<MarkerLifetime>()?.Begin();
				}
			}
		}

		internal static void Forget(GameObject go)
		{
			_active.Remove(go);
		}

		private static Material BeamMaterial()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			if ((Object)(object)_beamMat == (Object)null)
			{
				_beamMat = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Standard"))
				{
					renderQueue = 4000
				};
			}
			return _beamMat;
		}

		private static void BuildBeam(GameObject root, Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_009a: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			Vector3 a = pos + Vector3.up * 0.4f;
			Vector3 b = pos + Vector3.up * 40.4f;
			AddLine(root, "Halo", a, b, 1.4f, 0.5f, new Color(CyanCore.r, CyanCore.g, CyanCore.b, 0.22f), new Color(CyanTop.r, CyanTop.g, CyanTop.b, 0.03f));
			AddLine(root, "Core", a, b, 0.55f, 0.12f, CyanCore, CyanTop);
		}

		private static void AddLine(GameObject parent, string name, Vector3 a, Vector3 b, float wBottom, float wTop, Color cBottom, Color cTop)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent.transform, false);
			LineRenderer obj = val.AddComponent<LineRenderer>();
			obj.useWorldSpace = true;
			obj.positionCount = 2;
			obj.SetPosition(0, a);
			obj.SetPosition(1, b);
			obj.startWidth = wBottom;
			obj.endWidth = wTop;
			obj.numCapVertices = 4;
			obj.alignment = (LineAlignment)0;
			((Renderer)obj).sharedMaterial = BeamMaterial();
			obj.startColor = cBottom;
			obj.endColor = cTop;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			((Renderer)obj).lightProbeUsage = (LightProbeUsage)0;
		}

		private static void BuildIcon(GameObject root, Vector3 chestPos, Vector3 viewer, Sprite? icon)
		{
			//IL_000a: 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_0011: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)icon == (Object)null))
			{
				Vector3 val = viewer - chestPos;
				val.y = 0f;
				val = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val)).normalized : Vector3.forward);
				Vector3 position = chestPos + val * 0.6f + Vector3.up * 0.35f;
				GameObject val2 = new GameObject("Icon");
				val2.transform.SetParent(root.transform, false);
				val2.transform.position = position;
				SpriteRenderer val3 = val2.AddComponent<SpriteRenderer>();
				val3.sprite = icon;
				val3.color = new Color(0.6f, 0.9f, 1f, 1f);
				((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
				Bounds bounds = val3.sprite.bounds;
				float num = Mathf.Max(0.01f, ((Bounds)(ref bounds)).size.x);
				val2.transform.localScale = Vector3.one * (0.7f / num);
				val2.AddComponent<MarkerBillboard>();
			}
		}
	}
	public class MarkerLifetime : MonoBehaviour
	{
		private float _duration = 30f;

		private float _remaining;

		private bool _running;

		public void Init(float seconds)
		{
			_duration = Mathf.Max(0.5f, seconds);
		}

		public void Begin()
		{
			_remaining = _duration;
			_running = true;
		}

		private void Update()
		{
			if (_running)
			{
				_remaining -= Time.deltaTime;
				if (_remaining <= 0f)
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
			}
		}

		private void OnDestroy()
		{
			StorageMarkers.Forget(((Component)this).gameObject);
		}
	}
	public class MarkerBillboard : MonoBehaviour
	{
		private float _baseScale = 1f;

		private SpriteRenderer? _sr;

		private void Start()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			_baseScale = ((Component)this).transform.localScale.x;
			_sr = ((Component)this).GetComponent<SpriteRenderer>();
		}

		private void LateUpdate()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			Camera val = Utils.GetMainCamera();
			if ((Object)(object)val == (Object)null)
			{
				val = Camera.main;
			}
			if ((Object)(object)val != (Object)null)
			{
				((Component)this).transform.rotation = ((Component)val).transform.rotation;
			}
			float num = 0.5f + 0.5f * Mathf.Sin(Time.time * 5f);
			((Component)this).transform.localScale = Vector3.one * (_baseScale * (0.9f + 0.15f * num));
			if ((Object)(object)_sr != (Object)null)
			{
				Color color = _sr.color;
				color.a = 0.7f + 0.3f * num;
				_sr.color = color;
			}
		}
	}
	public class StorageRowHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		private Image? _bg;

		private static readonly Color Normal = new Color(1f, 1f, 1f, 0f);

		private static readonly Color Hover = new Color(1f, 1f, 1f, 0.12f);

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			_bg = ((Component)this).GetComponent<Image>();
			if ((Object)(object)_bg != (Object)null)
			{
				((Graphic)_bg).color = Normal;
			}
		}

		public void OnPointerEnter(PointerEventData eventData)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_bg != (Object)null)
			{
				((Graphic)_bg).color = Hover;
			}
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_bg != (Object)null)
			{
				((Graphic)_bg).color = Normal;
			}
		}
	}
	public class StorageEntry
	{
		public string Token = string.Empty;

		public string Name = string.Empty;

		public int Count;

		public Sprite? Icon;
	}
	public class StorageSnapshot
	{
		public List<StorageEntry> Entries = new List<StorageEntry>();

		public int ChestCount;

		public int TotalItems;

		public int TotalSlots;

		public int UsedSlots;

		public int AlmostFullChests;
	}
	public static class StorageScanner
	{
		[CompilerGenerated]
		private sealed class <NearbyChests>d__0 : IEnumerable<Container>, IEnumerable, IEnumerator<Container>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private Container <>2__current;

			private int <>l__initialThreadId;

			private float radius;

			public float <>3__radius;

			private Vector3 center;

			public Vector3 <>3__center;

			private float <radiusSqr>5__2;

			private Container[] <>7__wrap2;

			private int <>7__wrap3;

			Container IEnumerator<Container>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <NearbyChests>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>7__wrap2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_009a: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_00d1;
				}
				<>1__state = -1;
				<radiusSqr>5__2 = radius * radius;
				Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
				<>7__wrap2 = array;
				<>7__wrap3 = 0;
				goto IL_00df;
				IL_00d1:
				<>7__wrap3++;
				goto IL_00df;
				IL_00df:
				if (<>7__wrap3 < <>7__wrap2.Length)
				{
					Container val = <>7__wrap2[<>7__wrap3];
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val.m_nview == (Object)null) && val.m_nview.IsValid() && !(((Object)val).name ?? string.Empty).StartsWith("TreasureChest"))
					{
						Vector3 val2 = ((Component)val).transform.position - center;
						if (!(((Vector3)(ref val2)).sqrMagnitude > <radiusSqr>5__2))
						{
							<>2__current = val;
							<>1__state = 1;
							return true;
						}
					}
					goto IL_00d1;
				}
				<>7__wrap2 = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<Container> IEnumerable<Container>.GetEnumerator()
			{
				//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)
				<NearbyChests>d__0 <NearbyChests>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<NearbyChests>d__ = this;
				}
				else
				{
					<NearbyChests>d__ = new <NearbyChests>d__0(0);
				}
				<NearbyChests>d__.center = <>3__center;
				<NearbyChests>d__.radius = <>3__radius;
				return <NearbyChests>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<Container>)this).GetEnumerator();
			}
		}

		[IteratorStateMachine(typeof(<NearbyChests>d__0))]
		public static IEnumerable<Container> NearbyChests(Vector3 center, float radius)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <NearbyChests>d__0(-2)
			{
				<>3__center = center,
				<>3__radius = radius
			};
		}

		public static StorageSnapshot AggregateNearby(Vector3 center, float radius)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, StorageEntry> dictionary = new Dictionary<string, StorageEntry>();
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			foreach (Container item in NearbyChests(center, radius))
			{
				Inventory inventory = item.GetInventory();
				if (inventory == null)
				{
					continue;
				}
				List<ItemData> allItems = inventory.GetAllItems();
				num++;
				int num5 = inventory.GetWidth() * inventory.GetHeight();
				int emptySlots = inventory.GetEmptySlots();
				num2 += num5;
				num3 += num5 - emptySlots;
				if (emptySlots <= 1)
				{
					num4++;
				}
				foreach (ItemData item2 in allItems)
				{
					if (item2?.m_shared == null)
					{
						continue;
					}
					string name = item2.m_shared.m_name;
					if (!dictionary.TryGetValue(name, out var value))
					{
						string text = ((Localization.instance != null) ? Localization.instance.Localize(name) : name);
						if (string.IsNullOrEmpty(text))
						{
							text = name;
						}
						Sprite icon = ((item2.m_shared.m_icons != null && item2.m_shared.m_icons.Length != 0) ? item2.m_shared.m_icons[0] : null);
						value = (dictionary[name] = new StorageEntry
						{
							Token = name,
							Name = text,
							Icon = icon
						});
					}
					value.Count += item2.m_stack;
				}
			}
			List<StorageEntry> list = dictionary.Values.OrderByDescending((StorageEntry e) => e.Count).ToList();
			int totalItems = list.Sum((StorageEntry e) => e.Count);
			return new StorageSnapshot
			{
				Entries = list,
				ChestCount = num,
				TotalItems = totalItems,
				TotalSlots = num2,
				UsedSlots = num3,
				AlmostFullChests = num4
			};
		}

		public static void Scan()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			float value = Plugin.Radius.Value;
			StorageSnapshot storageSnapshot = AggregateNearby(((Component)localPlayer).transform.position, value);
			Plugin.Log.LogInfo((object)$"=== Storage scan within {value:0.#} m ===");
			foreach (StorageEntry entry in storageSnapshot.Entries)
			{
				Plugin.Log.LogInfo((object)$"{entry.Name}: {entry.Count}");
			}
			Plugin.Log.LogInfo((object)$"=== {storageSnapshot.ChestCount} chests, {storageSnapshot.Entries.Count} item types, {storageSnapshot.TotalItems} items total ===");
		}
	}
	public class StorageTerminal : MonoBehaviour, Interactable, Hoverable
	{
		public string GetHoverName()
		{
			return "Odin Terminal";
		}

		public string GetHoverText()
		{
			if (Localization.instance == null)
			{
				return "[E] Open Storage";
			}
			return Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] Open Storage");
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (hold)
			{
				return false;
			}
			StorageTerminalUI.Open(((Component)this).transform.position);
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}
	}
	public static class StorageTerminalUI
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Close;

			public static UnityAction <1>__DoDeposit;

			public static UnityAction <2>__OnCleanupClicked;

			public static UnityAction<string> <3>__OnSearchChanged;

			public static UnityAction <4>__ConfirmCleanup;

			public static UnityAction <5>__CancelCleanup;
		}

		private const string CatAll = "all";

		private const string CatOre = "ore";

		private const string CatFood = "food";

		private const string CatMaterial = "material";

		private const float NameMinWidth = 40f;

		private const float CountColWidth = 52f;

		private const float NameCountGap = 10f;

		private static readonly List<(Text Label, string Full)> _nameLabels = new List<(Text, string)>();

		private static GameObject? _panel;

		private static InputField? _search;

		private static Text? _header;

		private static Transform? _content;

		private static GameObject? _confirmPanel;

		private static Text? _confirmText;

		private static RectTransform? _fillRt;

		private static Image? _fillImg;

		private static readonly List<GameObject> _rows = new List<GameObject>();

		private static readonly List<string> _order = new List<string>();

		private static readonly Dictionary<string, StorageEntry> _entries = new Dictionary<string, StorageEntry>();

		private static string _query = string.Empty;

		private static string _category = "all";

		private static Vector3 _center;

		private static readonly string[] OreWords = new string[8] { "copper", "tin", "bronze", "iron", "silver", "blackmetal", "flametal", "ore" };

		private static readonly string[] FoodWords = new string[18]
		{
			"carrot", "mushroom", "raspberr", "blueberr", "cloudberr", "honey", "meat", "fish", "cooked", "bread",
			"mead", "sausage", "stew", "soup", "turnip", "onion", "jam", "pie"
		};

		public static bool IsOpen
		{
			get
			{
				if ((Object)(object)_panel != (Object)null)
				{
					return _panel.activeSelf;
				}
				return false;
			}
		}

		public static void Create()
		{
			//IL_0035: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_00b4: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: 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_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Expected O, but got Unknown
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Expected O, but got Unknown
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0441: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_panel != (Object)null) && GUIManager.Instance != null && !GUIManager.IsHeadless())
			{
				_panel = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 500f, 600f, true);
				_panel.SetActive(false);
				Text component = GUIManager.Instance.CreateText("Storage", _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -28f), GUIManager.Instance.AveriaSerifBold, 26, GUIManager.Instance.ValheimOrange, true, Color.black, 140f, 36f, false).GetComponent<Text>();
				if ((Object)(object)component != (Object)null)
				{
					component.alignment = (TextAnchor)4;
					component.horizontalOverflow = (HorizontalWrapMode)1;
				}
				ButtonClickedEvent onClick = GUIManager.Instance.CreateButton("X", _panel.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-30f, -28f), 40f, 40f).GetComponent<Button>().onClick;
				object obj = <>O.<0>__Close;
				if (obj == null)
				{
					UnityAction val = Close;
					<>O.<0>__Close = val;
					obj = (object)val;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj);
				GameObject obj2 = GUIManager.Instance.CreateButton("Deposit", _panel.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(65f, -28f), 110f, 32f);
				Text componentInChildren = obj2.GetComponentInChildren<Text>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.fontSize = 15;
				}
				ButtonClickedEvent onClick2 = obj2.GetComponent<Button>().onClick;
				object obj3 = <>O.<1>__DoDeposit;
				if (obj3 == null)
				{
					UnityAction val2 = DoDeposit;
					<>O.<1>__DoDeposit = val2;
					obj3 = (object)val2;
				}
				((UnityEvent)onClick2).AddListener((UnityAction)obj3);
				GameObject obj4 = GUIManager.Instance.CreateButton("Consolidate", _panel.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-145f, -28f), 110f, 32f);
				Text componentInChildren2 = obj4.GetComponentInChildren<Text>();
				if ((Object)(object)componentInChildren2 != (Object)null)
				{
					componentInChildren2.fontSize = 13;
				}
				ButtonClickedEvent onClick3 = obj4.GetComponent<Button>().onClick;
				object obj5 = <>O.<2>__OnCleanupClicked;
				if (obj5 == null)
				{
					UnityAction val3 = OnCleanupClicked;
					<>O.<2>__OnCleanupClicked = val3;
					obj5 = (object)val3;
				}
				((UnityEvent)onClick3).AddListener((UnityAction)obj5);
				BuildConfirmDialog(_panel.transform);
				_header = GUIManager.Instance.CreateText(string.Empty, _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -70f), GUIManager.Instance.AveriaSerifBold, 14, GUIManager.Instance.ValheimBeige, true, Color.black, 460f, 38f, false).GetComponent<Text>();
				if ((Object)(object)_header != (Object)null)
				{
					_header.alignment = (TextAnchor)1;
				}
				BuildFillBar(_panel.transform);
				_search = GUIManager.Instance.CreateInputField(_panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -120f), (ContentType)0, "Search…", 16, 440f, 32f).GetComponent<InputField>();
				((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)OnSearchChanged);
				BuildFilterBar(_panel.transform);
				GameObject obj6 = GUIManager.Instance.CreateScrollView(_panel.transform, false, true, 0.6f, 0f, GUIManager.Instance.ValheimScrollbarHandleColorBlock, new Color(0f, 0f, 0f, 0.2f), 460f, 395f);
				RectTransform component2 = obj6.GetComponent<RectTransform>();
				component2.anchorMin = new Vector2(0.5f, 0f);
				component2.anchorMax = new Vector2(0.5f, 0f);
				component2.pivot = new Vector2(0.5f, 0f);
				component2.anchoredPosition = new Vector2(0f, 20f);
				_content = (Transform?)(object)obj6.GetComponentInChildren<ScrollRect>().content;
				VerticalLayoutGroup val4 = ((Component)_content).gameObject.GetComponent<VerticalLayoutGroup>();
				if ((Object)(object)val4 == (Object)null)
				{
					val4 = ((Component)_content).gameObject.AddComponent<VerticalLayoutGroup>();
				}
				((HorizontalOrVerticalLayoutGroup)val4).spacing = 4f;
				((HorizontalOrVerticalLayoutGroup)val4).childControlWidth = true;
				((HorizontalOrVerticalLayoutGroup)val4).childControlHeight = true;
				((HorizontalOrVerticalLayoutGroup)val4).childForceExpandWidth = true;
				((HorizontalOrVerticalLayoutGroup)val4).childForceExpandHeight = false;
				ContentSizeFitter val5 = ((Component)_content).gameObject.GetComponent<ContentSizeFitter>();
				if ((Object)(object)val5 == (Object)null)
				{
					val5 = ((Component)_content).gameObject.AddComponent<ContentSizeFitter>();
				}
				val5.verticalFit = (FitMode)2;
				ApplyUiScale();
			}
		}

		private static void ApplyUiScale()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_panel == (Object)null))
			{
				float num = Mathf.Clamp((float)Screen.height / 1080f, 0.8f, 2.5f);
				_panel.transform.localScale = new Vector3(num, num, 1f);
			}
		}

		private static void BuildFilterBar(Transform parent)
		{
			//IL_0018: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("OdinFilterBar", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 1f);
			component.anchorMax = new Vector2(0.5f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = new Vector2(0f, -156f);
			component.sizeDelta = new Vector2(460f, 30f);
			HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 6f;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = true;
			AddFilterButton(val.transform, "All", "all");
			AddFilterButton(val.transform, "Ore/Metal", "ore");
			AddFilterButton(val.transform, "Food", "food");
			AddFilterButton(val.transform, "Materials", "material");
		}

		private static void AddFilterButton(Transform parent, string label, string category)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			string category2 = category;
			GameObject val = GUIManager.Instance.CreateButton(label, parent, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 100f, 28f);
			Text componentInChildren = val.GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.fontSize = 14;
			}
			LayoutElement val2 = val.GetComponent<LayoutElement>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = val.AddComponent<LayoutElement>();
			}
			val2.flexibleWidth = 1f;
			((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				SetCategory(category2);
			});
		}

		public static void Open(Vector3 center)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panel == (Object)null)
			{
				return;
			}
			_center = center;
			StorageMarkers.Clear();
			_query = string.Empty;
			_category = "all";
			if ((Object)(object)_search != (Object)null)
			{
				_search.text = string.Empty;
			}
			StorageSnapshot storageSnapshot = StorageScanner.AggregateNearby(_center, Plugin.Radius.Value);
			_order.Clear();
			_entries.Clear();
			foreach (StorageEntry entry in storageSnapshot.Entries)
			{
				_order.Add(entry.Token);
				_entries[entry.Token] = entry;
			}
			UpdateHeader(storageSnapshot);
			ApplyUiScale();
			_panel.SetActive(true);
			GUIManager.BlockInput(true);
			ApplyFilters();
		}

		public static void Refresh()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOpen)
			{
				return;
			}
			StorageSnapshot storageSnapshot = StorageScanner.AggregateNearby(_center, Plugin.Radius.Value);
			Dictionary<string, StorageEntry> dictionary = new Dictionary<string, StorageEntry>();
			foreach (StorageEntry entry in storageSnapshot.Entries)
			{
				dictionary[entry.Token] = entry;
			}
			foreach (string item in _order)
			{
				StorageEntry value2;
				if (dictionary.TryGetValue(item, out var value))
				{
					_entries[item] = value;
				}
				else if (_entries.TryGetValue(item, out value2))
				{
					value2.Count = 0;
				}
			}
			foreach (StorageEntry entry2 in storageSnapshot.Entries)
			{
				if (!_entries.ContainsKey(entry2.Token))
				{
					_order.Add(entry2.Token);
					_entries[entry2.Token] = entry2;
				}
			}
			UpdateHeader(storageSnapshot);
			ApplyFilters();
		}

		private static void BuildFillBar(Transform parent)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_009c: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("OdinFillBarBg", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 1f);
			component.anchorMax = new Vector2(0.5f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = new Vector2(0f, -96f);
			component.sizeDelta = new Vector2(440f, 6f);
			((Graphic)val.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.5f);
			GameObject val2 = new GameObject("OdinFillBarFill", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val2.transform.SetParent(val.transform, false);
			_fillRt = val2.GetComponent<RectTransform>();
			_fillRt.anchorMin = new Vector2(0f, 0f);
			_fillRt.anchorMax = new Vector2(0f, 1f);
			_fillRt.pivot = new Vector2(0f, 0.5f);
			_fillRt.offsetMin = Vector2.zero;
			_fillRt.offsetMax = Vector2.zero;
			_fillImg = val2.GetComponent<Image>();
			((Graphic)_fillImg).color = new Color(0.3f, 0.8f, 0.3f, 1f);
		}

		private static void UpdateHeader(StorageSnapshot snap)
		{
			//IL_0101: 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)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			int totalSlots = snap.TotalSlots;
			int usedSlots = snap.UsedSlots;
			float num = ((totalSlots > 0) ? ((float)usedSlots / (float)totalSlots) : 0f);
			int num2 = Mathf.RoundToInt(num * 100f);
			if ((Object)(object)_header != (Object)null)
			{
				string text = $"{snap.ChestCount} chests · {snap.Entries.Count} types · {snap.TotalItems} items";
				string text2 = $"{usedSlots} / {totalSlots} slots · {num2}%";
				if (snap.AlmostFullChests == 1)
				{
					text2 += " · 1 chest nearly full";
				}
				else if (snap.AlmostFullChests > 1)
				{
					text2 += $" · {snap.AlmostFullChests} chests nearly full";
				}
				_header.text = text + "\n" + text2;
			}
			if ((Object)(object)_fillRt != (Object)null)
			{
				_fillRt.anchorMax = new Vector2(Mathf.Clamp01(num), 1f);
				_fillRt.offsetMin = Vector2.zero;
				_fillRt.offsetMax = Vector2.zero;
			}
			if ((Object)(object)_fillImg != (Object)null)
			{
				((Graphic)_fillImg).color = ((num >= 0.9f) ? new Color(0.85f, 0.25f, 0.2f, 1f) : ((num >= 0.75f) ? new Color(0.9f, 0.8f, 0.2f, 1f) : new Color(0.3f, 0.8f, 0.3f, 1f)));
			}
		}

		public static void Close()
		{
			if (!((Object)(object)_panel == (Object)null))
			{
				_panel.SetActive(false);
				GUIManager.BlockInput(false);
				StorageMarkers.StartTimers();
			}
		}

		private static void OnSearchChanged(string query)
		{
			_query = query ?? string.Empty;
			ApplyFilters();
		}

		private static void SetCategory(string category)
		{
			_category = category;
			ApplyFilters();
		}

		private static void ApplyFilters()
		{
			List<StorageEntry> list = new List<StorageEntry>();
			foreach (string item in _order)
			{
				if (_entries.TryGetValue(item, out StorageEntry value) && value.Count > 0)
				{
					list.Add(value);
				}
			}
			IEnumerable<StorageEntry> source = list;
			if (_category != "all")
			{
				source = source.Where((StorageEntry e) => Classify(e.Token) == _category);
			}
			if (!string.IsNullOrEmpty(_query))
			{
				string q = _query.ToLowerInvariant();
				source = source.Where((StorageEntry e) => e.Name.ToLowerInvariant().Contains(q));
			}
			RebuildRows(source.ToList());
		}

		private static string Classify(string token)
		{
			string t = token.ToLowerInvariant();
			if (OreWords.Any((string w) => t.Contains(w)))
			{
				return "ore";
			}
			if (FoodWords.Any((string w) => t.Contains(w)))
			{
				return "food";
			}
			return "material";
		}

		private static void RebuildRows(List<StorageEntry> entries)
		{
			if ((Object)(object)_content == (Object)null)
			{
				return;
			}
			foreach (GameObject row in _rows)
			{
				Object.Destroy((Object)(object)row);
			}
			_rows.Clear();
			_nameLabels.Clear();
			foreach (StorageEntry entry in entries)
			{
				_rows.Add(CreateRow(entry));
			}
			FitNameLabels();
		}

		private static void FitNameLabels()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_005e: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_content == (Object)null || _nameLabels.Count == 0)
			{
				return;
			}
			Canvas.ForceUpdateCanvases();
			LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)_content);
			foreach (var (val, s) in _nameLabels)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Rect rect = ((RectTransform)((Component)val).transform).rect;
					float num = ((Rect)(ref rect)).width - 10f;
					if (!(num <= 1f))
					{
						val.horizontalOverflow = (HorizontalWrapMode)1;
						val.text = TruncateToWidth(val, s, num);
					}
				}
			}
		}

		private static GameObject CreateRow(StorageEntry e)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_004a: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: 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_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("OdinRow", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(_content, false);
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).color = new Color(1f, 1f, 1f, 0f);
			((Graphic)obj).raycastTarget = true;
			HorizontalLayoutGroup obj2 = val.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 8f;
			((LayoutGroup)obj2).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			LayoutElement obj3 = val.AddComponent<LayoutElement>();
			obj3.minHeight = 34f;
			obj3.preferredHeight = 34f;
			GameObject val2 = new GameObject("Icon", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val2.transform.SetParent(val.transform, false);
			Image component = val2.GetComponent<Image>();
			if ((Object)(object)e.Icon != (Object)null)
			{
				component.sprite = e.Icon;
				component.preserveAspect = true;
			}
			else
			{
				((Behaviour)component).enabled = false;
			}
			LayoutElement obj4 = val2.AddComponent<LayoutElement>();
			obj4.minWidth = 32f;
			obj4.preferredWidth = 32f;
			obj4.minHeight = 32f;
			obj4.preferredHeight = 32f;
			AddFindButton(val.transform, 56f, e.Token, e.Icon);
			GameObject val3 = GUIManager.Instance.CreateText(e.Name, val.transform, new Vector2(0f, 0.5f), new Vector2(1f, 0.5f), Vector2.zero, GUIManager.Instance.AveriaSerifBold, 18, Color.white, true, Color.black, 40f, 30f, false);
			Text component2 = val3.GetComponent<Text>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.alignment = (TextAnchor)3;
				component2.horizontalOverflow = (HorizontalWrapMode)0;
				component2.verticalOverflow = (VerticalWrapMode)0;
				_nameLabels.Add((component2, e.Name));
			}
			LayoutElement val4 = val3.GetComponent<LayoutElement>();
			if ((Object)(object)val4 == (Object)null)
			{