Decompiled source of Safe Pouch v0.3.2

BepInEx/plugins/SafePouch/SafePouch.dll

Decompiled a day 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 BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SafePouch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.1.0")]
[assembly: AssemblyInformationalVersion("0.3.1")]
[assembly: AssemblyProduct("SafePouch")]
[assembly: AssemblyTitle("SafePouch")]
[assembly: AssemblyVersion("0.3.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 SafePouch
{
	[BepInPlugin("local.valheim.safepouch", "Safe Pouch", "0.3.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Player), "Load")]
		private static class LoadPatch
		{
			private static void Postfix(Player __instance)
			{
				Instance._states.Remove(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "Save")]
		private static class SavePatch
		{
			private static void Prefix(Player __instance)
			{
				if (Instance._states.TryGetValue(__instance, out PouchState value))
				{
					value.Store();
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "GetTotalWeight")]
		private static class WeightPatch
		{
			private static void Postfix(Inventory __instance, ref float __result)
			{
				Player localPlayer = Player.m_localPlayer;
				if (Object.op_Implicit((Object)(object)localPlayer) && __instance == ((Humanoid)localPlayer).GetInventory())
				{
					__result += Instance.State(localPlayer).Inventory.GetAllItems().Sum((ItemData i) => i.GetWeight(-1)) * ((float)Instance.WeightPercent.Value / 100f);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
		private static class SelectedPatch
		{
			private static bool Prefix(InventoryGui __instance, InventoryGrid grid, Vector2i pos)
			{
				//IL_005b: 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)
				PouchState current = Current;
				if (current == null || Drag.Inventory(__instance) != current.Inventory)
				{
					return true;
				}
				Inventory inventory = grid.GetInventory();
				if (inventory != ((Humanoid)Player.m_localPlayer).GetInventory())
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, "Move pouch items into your inventory first.", 0, (Sprite)null, false);
					return false;
				}
				ItemData val = Drag.Item(__instance);
				if (val != null)
				{
					current.Transfer(current.Inventory, inventory, val, Drag.Amount(__instance), pos.x, pos.y);
				}
				Drag.Clear(__instance);
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static class ContainerUpdatePatch
		{
			private static void Prefix(ref Inventory? ___m_dragInventory, out Inventory? __state)
			{
				__state = null;
				PouchState current = Current;
				if (current != null && ___m_dragInventory == current.Inventory)
				{
					__state = ___m_dragInventory;
					___m_dragInventory = null;
				}
			}

			private static void Postfix(ref Inventory? ___m_dragInventory, ItemData? ___m_dragItem, Inventory? __state)
			{
				if (__state != null && ___m_dragItem != null && ___m_dragInventory == null)
				{
					___m_dragInventory = __state;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnDropOutside")]
		private static class OutsidePatch
		{
			private static bool Prepare()
			{
				return AccessTools.Method(typeof(InventoryGui), "OnDropOutside", (Type[])null, (Type[])null) != null;
			}

			private static bool Prefix(InventoryGui __instance)
			{
				PouchState current = Current;
				if (current == null || Drag.Inventory(__instance) != current.Inventory)
				{
					return true;
				}
				Drag.Clear(__instance);
				return false;
			}
		}

		public const string Id = "local.valheim.safepouch";

		internal static Plugin Instance;

		private Harmony _harmony;

		private PouchUi? _ui;

		private bool _uiFailed;

		internal ConfigEntry<float> PouchGap;

		internal ConfigEntry<float> VerticalOffset;

		internal ConfigEntry<int> WeightPercent;

		internal ConfigEntry<int> SlotCount;

		private readonly ConditionalWeakTable<Player, PouchState> _states = new ConditionalWeakTable<Player, PouchState>();

		internal static PouchState? Current
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					return null;
				}
				return Instance.State(Player.m_localPlayer);
			}
		}

		private void Awake()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			Instance = this;
			SlotCount = ((BaseUnityPlugin)this).Config.Bind<int>("Pouch", "SlotCount", 4, new ConfigDescription("Number of pouch slots (1-28), wrapping after seven per row. Restart required. Occupied slots beyond a reduced count remain withdrawal-only until emptied.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 28), Array.Empty<object>()));
			WeightPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Pouch", "WeightPercent", 100, new ConfigDescription("Percentage of normal item weight counted while inside the pouch: 0 = weightless, 50 = half weight, 100 = normal weight. Withdrawn items always use normal weight.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			PouchGap = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "Gap", 8f, new ConfigDescription("Space below the visible inventory panel in UI units.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
			VerticalOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "VerticalOffset", 0f, new ConfigDescription("Additional pouch offset in UI units. Positive moves down; negative moves up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-500f, 500f), Array.Empty<object>()));
			_harmony = new Harmony("local.valheim.safepouch");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Safe Pouch 0.3.1 loaded: configurable client-only slots.");
		}

		internal PouchState State(Player player)
		{
			return _states.GetValue(player, (Player p) => new PouchState(p, SlotCount.Value));
		}

		internal void Report(Exception error)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)error);
		}

		private void LateUpdate()
		{
			if (_uiFailed || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)InventoryGui.instance))
			{
				return;
			}
			try
			{
				PouchState pouchState = State(Player.m_localPlayer);
				if (_ui == null || !_ui.Alive || _ui.SlotCount != pouchState.VisibleSlots)
				{
					_ui?.Destroy();
					_ui = new PouchUi(InventoryGui.instance, pouchState.VisibleSlots);
				}
				_ui.Refresh(pouchState);
			}
			catch (Exception error)
			{
				_uiFailed = true;
				_ui?.Destroy();
				Report(error);
				((BaseUnityPlugin)this).Logger.LogError((object)"Pouch UI disabled for this session. Saved contents are retained.");
			}
		}

		private void OnDestroy()
		{
			_ui?.Destroy();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class Drag
	{
		internal static ItemData? Item(InventoryGui gui)
		{
			return Traverse.Create((object)gui).Field("m_dragItem").GetValue<ItemData>();
		}

		internal static Inventory? Inventory(InventoryGui gui)
		{
			return Traverse.Create((object)gui).Field("m_dragInventory").GetValue<Inventory>();
		}

		internal static int Amount(InventoryGui gui)
		{
			return Traverse.Create((object)gui).Field("m_dragAmount").GetValue<int>();
		}

		internal static void Set(InventoryGui gui, ItemData? item, Inventory? inventory, int amount)
		{
			AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null).Invoke(gui, new object[3] { item, inventory, amount });
		}

		internal static void Clear(InventoryGui gui)
		{
			Set(gui, null, null, 1);
		}
	}
	internal static class PouchSave
	{
		internal static string Encode(int[] counts, string payload)
		{
			Validate(counts);
			return "v3|" + string.Join(",", counts) + "|" + payload;
		}

		internal static (int[] Counts, string Payload) Decode(string data)
		{
			string[] array = data.Split('|');
			if (array.Length != 3 || (array[0] != "v2" && array[0] != "v3"))
			{
				throw new FormatException("Unknown pouch save format.");
			}
			int[] array2 = array[1].Split(',').Select(int.Parse).ToArray();
			if (array[0] == "v2" && array2.Length != 4)
			{
				throw new FormatException("Invalid legacy slot count.");
			}
			Validate(array2);
			return (Counts: array2, Payload: array[2]);
		}

		private static void Validate(int[] counts)
		{
			if (counts.Length < 1 || counts.Length > 28 || counts.Any((int c) => c < 0 || c > 99999))
			{
				throw new FormatException("Invalid pouch stack counts.");
			}
		}
	}
	internal sealed class PouchState
	{
		private const string Key = "local.valheim.safepouch.inventory.v1";

		internal readonly Inventory Inventory = new Inventory("Safe Pouch", (Sprite)null, 28, 1);

		private readonly Player _player;

		internal int ConfiguredSlots { get; }

		internal int VisibleSlots => Math.Min(28, Math.Max(ConfiguredSlots, (from i in Inventory.GetAllItems()
			select i.m_gridPos.x + 1).DefaultIfEmpty(0).Max()));

		internal bool Locked { get; private set; }

		internal PouchState(Player player, int slotCount = 4)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected O, but got Unknown
			ConfiguredSlots = Math.Max(1, Math.Min(28, slotCount));
			_player = player;
			if (!player.m_customData.TryGetValue("local.valheim.safepouch.inventory.v1", out var value))
			{
				return;
			}
			try
			{
				int[] array = null;
				int num;
				int num2;
				if (value.StartsWith("v2|", StringComparison.Ordinal) || value.StartsWith("v3|", StringComparison.Ordinal))
				{
					(int[], string) tuple = PouchSave.Decode(value);
					array = tuple.Item1;
					num = array.Count((int c) => c > 0);
					num2 = array.Sum();
					Inventory.Load(new ZPackage(tuple.Item2));
				}
				else
				{
					int num3 = value.IndexOf(':');
					string[] array2 = value.Substring(0, num3).Split(',');
					num = int.Parse(array2[0]);
					num2 = int.Parse(array2[1]);
					Inventory.Load(new ZPackage(value.Substring(num3 + 1)));
				}
				List<ItemData> allItems = Inventory.GetAllItems();
				int savedSlots = ((array != null) ? array.Length : 4);
				if (allItems.Count != num || allItems.Count > savedSlots || allItems.Select((ItemData i) => i.m_gridPos.x).Distinct().Count() != allItems.Count || allItems.Any((ItemData i) => i.m_gridPos.x < 0 || i.m_gridPos.x >= savedSlots || i.m_gridPos.y != 0))
				{
					throw new InvalidOperationException("Pouch data could not be restored completely. Original data retained; restore missing item mods before using this pouch.");
				}
				if (array != null)
				{
					foreach (ItemData item in allItems)
					{
						if (item.m_stack != 1 || array[item.m_gridPos.x] < 1)
						{
							throw new FormatException("Invalid pouch representative item.");
						}
						item.m_stack = array[item.m_gridPos.x];
					}
				}
				if (allItems.Sum((ItemData i) => i.m_stack) != num2 || allItems.Any((ItemData i) => i.m_stack < 1 || i.m_stack > SlotRules.PouchCapacity(i.m_shared.m_teleportable, i.m_shared.m_maxStackSize)))
				{
					throw new FormatException("Invalid pouch item counts. Original data retained.");
				}
			}
			catch (Exception error)
			{
				Locked = true;
				Plugin.Instance.Report(error);
			}
		}

		internal void Store()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			if (Locked)
			{
				return;
			}
			int[] array = new int[VisibleSlots];
			Inventory val = new Inventory("Safe Pouch save", (Sprite)null, 28, 1);
			foreach (ItemData allItem in Inventory.GetAllItems())
			{
				array[allItem.m_gridPos.x] = allItem.m_stack;
				ItemData val2 = allItem.Clone();
				val2.m_stack = 1;
				val.GetAllItems().Add(val2);
			}
			ZPackage val3 = new ZPackage();
			val.Save(val3);
			_player.m_customData["local.valheim.safepouch.inventory.v1"] = PouchSave.Encode(array, val3.GetBase64());
		}

		internal int Transfer(Inventory source, Inventory target, ItemData item, int requested, int x, int y)
		{
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			if (Locked || ((Character)_player).IsDead() || ((Character)_player).IsTeleporting() || !source.ContainsItem(item) || x < 0 || y < 0 || x >= target.GetWidth() || y >= target.GetHeight())
			{
				return 0;
			}
			if (target == Inventory && x >= ConfiguredSlots)
			{
				return 0;
			}
			ItemData itemAt = target.GetItemAt(x, y);
			if (itemAt == item)
			{
				return 0;
			}
			int maxStack = ((target == Inventory) ? SlotRules.PouchCapacity(item.m_shared.m_teleportable, item.m_shared.m_maxStackSize) : item.m_shared.m_maxStackSize);
			int num = SlotRules.TransferAmount(restricted: false, maxStack, itemAt?.m_stack ?? 0, itemAt == null || itemAt.IsSameType(item), item.m_stack, requested);
			if (num == 0)
			{
				return 0;
			}
			((Humanoid)_player).RemoveEquipAction(item);
			((Humanoid)_player).UnequipItem(item, false);
			if (target == Inventory)
			{
				if (itemAt == null)
				{
					ItemData val = item.Clone();
					val.m_stack = num;
					val.m_equipped = false;
					val.m_gridPos = new Vector2i(x, y);
					target.GetAllItems().Add(val);
				}
				else
				{
					itemAt.m_stack += num;
				}
				source.RemoveItem(item, num);
				Store();
				return num;
			}
			int stack = item.m_stack;
			target.MoveItemToThis(source, item, num, x, y);
			int result = stack - item.m_stack;
			Store();
			return result;
		}

		internal void Withdraw(ItemData item)
		{
			Inventory inventory = ((Humanoid)_player).GetInventory();
			for (int i = 0; i < 2; i++)
			{
				if (!Inventory.ContainsItem(item))
				{
					break;
				}
				for (int j = 0; j < inventory.GetHeight(); j++)
				{
					if (!Inventory.ContainsItem(item))
					{
						break;
					}
					for (int k = 0; k < inventory.GetWidth(); k++)
					{
						if (!Inventory.ContainsItem(item))
						{
							break;
						}
						if (inventory.GetItemAt(k, j) == null == (i == 1))
						{
							Transfer(Inventory, inventory, item, item.m_stack, k, j);
						}
					}
				}
			}
		}
	}
	internal sealed class PouchUi
	{
		private readonly InventoryGui _gui;

		private readonly GameObject _panel;

		private readonly Image _background;

		private Image? _inventoryBackground;

		private readonly InventoryElement[] _slots;

		private readonly TMP_Text _status;

		private PouchState? _state;

		private readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4];

		private readonly List<Button> _inventoryButtons = new List<Button>();

		private static readonly string[] BackgroundPaths = new string[4] { "Bkg", "Background", "Darken", "selected_frame/selected (1)" };

		internal int SlotCount => _slots.Length;

		internal bool Alive
		{
			get
			{
				if (Object.op_Implicit((Object)(object)_panel))
				{
					return Object.op_Implicit((Object)(object)_gui);
				}
				return false;
			}
		}

		internal PouchUi(InventoryGui gui, int slotCount)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_00bd: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			_slots = (InventoryElement[])(object)new InventoryElement[slotCount];
			_gui = gui;
			float elementSpace = gui.m_playerGrid.m_elementSpace;
			int num = Math.Min(7, slotCount);
			int num2 = (slotCount + 7 - 1) / 7;
			float num3 = ((num == 1) ? 60 : 38);
			_panel = new GameObject("SafePouch", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform val = (RectTransform)_panel.transform;
			((Transform)val).SetParent((Transform)(object)gui.m_player, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 0f);
			val.anchorMax = val2;
			val.anchorMin = val2;
			val.pivot = new Vector2(0f, 1f);
			val.anchoredPosition = new Vector2(0f, -8f);
			val.sizeDelta = new Vector2(elementSpace * (float)num + 24f, elementSpace * (float)num2 + num3 + 40f);
			_background = _panel.GetComponent<Image>();
			Image val3 = ((Component)gui.m_player).GetComponent<Image>();
			if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.sprite))
			{
				val3 = (from Transform t in (IEnumerable)gui.m_player
					where string.Equals(((Object)t).name, "Bkg", StringComparison.OrdinalIgnoreCase) || string.Equals(((Object)t).name, "Background", StringComparison.OrdinalIgnoreCase)
					select ((Component)t).GetComponent<Image>()).FirstOrDefault((Func<Image, bool>)((Image i) => Object.op_Implicit((Object)(object)i) && Object.op_Implicit((Object)(object)i.sprite)));
			}
			_inventoryBackground = val3;
			((Graphic)_background).color = new Color(0.16f, 0.14f, 0.15f, 0.97f);
			((Graphic)_background).raycastTarget = true;
			SyncBackgroundStyle();
			MakeText((num == 1) ? "Safe\nPouch" : "Safe Pouch", new Vector2(12f, -7f), 23f, new Color(1f, 0.77f, 0.38f), gui.m_containerName, num3 - 9f);
			_status = MakeText("Kept on death", new Vector2(12f, (0f - elementSpace) * (float)num2 - num3 - 5f), 16f, new Color(0.85f, 0.82f, 0.74f), gui.m_recipeDecription);
			for (int num4 = 0; num4 < slotCount; num4++)
			{
				int slotIndex = num4;
				GameObject val4 = Object.Instantiate<GameObject>(gui.m_playerGrid.m_elementPrefab, (Transform)(object)val);
				((Object)val4).name = "SafePouchSlot" + num4;
				RectTransform val5 = (RectTransform)val4.transform;
				((Vector2)(ref val2))..ctor(0f, 1f);
				val5.anchorMax = val2;
				val5.anchorMin = val2;
				val5.pivot = new Vector2(0f, 1f);
				val5.anchoredPosition = new Vector2(12f + elementSpace * (float)(num4 % 7), 0f - num3 - elementSpace * (float)(num4 / 7));
				InventoryElement component = val4.GetComponent<InventoryElement>();
				component.Initialize(num4, 0);
				_slots[num4] = component;
				UIInputHandler componentInChildren = val4.GetComponentInChildren<UIInputHandler>();
				componentInChildren.m_onLeftDown = delegate
				{
					Click(slotIndex);
				};
				componentInChildren.m_onRightDown = delegate
				{
					Withdraw(slotIndex);
				};
				UIDragHandler[] componentsInChildren = val4.GetComponentsInChildren<UIDragHandler>(true);
				for (int num5 = 0; num5 < componentsInChildren.Length; num5++)
				{
					((Behaviour)componentsInChildren[num5]).enabled = false;
				}
				Transform obj = val4.transform.Find("binding");
				TMP_Text val6 = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
				if (Object.op_Implicit((Object)(object)val6))
				{
					((Behaviour)val6).enabled = false;
				}
			}
		}

		private TMP_Text MakeText(string text, Vector2 position, float size, Color color, TMP_Text style, float height = 32f)
		{
			//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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(text, new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			});
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(_panel.transform, false);
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0f, 1f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.pivot = new Vector2(0f, 1f);
			val2.anchoredPosition = position;
			val2.sizeDelta = new Vector2(((RectTransform)_panel.transform).sizeDelta.x - 24f, height);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).font = style.font;
			((TMP_Text)component).fontSharedMaterial = style.fontSharedMaterial;
			((TMP_Text)component).fontSize = size;
			((TMP_Text)component).enableAutoSizing = true;
			((TMP_Text)component).fontSizeMin = 12f;
			((TMP_Text)component).fontSizeMax = size;
			((TMP_Text)component).enableWordWrapping = true;
			((Graphic)component).color = color;
			((TMP_Text)component).text = text;
			((Graphic)component).raycastTarget = false;
			return (TMP_Text)(object)component;
		}

		internal void Refresh(PouchState state)
		{
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			_state = state;
			_panel.SetActive(InventoryGui.IsVisible() && !((Character)Player.m_localPlayer).IsDead() && !_gui.IsContainerOpen());
			if (!_panel.activeInHierarchy)
			{
				return;
			}
			SyncBackgroundStyle();
			UpdatePosition();
			_status.text = (state.Locked ? "Pouch locked — check log" : ((state.VisibleSlots > state.ConfiguredSlots) ? "Extra slots: withdraw only" : "Kept on death"));
			for (int i = 0; i < _slots.Length; i++)
			{
				InventoryElement val = _slots[i];
				ItemData itemAt = state.Inventory.GetItemAt(i, 0);
				((Behaviour)val.m_icon).enabled = itemAt != null;
				if (itemAt != null)
				{
					val.m_icon.sprite = itemAt.GetIcon();
				}
				((Behaviour)val.m_amount).enabled = itemAt != null && itemAt.m_stack > 1;
				val.m_amount.text = itemAt?.m_stack.ToString() ?? "";
				((Behaviour)val.m_quality).enabled = itemAt != null && itemAt.m_shared.m_maxQuality > 1;
				val.m_quality.text = itemAt?.m_quality.ToString() ?? "";
				((Behaviour)val.m_equiped).enabled = false;
				((Behaviour)val.m_queued).enabled = false;
				((Behaviour)val.m_food).enabled = false;
				((Behaviour)val.m_noteleport).enabled = false;
				val.m_selected.SetActive(itemAt != null && Drag.Item(_gui) == itemAt);
				((Component)val.m_durability).gameObject.SetActive(false);
				val.m_tooltip.Set(itemAt?.m_shared.m_name ?? "Safe Pouch", (i >= state.ConfiguredSlots) ? "Withdraw this item to finish reducing the pouch size." : ((itemAt == null) ? "Items here survive death.\nNormal stackable items: up to 99,999 per slot.\nPortal-restricted items: one per slot." : (itemAt.GetTooltip(-1) + "\n<color=orange>Kept on death</color>" + ((!itemAt.m_shared.m_teleportable) ? "\nOne per slot. Can travel through portals here." : ""))), _gui.m_playerGrid.m_tooltipAnchor, default(Vector2));
			}
		}

		private void UpdatePosition()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			RectTransform player = _gui.m_player;
			Rect rect = player.rect;
			float bottom = ((Rect)(ref rect)).yMin;
			string[] backgroundPaths = BackgroundPaths;
			foreach (string text in backgroundPaths)
			{
				Transform obj = ((Transform)player).Find(text);
				RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
				if (Object.op_Implicit((Object)(object)val) && ((Component)val).gameObject.activeInHierarchy)
				{
					IncludeBottom(val, ref bottom);
				}
			}
			((Component)player).GetComponentsInChildren<Button>(false, _inventoryButtons);
			foreach (Button inventoryButton in _inventoryButtons)
			{
				if (Object.op_Implicit((Object)(object)inventoryButton) && ((Behaviour)inventoryButton).isActiveAndEnabled && !((Component)inventoryButton).transform.IsChildOf(_panel.transform))
				{
					Transform transform = ((Component)inventoryButton).transform;
					RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					if (Object.op_Implicit((Object)(object)val2))
					{
						IncludeBottom(val2, ref bottom);
					}
				}
			}
			RectTransform val3 = (RectTransform)_panel.transform;
			float num = bottom;
			rect = player.rect;
			val3.anchoredPosition = new Vector2(0f, num - ((Rect)(ref rect)).yMin - Plugin.Instance.PouchGap.Value - Plugin.Instance.VerticalOffset.Value);
		}

		private void SyncBackgroundStyle()
		{
			//IL_0096: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_inventoryBackground))
			{
				Image inventoryBackground = _inventoryBackground;
				if ((Object)(object)((Graphic)_background).material != (Object)(object)((Graphic)inventoryBackground).material)
				{
					((Graphic)_background).material = ((Graphic)inventoryBackground).material;
				}
				if ((Object)(object)_background.sprite != (Object)(object)inventoryBackground.sprite)
				{
					_background.sprite = inventoryBackground.sprite;
				}
				if ((Object)(object)_background.overrideSprite != (Object)(object)inventoryBackground.overrideSprite)
				{
					_background.overrideSprite = inventoryBackground.overrideSprite;
				}
				if (((Graphic)_background).color != ((Graphic)inventoryBackground).color)
				{
					((Graphic)_background).color = ((Graphic)inventoryBackground).color;
				}
				if (_background.type != inventoryBackground.type)
				{
					_background.type = inventoryBackground.type;
				}
				if (_background.pixelsPerUnitMultiplier != inventoryBackground.pixelsPerUnitMultiplier)
				{
					_background.pixelsPerUnitMultiplier = inventoryBackground.pixelsPerUnitMultiplier;
				}
				if (_background.fillCenter != inventoryBackground.fillCenter)
				{
					_background.fillCenter = inventoryBackground.fillCenter;
				}
				if (_background.preserveAspect != inventoryBackground.preserveAspect)
				{
					_background.preserveAspect = inventoryBackground.preserveAspect;
				}
			}
		}

		private void IncludeBottom(RectTransform edge, ref float bottom)
		{
			//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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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)
			edge.GetWorldCorners(_corners);
			float num = float.PositiveInfinity;
			float num2 = float.NegativeInfinity;
			float num3 = float.PositiveInfinity;
			Vector3[] corners = _corners;
			foreach (Vector3 val in corners)
			{
				Vector3 val2 = ((Transform)_gui.m_player).InverseTransformPoint(val);
				num = Mathf.Min(num, val2.x);
				num2 = Mathf.Max(num2, val2.x);
				num3 = Mathf.Min(num3, val2.y);
			}
			float num4 = num2;
			Rect rect = _gui.m_player.rect;
			if (num4 > ((Rect)(ref rect)).xMin)
			{
				float num5 = num;
				rect = _gui.m_player.rect;
				if (num5 < ((Rect)(ref rect)).xMax)
				{
					bottom = Mathf.Min(bottom, num3);
				}
			}
		}

		private void Click(int index)
		{
			if (_state == null || _state.Locked || ((Character)Player.m_localPlayer).IsDead() || ((Character)Player.m_localPlayer).IsTeleporting())
			{
				return;
			}
			ItemData val = Drag.Item(_gui);
			Inventory val2 = Drag.Inventory(_gui);
			if (val != null && val2 != null)
			{
				if (index >= _state.ConfiguredSlots)
				{
					return;
				}
				if (val2 != ((Humanoid)Player.m_localPlayer).GetInventory() && val2 != _state.Inventory)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, "Move the item into your inventory first.", 0, (Sprite)null, false);
					return;
				}
				int num = Math.Min(val.m_stack, Drag.Amount(_gui));
				if (!val.m_shared.m_teleportable && val2 != _state.Inventory)
				{
					for (int i = 0; i < _state.ConfiguredSlots; i++)
					{
						if (num <= 0)
						{
							break;
						}
						num -= _state.Transfer(val2, _state.Inventory, val, num, (index + i) % _state.ConfiguredSlots, 0);
					}
				}
				else
				{
					_state.Transfer(val2, _state.Inventory, val, num, index, 0);
				}
				Drag.Clear(_gui);
			}
			else
			{
				ItemData itemAt = _state.Inventory.GetItemAt(index, 0);
				if (itemAt != null)
				{
					Drag.Set(_gui, itemAt, _state.Inventory, itemAt.m_stack);
				}
			}
		}

		private void Withdraw(int index)
		{
			if (_state != null && !_state.Locked)
			{
				Drag.Clear(_gui);
				ItemData itemAt = _state.Inventory.GetItemAt(index, 0);
				if (itemAt != null)
				{
					_state.Withdraw(itemAt);
				}
			}
		}

		internal void Destroy()
		{
			Object.Destroy((Object)(object)_panel);
		}
	}
	internal static class SlotRules
	{
		internal const int Slots = 4;

		internal const int MaxSlots = 28;

		internal const int Columns = 7;

		internal const int PouchStackLimit = 99999;

		internal static int PouchCapacity(bool teleportable, int normalMax)
		{
			if (teleportable && normalMax > 1)
			{
				return 99999;
			}
			return 1;
		}

		internal static int TransferAmount(bool restricted, int maxStack, int existing, bool compatible, int available, int requested)
		{
			if (!compatible || available <= 0 || requested <= 0 || existing < 0)
			{
				return 0;
			}
			int num = (restricted ? 1 : Math.Max(1, maxStack));
			return Math.Max(0, Math.Min(Math.Min(available, requested), num - existing));
		}
	}
}