Decompiled source of DeepSlots v0.1.1

plugins/DeepSlots.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DeepSlots
{
	internal sealed class Rules
	{
		internal readonly HashSet<ItemType> Types = new HashSet<ItemType>();

		internal readonly HashSet<string> Include = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal readonly HashSet<string> Exclude = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal bool AnyItem;

		internal void Set(string types, string include, string exclude)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			Types.Clear();
			Include.Clear();
			Exclude.Clear();
			foreach (string item in Split(types))
			{
				if (Enum.TryParse<ItemType>(item, ignoreCase: true, out ItemType result))
				{
					Types.Add(result);
				}
			}
			foreach (string item2 in Split(include))
			{
				Include.Add(item2);
			}
			foreach (string item3 in Split(exclude))
			{
				Exclude.Add(item3);
			}
		}

		internal static IEnumerable<string> Split(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				yield break;
			}
			string[] array = text.Split(new char[3] { ',', ';', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0)
				{
					yield return text2;
				}
			}
		}

		internal static List<(string item, int amount)> ParseRecipe(string text)
		{
			List<(string, int)> list = new List<(string, int)>();
			foreach (string item in Split(text))
			{
				int num = item.IndexOf(':');
				string text2 = ((num < 0) ? item : item.Substring(0, num)).Trim();
				int result = 1;
				if ((num < 0 || int.TryParse(item.Substring(num + 1).Trim(), out result)) && text2.Length > 0 && result > 0)
				{
					list.Add((text2, result));
				}
			}
			return list;
		}

		internal bool Accepts(ItemData item)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			if (AnyItem)
			{
				return true;
			}
			if (item.m_shared.m_maxStackSize <= 1)
			{
				return false;
			}
			string prefab = Cells.Prefab(item);
			string name = item.m_shared.m_name;
			if (Listed(Exclude, prefab, name))
			{
				return false;
			}
			if (Listed(Include, prefab, name))
			{
				return true;
			}
			return Types.Contains(item.m_shared.m_itemType);
		}

		private static bool Listed(HashSet<string> list, string prefab, string name)
		{
			if (list.Count == 0)
			{
				return false;
			}
			if (prefab != null && list.Contains(prefab))
			{
				return true;
			}
			if (name != null)
			{
				if (!list.Contains(name))
				{
					if (name.StartsWith("$"))
					{
						return list.Contains(name.Substring(1));
					}
					return false;
				}
				return true;
			}
			return false;
		}
	}
	internal sealed class Box
	{
		internal Rules Rules;

		internal int Cap = 1000000000;

		internal bool Loading;

		internal string Kind;

		internal Dictionary<string, int> Fixed;

		internal int FixedCount;
	}
	internal static class Cells
	{
		internal const int DefaultCap = 1000000000;

		private static readonly ConditionalWeakTable<Inventory, Box> boxes = new ConditionalWeakTable<Inventory, Box>();

		internal const int KeyVersion = 1;

		internal static void Mark(Inventory inventory, Box box)
		{
			if (inventory != null)
			{
				boxes.Remove(inventory);
				if (box != null)
				{
					boxes.Add(inventory, box);
				}
			}
		}

		internal static Box Of(Inventory inventory)
		{
			if (inventory == null || !boxes.TryGetValue(inventory, out var value))
			{
				return null;
			}
			return value;
		}

		internal static bool Is(Inventory inventory)
		{
			return Of(inventory) != null;
		}

		internal static string Prefab(ItemData item)
		{
			if (item.m_dropPrefab == null)
			{
				return null;
			}
			if (!Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				return null;
			}
			return ((Object)item.m_dropPrefab).name;
		}

		internal static int Max(ItemData item)
		{
			return Math.Max(1, item.m_shared.m_maxStackSize);
		}

		internal static bool Oversized(ItemData item)
		{
			if (item != null && item.m_shared != null && item.m_shared.m_maxStackSize > 1)
			{
				return item.m_stack > item.m_shared.m_maxStackSize;
			}
			return false;
		}

		internal static bool Same(ItemData a, ItemData b)
		{
			if (a == null || b == null || a.m_shared == null || b.m_shared == null)
			{
				return false;
			}
			if (a.m_shared.m_name != b.m_shared.m_name || a.m_quality != b.m_quality || a.m_variant != b.m_variant || a.m_worldLevel != b.m_worldLevel)
			{
				return false;
			}
			Dictionary<string, string> customData = a.m_customData;
			Dictionary<string, string> customData2 = b.m_customData;
			int num = customData?.Count ?? 0;
			int num2 = customData2?.Count ?? 0;
			if (num != num2)
			{
				return false;
			}
			if (num == 0)
			{
				return true;
			}
			foreach (KeyValuePair<string, string> item in customData)
			{
				if (!customData2.TryGetValue(item.Key, out var value) || value != item.Value)
				{
					return false;
				}
			}
			return true;
		}

		internal static ItemData CellOf(Inventory inventory, ItemData like, ItemData except = null)
		{
			if (like?.m_shared == null || like.m_shared.m_maxStackSize <= 1)
			{
				return null;
			}
			foreach (ItemData item in inventory.m_inventory)
			{
				if (item != except && Same(item, like))
				{
					return item;
				}
			}
			return null;
		}

		internal static bool Inside(Inventory inventory, int x, int y)
		{
			if (x >= 0 && y >= 0 && x < inventory.m_width)
			{
				return y < inventory.m_height;
			}
			return false;
		}

		internal static Vector2i FirstEmpty(Inventory inventory, int rows = -1)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (rows < 0)
			{
				rows = inventory.m_height;
			}
			for (int i = 0; i < rows; i++)
			{
				for (int j = 0; j < inventory.m_width; j++)
				{
					if (inventory.GetItemAt(j, i) == null)
					{
						return new Vector2i(j, i);
					}
				}
			}
			return new Vector2i(-1, -1);
		}

		internal static void Changed(Inventory inventory)
		{
			inventory.Changed(false, false);
		}

		private static bool Plain(ItemData i)
		{
			if (i.m_quality <= 1 && i.m_variant == 0)
			{
				if (i.m_customData != null)
				{
					return i.m_customData.Count == 0;
				}
				return true;
			}
			return false;
		}

		internal static int SlotIndex(Box box, ItemData item)
		{
			if (box?.Fixed == null || item == null || item.m_shared?.m_name == null || !Plain(item))
			{
				return -1;
			}
			if (!box.Fixed.TryGetValue(item.m_shared.m_name, out var value))
			{
				return -1;
			}
			return value;
		}

		internal static Vector2i At(Inventory inventory, int index)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2i(index % inventory.m_width, index / inventory.m_width);
		}

		internal static int SortedRows(int kinds, int width)
		{
			return Math.Max(1, (kinds + width) / Math.Max(1, width));
		}

		internal static Vector2i Extra(Inventory inventory, Box box)
		{
			//IL_0004: 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)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			Vector2i val;
			while (true)
			{
				val = At(inventory, num);
				if (val.y >= 255)
				{
					return new Vector2i(-1, -1);
				}
				if (inventory.GetItemAt(val.x, val.y) == null)
				{
					break;
				}
				num++;
			}
			if (val.y >= inventory.m_height)
			{
				inventory.m_height = val.y + 1;
			}
			return val;
		}

		private static Vector2i Home(Inventory inventory, Box box, ItemData item, Vector2i? wish)
		{
			//IL_000a: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (box.Fixed != null)
			{
				return Extra(inventory, box);
			}
			if (wish.HasValue && Inside(inventory, wish.Value.x, wish.Value.y) && inventory.GetItemAt(wish.Value.x, wish.Value.y) == null)
			{
				return wish.Value;
			}
			return FirstEmpty(inventory);
		}

		private static int Compare(Box box, ItemData a, ItemData b)
		{
			int num = SlotIndex(box, a);
			int num2 = SlotIndex(box, b);
			if (num < 0)
			{
				num = int.MaxValue;
			}
			if (num2 < 0)
			{
				num2 = int.MaxValue;
			}
			if (num != num2)
			{
				return num.CompareTo(num2);
			}
			int num3 = string.CompareOrdinal(a.m_shared.m_name, b.m_shared.m_name);
			if (num3 != 0)
			{
				return num3;
			}
			return a.m_quality.CompareTo(b.m_quality);
		}

		internal static bool Normalize(Inventory inventory, Box box)
		{
			//IL_0133: 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)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			if (box?.Fixed == null)
			{
				return false;
			}
			List<ItemData> inventory2 = inventory.m_inventory;
			bool result = false;
			List<ItemData> list = new List<ItemData>();
			for (int i = 0; i < inventory2.Count; i++)
			{
				ItemData val = inventory2[i];
				if (list.Contains(val) || val.m_shared.m_maxStackSize <= 1)
				{
					continue;
				}
				for (int j = i + 1; j < inventory2.Count; j++)
				{
					ItemData val2 = inventory2[j];
					if (!list.Contains(val2) && Same(val, val2))
					{
						val.m_stack = (int)Math.Min(box.Cap, (long)val.m_stack + (long)val2.m_stack);
						list.Add(val2);
					}
				}
			}
			foreach (ItemData item in list)
			{
				inventory2.Remove(item);
				result = true;
			}
			List<ItemData> list2 = new List<ItemData>(inventory2);
			list2.Sort((ItemData a, ItemData b) => Compare(box, a, b));
			for (int num = 0; num < list2.Count; num++)
			{
				Vector2i val3 = At(inventory, num);
				if (list2[num].m_gridPos.x != val3.x || list2[num].m_gridPos.y != val3.y)
				{
					list2[num].m_gridPos = val3;
					result = true;
				}
			}
			int num2 = SortedRows(list2.Count, inventory.m_width);
			if (inventory.m_height != num2)
			{
				inventory.m_height = num2;
				result = true;
			}
			return result;
		}

		private static void Sorted(Inventory inventory, Box box)
		{
			if (box.Fixed != null && !box.Loading)
			{
				Normalize(inventory, box);
			}
		}

		internal static bool Add(Inventory inventory, Box box, ItemData item, Vector2i? at = null)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			if (item == null || item.m_stack <= 0)
			{
				return false;
			}
			if (!box.Loading && !box.Rules.Accepts(item))
			{
				return false;
			}
			ItemData val = CellOf(inventory, item, item);
			if (val != null)
			{
				long num = (long)box.Cap - (long)val.m_stack;
				if (num >= item.m_stack)
				{
					val.m_stack += item.m_stack;
					Changed(inventory);
					return true;
				}
				int num2 = (int)Math.Max(0L, num);
				val.m_stack += num2;
				item.m_stack -= num2;
				if (num2 > 0)
				{
					Changed(inventory);
				}
				return false;
			}
			if (inventory.m_inventory.Contains(item))
			{
				return true;
			}
			if (item.m_stack > box.Cap)
			{
				return false;
			}
			Vector2i val2 = Home(inventory, box, item, at);
			if (val2.x < 0)
			{
				return false;
			}
			item.m_gridPos = val2;
			item.m_equipped = false;
			inventory.m_inventory.Add(item);
			Sorted(inventory, box);
			Changed(inventory);
			return true;
		}

		internal static bool AddAt(Inventory inventory, Box box, ItemData item, int amount, int x, int y)
		{
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			if (item == null)
			{
				return false;
			}
			amount = Math.Min(amount, item.m_stack);
			if (amount <= 0)
			{
				return false;
			}
			if (box.Loading)
			{
				return Place(inventory, box, item, amount, x, y);
			}
			if (!box.Rules.Accepts(item))
			{
				return false;
			}
			ItemData val = (Inside(inventory, x, y) ? inventory.GetItemAt(x, y) : null);
			if (inventory.m_inventory.Contains(item))
			{
				if (val == item)
				{
					return true;
				}
				if (box.Fixed != null)
				{
					return false;
				}
				if (amount < item.m_stack || val != null || !Inside(inventory, x, y))
				{
					return false;
				}
				item.m_gridPos = new Vector2i(x, y);
				Changed(inventory);
				return true;
			}
			ItemData val2 = CellOf(inventory, item);
			if (val2 != null)
			{
				long val3 = (long)box.Cap - (long)val2.m_stack;
				int num = (int)Math.Max(0L, Math.Min(amount, val3));
				val2.m_stack += num;
				item.m_stack -= num;
				if (num > 0)
				{
					Changed(inventory);
				}
				return num == amount;
			}
			int num2 = amount;
			if (amount > box.Cap)
			{
				amount = box.Cap;
			}
			Vector2i val4 = Home(inventory, box, item, (Vector2i?)new Vector2i(x, y));
			if (val4.x < 0)
			{
				return false;
			}
			ItemData val5 = item.Clone();
			val5.m_stack = amount;
			val5.m_gridPos = val4;
			val5.m_equipped = false;
			inventory.m_inventory.Add(val5);
			item.m_stack -= amount;
			Sorted(inventory, box);
			Changed(inventory);
			return amount == num2;
		}

		private static bool Place(Inventory inventory, Box box, ItemData item, int amount, int x, int y)
		{
			//IL_0086: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			Vector2i val = default(Vector2i);
			((Vector2i)(ref val))..ctor(x, y);
			if (box.Fixed != null)
			{
				ItemData val2 = CellOf(inventory, item);
				if (val2 != null)
				{
					val2.m_stack = (int)Math.Min(box.Cap, (long)val2.m_stack + (long)amount);
					item.m_stack -= amount;
					return true;
				}
				val = Extra(inventory, box);
				if (val.x < 0)
				{
					return false;
				}
			}
			else if (x < 0 || x >= inventory.m_width || y < 0 || inventory.GetItemAt(x, y) != null)
			{
				val = FirstEmpty(inventory, inventory.m_height);
				if (val.x < 0)
				{
					val = FirstEmpty(inventory, 255);
				}
				if (val.x < 0)
				{
					return false;
				}
			}
			ItemData val3 = item.Clone();
			val3.m_stack = amount;
			val3.m_gridPos = val;
			inventory.m_inventory.Add(val3);
			item.m_stack -= amount;
			return true;
		}

		internal static bool CanAdd(Inventory inventory, Box box, ItemData item, int stack)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (item == null || !box.Rules.Accepts(item))
			{
				return false;
			}
			if (stack <= 0)
			{
				stack = item.m_stack;
			}
			ItemData val = CellOf(inventory, item, item);
			if (val != null)
			{
				return (long)box.Cap - (long)val.m_stack >= stack;
			}
			if (stack > box.Cap)
			{
				return false;
			}
			if (box.Fixed != null)
			{
				return true;
			}
			return FirstEmpty(inventory).x >= 0;
		}

		internal static int FreeSpace(Inventory inventory, Box box, string name, float worldLevel)
		{
			long num = 0L;
			foreach (ItemData item in inventory.m_inventory)
			{
				if (item.m_shared.m_name == name && item.m_shared.m_maxStackSize > 1 && (float)item.m_worldLevel == worldLevel)
				{
					num += Math.Max(0L, (long)box.Cap - (long)item.m_stack);
				}
			}
			return (int)Math.Min(2147483647L, num);
		}

		internal static int Fill(Inventory inventory, ItemData item, int amount, Vector2i? first = null)
		{
			//IL_0030: 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_0050: 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_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: 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_0160: Unknown result type (might be due to invalid IL or missing references)
			if (item == null)
			{
				return 0;
			}
			int num = Max(item);
			int num2 = Math.Min(amount, item.m_stack);
			int num3 = num2;
			if (num3 <= 0)
			{
				return 0;
			}
			if (first.HasValue && Inside(inventory, first.Value.x, first.Value.y))
			{
				ItemData itemAt = inventory.GetItemAt(first.Value.x, first.Value.y);
				if (itemAt == null)
				{
					num3 -= New(inventory, item, Math.Min(num3, num), first.Value);
				}
				else if (itemAt != item && Same(itemAt, item) && itemAt.m_stack < num)
				{
					int num4 = Math.Min(num3, num - itemAt.m_stack);
					itemAt.m_stack += num4;
					num3 -= num4;
				}
			}
			if (num3 > 0)
			{
				ItemData[] array = inventory.m_inventory.ToArray();
				foreach (ItemData val in array)
				{
					if (num3 <= 0)
					{
						break;
					}
					if (val != item && Same(val, item) && val.m_stack < num)
					{
						int num5 = Math.Min(num3, num - val.m_stack);
						val.m_stack += num5;
						num3 -= num5;
					}
				}
			}
			while (num3 > 0)
			{
				Vector2i val2 = inventory.FindEmptySlot(inventory.TopFirst(item));
				if (val2.x < 0)
				{
					break;
				}
				num3 -= New(inventory, item, Math.Min(num3, num), val2);
			}
			int num6 = num2 - num3;
			item.m_stack -= num6;
			if (num6 > 0)
			{
				Changed(inventory);
			}
			return num6;
		}

		private static int New(Inventory inventory, ItemData item, int n, Vector2i pos)
		{
			//IL_000f: 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)
			ItemData val = item.Clone();
			val.m_stack = n;
			val.m_gridPos = pos;
			val.m_equipped = false;
			inventory.m_inventory.Add(val);
			return n;
		}

		internal static bool FillAll(Inventory inventory, ItemData item, Vector2i? first = null)
		{
			int stack = item.m_stack;
			Fill(inventory, item, stack, first);
			if (item.m_stack > 0)
			{
				return false;
			}
			item.m_stack = stack;
			return true;
		}

		internal static List<(ItemData item, int stack)> Clamp(Inventory inventory)
		{
			List<(ItemData, int)> list = new List<(ItemData, int)>();
			foreach (ItemData item in inventory.m_inventory)
			{
				if (Oversized(item))
				{
					list.Add((item, item.m_stack));
					item.m_stack = item.m_shared.m_maxStackSize;
				}
			}
			return list;
		}

		internal static void Restore(List<(ItemData item, int stack)> saved)
		{
			foreach (var item3 in saved)
			{
				ItemData item = item3.item;
				int item2 = item3.stack;
				item.m_stack = item2;
			}
		}

		internal static byte[] SaveCounts(Inventory inventory)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData item in inventory.m_inventory)
			{
				if (Oversized(item))
				{
					list.Add(item);
				}
			}
			if (list.Count == 0)
			{
				return new byte[0];
			}
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(list.Count);
			foreach (ItemData item2 in list)
			{
				val.Write(item2.m_shared.m_name ?? "");
				val.Write(item2.m_quality);
				val.Write(item2.m_variant);
				val.Write(item2.m_gridPos.x);
				val.Write(item2.m_gridPos.y);
				val.Write(item2.m_stack);
			}
			return val.GetArray();
		}

		internal static int ApplyCounts(Inventory inventory, byte[] data)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			if (data == null || data.Length == 0)
			{
				return 0;
			}
			ZPackage val = new ZPackage(data);
			if (val.ReadInt() != 1)
			{
				return -1;
			}
			int num = val.ReadInt();
			int num2 = 0;
			HashSet<ItemData> done = new HashSet<ItemData>();
			for (int i = 0; i < num; i++)
			{
				string name = val.ReadString();
				int quality = val.ReadInt();
				int variant = val.ReadInt();
				int num3 = val.ReadInt();
				int num4 = val.ReadInt();
				int num5 = val.ReadInt();
				ItemData val2 = null;
				ItemData itemAt = inventory.GetItemAt(num3, num4);
				if (itemAt != null && Match(itemAt))
				{
					val2 = itemAt;
				}
				else
				{
					foreach (ItemData item in inventory.m_inventory)
					{
						if (Match(item) && item.m_stack <= Max(item))
						{
							val2 = item;
							break;
						}
					}
				}
				if (val2 == null)
				{
					num2++;
					continue;
				}
				if (num5 > val2.m_stack)
				{
					val2.m_stack = num5;
				}
				done.Add(val2);
				bool Match(ItemData val3)
				{
					if (!done.Contains(val3) && val3.m_shared.m_name == name && val3.m_quality == quality)
					{
						return val3.m_variant == variant;
					}
					return false;
				}
			}
			return num2;
		}

		internal static List<(ItemData item, int amount)> DropPlan(IEnumerable<ItemData> items)
		{
			List<(ItemData, int)> list = new List<(ItemData, int)>();
			foreach (ItemData item in items)
			{
				int val = Max(item);
				int num = item.m_stack;
				while (num > 0)
				{
					int num2 = Math.Min(num, val);
					list.Add((item, num2));
					num -= num2;
				}
			}
			return list;
		}

		internal static string Short(long n, bool russian)
		{
			if (n < 10000)
			{
				return Full(n, russian);
			}
			if (n < 1000000)
			{
				return Scaled(n, 1000L, "k", russian);
			}
			if (n < 1000000000)
			{
				return Scaled(n, 1000000L, "M", russian);
			}
			return Scaled(n, 1000000000L, "B", russian);
		}

		private static string Scaled(long n, long unit, string suffix, bool russian)
		{
			long num = n / unit;
			if (num >= 100)
			{
				return num.ToString(CultureInfo.InvariantCulture) + suffix;
			}
			long num2 = n * 10 / unit % 10;
			if (num2 == 0L)
			{
				return num.ToString(CultureInfo.InvariantCulture) + suffix;
			}
			return num.ToString(CultureInfo.InvariantCulture) + (russian ? "," : ".") + num2.ToString(CultureInfo.InvariantCulture) + suffix;
		}

		internal static string Full(long n, bool russian)
		{
			string text = Math.Abs(n).ToString(CultureInfo.InvariantCulture);
			StringBuilder stringBuilder = new StringBuilder();
			if (n < 0)
			{
				stringBuilder.Append('-');
			}
			for (int i = 0; i < text.Length; i++)
			{
				if (i > 0 && (text.Length - i) % 3 == 0)
				{
					stringBuilder.Append(russian ? ' ' : ',');
				}
				stringBuilder.Append(text[i]);
			}
			return stringBuilder.ToString();
		}

		internal static string CopyName(string name, bool russian)
		{
			name = (name ?? "").Trim();
			if (name.Length > 1 && char.IsUpper(name[0]) && char.IsLower(name[1]))
			{
				name = char.ToLowerInvariant(name[0]) + name.Substring(1);
			}
			if (!russian)
			{
				if (name.Length != 0)
				{
					return "Deep " + name;
				}
				return "Deep chest";
			}
			if (name.Length == 0)
			{
				return "Глубокий сундук";
			}
			string text = "Глубокий ";
			string[] array = name.Split(new char[2] { ' ', '-' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim(',', '.', '(', ')', '«', '»', '"').ToLowerInvariant();
				if (text2.Length != 0 && (text2.Length <= 3 || (!text2.EndsWith("ый") && !text2.EndsWith("ий") && !text2.EndsWith("ой") && !text2.EndsWith("ая") && !text2.EndsWith("яя") && !text2.EndsWith("ое") && !text2.EndsWith("ее") && !text2.EndsWith("ые") && !text2.EndsWith("ие"))))
				{
					switch (text2[text2.Length - 1])
					{
					case 'а':
					case 'я':
						text = "Глубокая ";
						break;
					case 'е':
					case 'о':
						text = "Глубокое ";
						break;
					case 'и':
					case 'ы':
						text = "Глубокие ";
						break;
					}
					break;
				}
			}
			return text + name;
		}
	}
	internal static class Hooks
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class SceneAwake
		{
			[HarmonyPriority(200)]
			private static void Prefix(ZNetScene __instance)
			{
				try
				{
					Prefabs.Register(__instance);
				}
				catch (Exception ex)
				{
					Plugin.Warn("ZNetScene: " + ex);
				}
			}

			private static void Postfix()
			{
				Prefabs.Hammer();
				Words.Refresh();
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class DbAwake
		{
			private static void Postfix()
			{
				Trophies.Build(force: true);
				Prefabs.Refresh();
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class DbCopy
		{
			private static void Postfix()
			{
				Trophies.Build(force: true);
				Prefabs.Refresh();
			}
		}

		[HarmonyPatch(typeof(Localization), "SetupLanguage")]
		private static class Language
		{
			private static void Postfix(Localization __instance, string language)
			{
				Words.Add(__instance, language);
			}
		}

		[HarmonyPatch(typeof(Container), "Awake")]
		private static class ContainerAwake
		{
			private static void Prefix(Container __instance)
			{
				Kind kind = Kinds.ByContainerName(__instance.m_name);
				if (kind != null && !kind.Copy)
				{
					__instance.m_width = kind.Columns.Value;
					if (kind.FixedLayout)
					{
						Trophies.Build();
					}
					__instance.m_height = kind.RowsNow(kind.Columns.Value);
				}
			}

			private static void Postfix(Container __instance)
			{
				Kind kind = Kinds.ByContainerName(__instance.m_name);
				if (kind != null && __instance.m_inventory != null)
				{
					Box box = new Box
					{
						Rules = kind.Rules,
						Kind = kind.Id
					};
					if (kind.FixedLayout && Trophies.Slots != null && Trophies.List.Count > 0)
					{
						box.Fixed = Trophies.Slots;
						box.FixedCount = Trophies.List.Count;
					}
					Cells.Mark(__instance.m_inventory, box);
				}
			}
		}

		[HarmonyPatch(typeof(Container), "Save")]
		private static class ContainerSave
		{
			private static bool Prefix(Container __instance)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Expected O, but got Unknown
				Inventory inventory = __instance.m_inventory;
				if (!Cells.Is(inventory))
				{
					return true;
				}
				ZNetView nview = __instance.m_nview;
				ZDO val = ((nview != null) ? nview.GetZDO() : null);
				if (val == null)
				{
					return false;
				}
				ZPackage val2 = new ZPackage();
				List<(ItemData, int)> saved = Cells.Clamp(inventory);
				try
				{
					inventory.Save(val2);
				}
				finally
				{
					Cells.Restore(saved);
				}
				val.Set(ZDOVars.s_items, val2.GetArray());
				val.Set(CountsKey, Cells.SaveCounts(inventory));
				__instance.m_lastRevision = val.DataRevision;
				return false;
			}
		}

		[HarmonyPatch(typeof(Container), "Load")]
		private static class ContainerLoad
		{
			private static void Prefix(Container __instance, out Box __state)
			{
				__state = Cells.Of(__instance.m_inventory);
				if (__state != null)
				{
					__state.Loading = true;
				}
			}

			private static void Postfix(Container __instance, bool __result, Box __state)
			{
				if (__state == null)
				{
					return;
				}
				__state.Loading = false;
				if (!__result)
				{
					return;
				}
				ZNetView nview = __instance.m_nview;
				ZDO val = ((nview != null) ? nview.GetZDO() : null);
				if (val != null)
				{
					int num = Cells.ApplyCounts(__instance.m_inventory, val.GetByteArray(CountsKey, (byte[])null));
					if (num != 0)
					{
						Plugin.Warn($"{((Object)__instance).name}: {num} saved counts did not match an item");
					}
					Cells.Normalize(__instance.m_inventory, __state);
				}
			}

			private static Exception Finalizer(Exception __exception, Box __state)
			{
				if (__state != null)
				{
					__state.Loading = false;
				}
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
		private static class AddItem
		{
			private static bool Prefix(Inventory __instance, ItemData item, ref bool __result)
			{
				if (item == null)
				{
					return true;
				}
				Box box = Cells.Of(__instance);
				if (box != null)
				{
					if (!box.Loading && !box.Rules.Accepts(item))
					{
						Say("deep_refused");
						__result = false;
						return false;
					}
					__result = Cells.Add(__instance, box, item);
					return false;
				}
				if (!Cells.Oversized(item))
				{
					return true;
				}
				__result = Cells.FillAll(__instance, item);
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(Vector2i)
		})]
		private static class AddItemAt
		{
			private static bool Prefix(Inventory __instance, ItemData item, Vector2i pos, ref bool __result)
			{
				//IL_0053: 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)
				if (item == null)
				{
					return true;
				}
				Box box = Cells.Of(__instance);
				if (box != null)
				{
					if (!box.Loading && !box.Rules.Accepts(item))
					{
						Say("deep_refused");
						__result = false;
						return false;
					}
					__result = Cells.Add(__instance, box, item, pos);
					return false;
				}
				if (!Cells.Oversized(item))
				{
					return true;
				}
				__result = Cells.FillAll(__instance, item, pos);
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		private static class AddItemAmount
		{
			private static bool Prefix(Inventory __instance, ItemData item, int amount, int x, int y, ref bool __result)
			{
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				if (item == null)
				{
					return true;
				}
				Box box = Cells.Of(__instance);
				if (box != null)
				{
					if (!box.Loading && !box.Rules.Accepts(item))
					{
						Say("deep_refused");
						__result = false;
						return false;
					}
					__result = Cells.AddAt(__instance, box, item, amount, x, y);
					return false;
				}
				if (!Cells.Oversized(item) || amount <= item.m_shared.m_maxStackSize)
				{
					return true;
				}
				int num = Math.Min(amount, item.m_stack);
				__result = Cells.Fill(__instance, item, num, (Vector2i?)new Vector2i(x, y)) == num;
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int)
		})]
		private static class CanAddItem
		{
			private static bool Prefix(Inventory __instance, ItemData item, int stack, ref bool __result)
			{
				Box box = Cells.Of(__instance);
				if (box == null)
				{
					return true;
				}
				__result = Cells.CanAdd(__instance, box, item, stack);
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "FindFreeStackSpace")]
		private static class FreeStackSpace
		{
			private static bool Prefix(Inventory __instance, string name, float worldLevel, ref int __result)
			{
				Box box = Cells.Of(__instance);
				if (box == null)
				{
					return true;
				}
				__result = Cells.FreeSpace(__instance, box, name, worldLevel);
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupDragItem")]
		private static class DragItem
		{
			private static void Prefix(ItemData item, Inventory inventory, ref int amount)
			{
				if (item != null && !fromSplit && Cells.Is(inventory))
				{
					int num = Cells.Max(item);
					if (amount > num)
					{
						amount = num;
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnSplitOk")]
		private static class SplitOk
		{
			private static void Prefix()
			{
				fromSplit = true;
			}

			private static void Finalizer()
			{
				fromSplit = false;
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "DropItem")]
		private static class GridDrop
		{
			private static bool Prefix(InventoryGrid __instance, Inventory fromInventory, ItemData item, int amount, Vector2i pos, ref bool __result)
			{
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				//IL_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)
				Inventory inventory = __instance.m_inventory;
				Box box = Cells.Of(inventory);
				Box box2 = Cells.Of(fromInventory);
				if ((box == null && box2 == null) || item == null || fromInventory == null)
				{
					return true;
				}
				if (inventory == fromInventory && box.Fixed != null)
				{
					__result = true;
					return false;
				}
				if (inventory == fromInventory)
				{
					ItemData itemAt = inventory.GetItemAt(pos.x, pos.y);
					if (itemAt != item)
					{
						if (itemAt != null)
						{
							itemAt.m_gridPos = item.m_gridPos;
						}
						item.m_gridPos = pos;
						Cells.Changed(inventory);
					}
					__result = true;
					return false;
				}
				amount = Math.Min(amount, item.m_stack);
				int stack = item.m_stack;
				if (box != null)
				{
					if (!box.Rules.Accepts(item))
					{
						Say("deep_refused");
						__result = false;
						return false;
					}
					Cells.AddAt(inventory, box, item, amount, pos.x, pos.y);
				}
				else
				{
					Cells.Fill(inventory, item, amount, pos);
				}
				int num = stack - item.m_stack;
				if (item.m_stack <= 0)
				{
					fromInventory.RemoveItem(item);
				}
				else if (num > 0)
				{
					Cells.Changed(fromInventory);
				}
				if (num < amount)
				{
					Say("deep_noroom");
				}
				__result = num > 0;
				return false;
			}
		}

		[HarmonyPatch(typeof(Humanoid), "DropItem")]
		private static class GroundDrop
		{
			private static void Prefix(Humanoid __instance, Inventory inventory, ItemData item, ref int amount)
			{
				if (item != null && Cells.Is(inventory))
				{
					int num = Cells.Max(item);
					if (amount > num)
					{
						amount = num;
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		private static class GridNumbers
		{
			private static void Postfix(InventoryGrid __instance)
			{
				Inventory inventory = __instance.m_inventory;
				if (!Cells.Is(inventory))
				{
					return;
				}
				bool russian = Plugin.Russian;
				int width = inventory.GetWidth();
				foreach (ItemData item in inventory.m_inventory)
				{
					if (item.m_shared.m_maxStackSize > 1)
					{
						InventoryElement element = __instance.GetElement(item.m_gridPos.x, item.m_gridPos.y, width);
						if (!((Object)(object)element == (Object)null) && !((Object)(object)element.m_amount == (Object)null))
						{
							((Behaviour)element.m_amount).enabled = true;
							element.m_amount.text = Cells.Short(item.m_stack, russian);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static class TrophyWindow
		{
			private static void Prefix(InventoryGui __instance)
			{
				Container currentContainer = __instance.m_currentContainer;
				if (!((Object)(object)currentContainer == (Object)null) && currentContainer.IsOwner())
				{
					Box box = Cells.Of(currentContainer.m_inventory);
					if (box?.Fixed != null && Cells.Normalize(currentContainer.m_inventory, box))
					{
						Cells.Changed(currentContainer.m_inventory);
					}
				}
			}

			private static void Postfix(InventoryGui __instance)
			{
				Container currentContainer = __instance.m_currentContainer;
				if (!((Object)(object)currentContainer == (Object)null) && !((Object)(object)__instance.m_containerName == (Object)null))
				{
					Box box = Cells.Of(currentContainer.m_inventory);
					if (box?.Fixed != null)
					{
						__instance.m_containerName.text = Localization.instance.Localize(currentContainer.m_inventory.GetName()) + "  " + Trophies.Collected(currentContainer.m_inventory) + " / " + box.FixedCount;
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "CreateItemTooltip")]
		private static class GridTooltip
		{
			private static bool Prefix(InventoryGrid __instance, ItemData item, UITooltip tooltip)
			{
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				if (item == null || (Object)(object)tooltip == (Object)null || item.m_shared.m_maxStackSize <= 1 || !Cells.Is(__instance.m_inventory))
				{
					return true;
				}
				string text = Localization.instance.Localize("$deep_total") + ": <color=orange>" + Cells.Full(item.m_stack, Plugin.Russian) + "</color>";
				tooltip.Set(item.m_shared.m_name, item.GetTooltip(-1) + "\n\n" + text, __instance.m_tooltipAnchor, default(Vector2));
				return false;
			}
		}

		[HarmonyPatch(typeof(Container), "GetHoverText")]
		private static class Hover
		{
			private static void Postfix(Container __instance, ref string __result)
			{
				Inventory inventory = __instance.m_inventory;
				if (Cells.Is(inventory) && __result != null)
				{
					int num = inventory.NrOfItems();
					int num2 = inventory.GetWidth() * inventory.GetHeight();
					Box box = Cells.Of(inventory);
					string text = ((box.Fixed != null) ? ("\n$deep_collected: " + Trophies.Collected(inventory) + " / " + box.FixedCount) : ("\n$deep_cells: " + num + "/" + num2));
					if (num > 0 && Plugin.Protect.Value)
					{
						text += "\n$deep_noremove";
					}
					__result += Localization.instance.Localize(text);
				}
			}
		}

		[HarmonyPatch(typeof(Container), "CanBeRemoved")]
		private static class Removable
		{
			private static void Postfix(Container __instance, ref bool __result)
			{
				if (__result && Plugin.Protect.Value && Cells.Is(__instance.m_inventory) && __instance.m_inventory.NrOfItems() > 0)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "ApplyDamage")]
		private static class NoDamage
		{
			private static bool Prefix(WearNTear __instance, ref bool __result)
			{
				if (!Plugin.Protect.Value)
				{
					return true;
				}
				Piece piece = __instance.m_piece;
				if ((Object)(object)piece == (Object)null || piece.m_name == null || !piece.m_name.StartsWith("$deep_", StringComparison.Ordinal))
				{
					return true;
				}
				Container componentInChildren = ((Component)__instance).GetComponentInChildren<Container>();
				if ((Object)(object)componentInChildren == (Object)null || !Cells.Is(componentInChildren.m_inventory) || componentInChildren.m_inventory.NrOfItems() == 0)
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(Container), "OnDestroyed")]
		private static class Broken
		{
			private static bool Prefix(Container __instance)
			{
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				Inventory inventory = __instance.m_inventory;
				if (!Cells.Is(inventory))
				{
					return true;
				}
				if (!__instance.m_nview.IsOwner())
				{
					return false;
				}
				List<ItemData> list = new List<ItemData>();
				foreach (ItemData item in inventory.m_inventory)
				{
					list.Add(item.Clone());
				}
				inventory.RemoveAll();
				__instance.Save();
				if (list.Count > 0 && (Object)(object)Plugin.Instance != (Object)null)
				{
					((MonoBehaviour)Plugin.Instance).StartCoroutine(Spill(list, ((Component)__instance).transform.position));
				}
				return false;
			}
		}

		internal static readonly int CountsKey = StringExtensionMethods.GetStableHashCode("chistix_deepslots_counts");

		private static float lastMessage;

		private static bool fromSplit;

		private const int SpillPerFrame = 8;

		internal static void Say(string key)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !(Time.time - lastMessage < 0.5f))
			{
				lastMessage = Time.time;
				((Character)localPlayer).Message((MessageType)2, "$" + key, 0, (Sprite)null, false);
			}
		}

		private static IEnumerator Spill(List<ItemData> items, Vector3 at)
		{
			//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)
			int n = 0;
			int total = 0;
			foreach (var (val, num) in Cells.DropPlan(items))
			{
				if (!((Object)(object)val.m_dropPrefab == (Object)null))
				{
					Vector3 val2 = at + Vector3.up * 0.5f + Random.insideUnitSphere * 0.5f;
					ItemDrop.DropItem(val, num, val2, Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f));
					total++;
					int num2 = n + 1;
					n = num2;
					if (num2 >= 8)
					{
						n = 0;
						yield return null;
					}
				}
			}
			Plugin.Debug($"spilled {total} stacks");
		}
	}
	internal sealed class Kind
	{
		internal string Id;

		internal string Source;

		internal string Fallback;

		internal string IconItem;

		internal string Section;

		internal string En;

		internal string Ru;

		internal string DescEn;

		internal string DescRu;

		internal int DefColumns;

		internal int DefRows;

		internal bool FixedLayout;

		internal string DefTypes;

		internal string DefInclude;

		internal string DefExclude;

		internal string DefRecipe;

		internal readonly Rules Rules = new Rules();

		internal ConfigEntry<bool> Enabled;

		internal ConfigEntry<int> Columns;

		internal ConfigEntry<int> Rows;

		internal ConfigEntry<string> Types;

		internal ConfigEntry<string> Include;

		internal ConfigEntry<string> Exclude;

		internal ConfigEntry<string> Recipe;

		internal ConfigEntry<string> Station;

		internal bool Copy;

		internal Piece SourcePiece;

		internal string Name => "$" + Id;

		internal int Hash => StringExtensionMethods.GetStableHashCode(Id);

		internal bool On
		{
			get
			{
				if (!Copy)
				{
					return Enabled.Value;
				}
				return Kinds.CopiesEnabled.Value;
			}
		}

		internal int RowsNow(int width)
		{
			if (!FixedLayout)
			{
				if (Rows == null)
				{
					return DefRows;
				}
				return Rows.Value;
			}
			return Cells.SortedRows(0, width);
		}

		internal void Bind(ConfigFile config)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes
			{
				CustomDrawer = Plugin.Stepper
			};
			Enabled = config.Bind<bool>(Section, "Enabled", true, En + " in the hammer's menu. Off: it is not built any more; the ones standing keep working.\n«" + Ru + "» в меню молотка. Выключено: новые не строятся, стоящие работают как прежде.");
			Columns = config.Bind<int>(Section, "Columns", DefColumns, new ConfigDescription("Cells in a row. Applies to a chest when it is loaded again (come back to the area or log in again); items never get lost, a narrower grid moves them to free cells.\nЯчеек в ряду. Применяется к сундуку, когда он загрузится заново (вернуться в эту местность или перезайти); предметы не теряются, при более узкой сетке они переезжают в свободные ячейки.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[4] { 5, 6, 7, 8 }), new object[1] { configurationManagerAttributes }));
			if (!FixedLayout)
			{
				Rows = config.Bind<int>(Section, "Rows", DefRows, new ConfigDescription("Rows of cells (over 4 the game's window scrolls). Applies when the chest is loaded again.\nРядов ячеек (больше 4 - родное окно прокручивается). Применяется, когда сундук загрузится заново.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[9] { 2, 3, 4, 5, 6, 7, 8, 9, 10 }), new object[1] { configurationManagerAttributes }));
			}
			Types = config.Bind<string>(Section, "ItemTypes", DefTypes, "Item types it takes, comma-separated (the game's names: Material, Trophy, Consumable, Ammo, Fish...). Only stackable items, never tools, weapons or armour.\nТипы предметов, которые он принимает, через запятую (названия игры: Material, Trophy, Consumable, Ammo, Fish...). Только стакаемые предметы, никогда инструменты, оружие и броня.");
			Include = config.Bind<string>(Section, "AlsoAccept", DefInclude, "Prefab names it takes besides the types, comma-separated (e.g. Coins, Raspberry).\nИмена префабов, которые он принимает сверх типов, через запятую (например Coins, Raspberry).");
			Exclude = config.Bind<string>(Section, "NeverAccept", DefExclude, "Prefab names it never takes, comma-separated (over the types and AlsoAccept).\nИмена префабов, которые он никогда не принимает, через запятую (важнее типов и AlsoAccept).");
			Recipe = config.Bind<string>(Section, "Recipe", DefRecipe, "Price to build: Prefab:amount, comma-separated. A wrong name is left out (see the log).\nЦена постройки: Префаб:количество через запятую. Неверное имя пропускается (см. журнал).");
			Station = config.Bind<string>(Section, "Station", "piece_workbench", new ConfigDescription("The crafting station that must be near to build it; none: no station.\nСтанция, рядом с которой его можно строить; none - без станции.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[7] { "piece_workbench", "forge", "piece_stonecutter", "piece_artisanstation", "blackforge", "piece_magetable", "none" }), new object[1] { configurationManagerAttributes }));
			Rules.Set(Types.Value, Include.Value, Exclude.Value);
		}

		internal void Reload()
		{
			Rules.Set(Types.Value, Include.Value, Exclude.Value);
		}
	}
	internal static class Kinds
	{
		internal static readonly Kind Wood = new Kind
		{
			Id = "deep_woodstore",
			Source = "piece_chest",
			IconItem = "Wood",
			Section = "Woodstore",
			En = "Woodstore",
			Ru = "Дровяной склад",
			DescEn = "Wood, stone, ore and other resources. Every cell keeps one kind of item with no stack limit (up to 1 billion).",
			DescRu = "Дерево, камень, руда и другие ресурсы. В каждой ячейке один вид предмета без предела стопки (до 1 млрд).",
			DefColumns = 8,
			DefRows = 4,
			DefTypes = "Material",
			DefInclude = "",
			DefExclude = "",
			DefRecipe = "Wood:15,Stone:10"
		};

		internal static readonly Kind Trophy = new Kind
		{
			Id = "deep_trophychest",
			Source = "itemstand",
			Fallback = "piece_chest_wood",
			IconItem = "TrophyDeer",
			Section = "TrophyChest",
			En = "Trophy chest",
			Ru = "Сундук трофеев",
			DescEn = "Hangs on a wall. Trophies only, every kind in one cell, as many as you have, in the order of the biomes; always a free cell for the next new kind. Shift + E shows one of its trophies on the plaque.",
			DescRu = "Вешается на стену. Только трофеи: каждый вид в одной ячейке, сколько бы их ни было, по порядку биомов; всегда есть свободная ячейка под новый вид. Shift + E - показать на подставке один из его трофеев.",
			FixedLayout = true,
			DefColumns = 8,
			DefRows = 6,
			DefTypes = "Trophy",
			DefInclude = "",
			DefExclude = "",
			DefRecipe = "Wood:10,Resin:4"
		};

		internal static readonly Kind[] All = new Kind[2] { Wood, Trophy };

		internal static readonly List<Kind> Copies = new List<Kind>();

		internal const string CopyPrefix = "deep_copy_";

		internal static ConfigEntry<bool> CopiesEnabled;

		internal static ConfigEntry<int> CopyCost;

		internal static IEnumerable<Kind> Every()
		{
			Kind[] all = All;
			for (int i = 0; i < all.Length; i++)
			{
				yield return all[i];
			}
			foreach (Kind copy in Copies)
			{
				yield return copy;
			}
		}

		internal static void BindCopies(ConfigFile config)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes
			{
				CustomDrawer = Plugin.Stepper
			};
			CopiesEnabled = config.Bind<bool>("Copies", "Enabled", true, "A Deep copy of every chest of the hammer (wooden, reinforced, black metal, personal, barrel... and other mods' chests): the same model and number of cells, but a cell has no stack limit (up to 1 billion), one kind of item per cell. Any item goes in. Off: the copies leave the hammer's menu, the ones standing keep working.\n«Глубокая» копия каждого сундука молотка (деревянный, укреплённый, из чёрного металла, личный, бочка... и сундуки других модов): та же модель и столько же ячеек, но в ячейке нет предела стопки (до 1 млрд), один вид предмета в ячейке. Принимает любые предметы. Выключено: копии пропадают из меню молотка, стоящие работают как прежде.");
			int[] array = new int[99];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = i + 2;
			}
			CopyCost = config.Bind<int>("Copies", "CostMultiplier", 5, new ConfigDescription("A copy costs the original's price times this (2x to 100x), at the original's crafting station.\nКопия стоит как оригинал, умноженный на это число (от 2x до 100x), у той же станции.", (AcceptableValueBase)(object)new AcceptableValueList<int>(array), new object[1] { configurationManagerAttributes }));
		}

		internal static Kind ByContainerName(string name)
		{
			if (string.IsNullOrEmpty(name) || !name.StartsWith("$deep_", StringComparison.Ordinal))
			{
				return null;
			}
			foreach (Kind item in Every())
			{
				if (item.Name == name)
				{
					return item;
				}
			}
			return null;
		}

		internal static Kind ByPrefab(string prefab)
		{
			foreach (Kind item in Every())
			{
				if (item.Id == prefab)
				{
					return item;
				}
			}
			return null;
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public Action<ConfigEntryBase> CustomDrawer;
	}
	[BepInPlugin("chistix.deepslots", "Deep Slots", "0.1.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "chistix.deepslots";

		public const string Version = "0.1.1";

		private static ManualLogSource log;

		internal static Plugin Instance;

		internal static ConfigEntry<bool> Protect;

		internal static ConfigEntry<bool> DebugLog;

		private static GUIStyle centred;

		internal static bool Russian
		{
			get
			{
				if (Localization.instance != null)
				{
					return Localization.instance.GetSelectedLanguage() == "Russian";
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Protect = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ProtectWhileFilled", true, "A chest that holds anything takes no damage (monsters, weather, a lost support) and cannot be dismantled; empty, it is a normal piece. Off: when it breaks, its contents fall out in the game's stacks, a few per frame.\nСундук, в котором что-то лежит, не получает урона (монстры, погода, потеря опоры) и не разбирается; пустой - обычная постройка. Выключено: при разрушении содержимое выпадает обычными стопками игры, по несколько за кадр.");
			DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLog", false, "More details in the log.\nПодробности в журнал.");
			Kind[] all = Kinds.All;
			for (int i = 0; i < all.Length; i++)
			{
				all[i].Bind(((BaseUnityPlugin)this).Config);
			}
			Kinds.BindCopies(((BaseUnityPlugin)this).Config);
			((BaseUnityPlugin)this).Config.SettingChanged += delegate(object _, SettingChangedEventArgs args)
			{
				ConfigDefinition s = args.ChangedSetting.Definition;
				Kind kind = Kinds.All.FirstOrDefault((Kind k) => k.Section == s.Section);
				if (s.Section == "Copies")
				{
					Prefabs.Refresh();
				}
				else if (kind != null)
				{
					kind.Reload();
					Prefabs.Refresh();
				}
			};
			new Harmony("chistix.deepslots").PatchAll(typeof(Plugin).Assembly);
			Log("Deep Slots 0.1.1");
		}

		private void Start()
		{
			try
			{
				MethodInfo methodInfo = (from a in AppDomain.CurrentDomain.GetAssemblies()
					select a.GetType("ValheimUnified.StackLimits", throwOnError: false)).FirstOrDefault((Type t) => t != null)?.GetMethod("Register", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
				{
					typeof(string),
					typeof(Func<Inventory, ItemData, int>)
				}, null);
				if (!(methodInfo == null))
				{
					Func<Inventory, ItemData, int> func = delegate(Inventory inventory, ItemData item)
					{
						Box box = Cells.Of(inventory);
						return (box != null && item?.m_shared != null && item.m_shared.m_maxStackSize > 1 && box.Rules.Accepts(item)) ? box.Cap : 0;
					};
					methodInfo.Invoke(null, new object[2] { "chistix.deepslots", func });
					Log("ValheimUnified: stack limits of the deep chests registered");
				}
			}
			catch (Exception ex)
			{
				Warn("ValheimUnified stack limits: " + ex.Message);
			}
		}

		internal static void Stepper(ConfigEntryBase entry)
		{
			//IL_0085: 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_0096: Expected O, but got Unknown
			AcceptableValueBase acceptableValues = entry.Description.AcceptableValues;
			if (((object)acceptableValues)?.GetType().GetProperty("AcceptableValues")?.GetValue(acceptableValues, null) is Array { Length: not 0 } array)
			{
				int num = Array.IndexOf(array, entry.BoxedValue);
				if (centred == null)
				{
					centred = new GUIStyle(GUI.skin.label)
					{
						alignment = (TextAnchor)4
					};
				}
				if (GUILayout.Button("‹", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) }))
				{
					entry.BoxedValue = array.GetValue((Math.Max(num, 0) - 1 + array.Length) % array.Length);
				}
				GUILayout.Label(entry.BoxedValue?.ToString() ?? "", centred, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.MinWidth(120f),
					GUILayout.ExpandWidth(true)
				});
				if (GUILayout.Button("›", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) }))
				{
					entry.BoxedValue = array.GetValue((num + 1) % array.Length);
				}
			}
			else
			{
				GUILayout.Label(entry.BoxedValue?.ToString() ?? "", Array.Empty<GUILayoutOption>());
			}
		}

		internal static void Log(string text)
		{
			ManualLogSource obj = log;
			if (obj != null)
			{
				obj.LogInfo((object)text);
			}
		}

		internal static void Warn(string text)
		{
			ManualLogSource obj = log;
			if (obj != null)
			{
				obj.LogWarning((object)text);
			}
		}

		internal static void Debug(string text)
		{
			if (DebugLog != null && DebugLog.Value)
			{
				ManualLogSource obj = log;
				if (obj != null)
				{
					obj.LogInfo((object)text);
				}
			}
		}
	}
	internal static class Prefabs
	{
		private static GameObject holder;

		internal static readonly Dictionary<string, GameObject> Built = new Dictionary<string, GameObject>(StringComparer.Ordinal);

		private static Dictionary<string, GameObject> scenePrefabs;

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

		private static readonly HashSet<Sprite> ours = new HashSet<Sprite>();

		private const int IconSize = 128;

		internal static void Register(ZNetScene scene)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			if ((Object)(object)scene == (Object)null || scene.m_prefabs == null)
			{
				return;
			}
			scenePrefabs = new Dictionary<string, GameObject>(StringComparer.Ordinal);
			foreach (GameObject prefab in scene.m_prefabs)
			{
				if ((Object)(object)prefab != (Object)null && !scenePrefabs.ContainsKey(((Object)prefab).name))
				{
					scenePrefabs[((Object)prefab).name] = prefab;
				}
			}
			if ((Object)(object)holder == (Object)null)
			{
				holder = new GameObject("DeepSlots prefabs");
				holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)holder);
			}
			FindCopies();
			foreach (Kind item in Kinds.Every())
			{
				if (!Built.TryGetValue(item.Id, out var value) || (Object)(object)value == (Object)null)
				{
					value = Make(item);
					if ((Object)(object)value == (Object)null)
					{
						continue;
					}
					Built[item.Id] = value;
				}
				if (scenePrefabs.TryGetValue(item.Id, out var value2) && (Object)(object)value2 != (Object)(object)value)
				{
					Plugin.Warn("prefab name taken by another mod: " + item.Id);
					continue;
				}
				if (!scene.m_prefabs.Contains(value))
				{
					scene.m_prefabs.Add(value);
				}
				scenePrefabs[item.Id] = value;
			}
			Refresh();
		}

		private static void FindCopies()
		{
			if (Kinds.Copies.Count > 0 || !scenePrefabs.TryGetValue("Hammer", out var value) || (Object)(object)value == (Object)null)
			{
				return;
			}
			PieceTable val = value.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.Ordinal);
			foreach (GameObject piece in val.m_pieces)
			{
				if (!((Object)(object)piece == (Object)null) && !((Object)piece).name.StartsWith("deep_", StringComparison.Ordinal))
				{
					Piece component = piece.GetComponent<Piece>();
					Container componentInChildren = piece.GetComponentInChildren<Container>(true);
					if (!((Object)(object)component == (Object)null) && !((Object)(object)componentInChildren == (Object)null) && !((Object)(object)piece.GetComponentInChildren<Vagon>(true) != (Object)null) && !((Object)(object)piece.GetComponentInChildren<Ship>(true) != (Object)null) && !((Object)(object)piece.GetComponentInChildren<Incinerator>(true) != (Object)null) && componentInChildren.m_width * componentInChildren.m_height > 0)
					{
						sortedSet.Add(((Object)piece).name);
					}
				}
			}
			foreach (string item in sortedSet)
			{
				GameObject val2 = scenePrefabs[item];
				Kind kind = new Kind
				{
					Id = "deep_copy_" + item,
					Source = item,
					Copy = true,
					SourcePiece = val2.GetComponent<Piece>()
				};
				kind.Rules.AnyItem = true;
				Kinds.Copies.Add(kind);
			}
			Plugin.Log(string.Format("deep copies of {0} chests: {1}", Kinds.Copies.Count, string.Join(", ", sortedSet)));
		}

		private static GameObject Make(Kind kind)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			if (!scenePrefabs.TryGetValue(kind.Source, out var value) || (Object)(object)value == (Object)null)
			{
				if (kind.Fallback == null || !scenePrefabs.TryGetValue(kind.Fallback, out value) || (Object)(object)value == (Object)null)
				{
					Plugin.Warn(kind.Id + ": no " + kind.Source + " in the game");
					return null;
				}
				Plugin.Warn(kind.Id + ": no " + kind.Source + ", made from " + kind.Fallback);
			}
			GameObject val = Object.Instantiate<GameObject>(value, holder.transform, false);
			((Object)val).name = kind.Id;
			val.transform.localPosition = Vector3.zero;
			Container val2 = val.GetComponentInChildren<Container>(true);
			if ((Object)(object)val2 == (Object)null && (Object)(object)val.GetComponent<ItemStand>() != (Object)null)
			{
				val2 = val.AddComponent<Container>();
				GameObject value2;
				Container val3 = (scenePrefabs.TryGetValue("piece_chest_wood", out value2) ? value2.GetComponentInChildren<Container>(true) : null);
				if ((Object)(object)val3 != (Object)null)
				{
					val2.m_bkg = val3.m_bkg;
					val2.m_openEffects = val3.m_openEffects;
					val2.m_closeEffects = val3.m_closeEffects;
				}
				ItemStand component = val.GetComponent<ItemStand>();
				component.m_name = kind.Name;
				component.m_autoAttach = false;
			}
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Warn(kind.Id + ": " + kind.Source + " has no Container");
				Object.DestroyImmediate((Object)(object)val);
				return null;
			}
			val2.m_name = kind.Name;
			if (!kind.Copy)
			{
				val2.m_width = kind.Columns.Value;
				val2.m_height = kind.RowsNow(kind.Columns.Value);
				val2.m_privacy = (PrivacySetting)2;
			}
			val2.m_defaultItems = new DropTable();
			val2.m_autoDestroyEmpty = false;
			val2.m_destroyedLootPrefab = null;
			Piece component2 = val.GetComponent<Piece>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_name = kind.Name;
				component2.m_description = kind.Name + "_desc";
				component2.m_enabled = true;
			}
			Plugin.Log(kind.Id + ": made from " + kind.Source);
			return val;
		}

		private static GameObject Find(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(name);
				if ((Object)(object)prefab != (Object)null)
				{
					return prefab;
				}
			}
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name);
				if ((Object)(object)itemPrefab != (Object)null)
				{
					return itemPrefab;
				}
			}
			if (scenePrefabs == null || !scenePrefabs.TryGetValue(name, out var value))
			{
				return null;
			}
			return value;
		}

		internal static void Refresh()
		{
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Expected O, but got Unknown
			//IL_0278: 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_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Expected O, but got Unknown
			foreach (Kind copy in Kinds.Copies)
			{
				if (!Built.TryGetValue(copy.Id, out var value) || (Object)(object)value == (Object)null || (Object)(object)copy.SourcePiece == (Object)null)
				{
					continue;
				}
				Piece component = value.GetComponent<Piece>();
				if (!((Object)(object)component == (Object)null))
				{
					int times = Kinds.CopyCost.Value;
					component.m_resources = copy.SourcePiece.m_resources.Where((Requirement q) => q != null && (Object)(object)q.m_resItem != (Object)null).Select((Func<Requirement, Requirement>)((Requirement q) => new Requirement
					{
						m_resItem = q.m_resItem,
						m_amount = Math.Max(1, q.m_amount) * times,
						m_amountPerLevel = q.m_amountPerLevel,
						m_recover = q.m_recover
					})).ToArray();
					component.m_craftingStation = copy.SourcePiece.m_craftingStation;
					component.m_icon = Badged(copy.SourcePiece.m_icon);
				}
			}
			Kind[] all = Kinds.All;
			foreach (Kind kind in all)
			{
				if (!Built.TryGetValue(kind.Id, out var value2) || (Object)(object)value2 == (Object)null)
				{
					continue;
				}
				Container componentInChildren = value2.GetComponentInChildren<Container>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.m_width = kind.Columns.Value;
					componentInChildren.m_height = kind.RowsNow(kind.Columns.Value);
				}
				Piece component2 = value2.GetComponent<Piece>();
				if ((Object)(object)component2 == (Object)null)
				{
					continue;
				}
				List<Requirement> list = new List<Requirement>();
				foreach (var item3 in Rules.ParseRecipe(kind.Recipe.Value))
				{
					string item = item3.item;
					int item2 = item3.amount;
					GameObject obj = Find(item);
					ItemDrop val = ((obj != null) ? obj.GetComponent<ItemDrop>() : null);
					if ((Object)(object)val == (Object)null)
					{
						Plugin.Warn(kind.Id + ": no item " + item + " for the recipe");
						continue;
					}
					list.Add(new Requirement
					{
						m_resItem = val,
						m_amount = item2,
						m_recover = true
					});
				}
				if (list.Count == 0)
				{
					GameObject obj2 = Find("Wood");
					ItemDrop val2 = ((obj2 != null) ? obj2.GetComponent<ItemDrop>() : null);
					if ((Object)(object)val2 != (Object)null)
					{
						list.Add(new Requirement
						{
							m_resItem = val2,
							m_amount = 10,
							m_recover = true
						});
					}
				}
				component2.m_resources = list.ToArray();
				string value3 = kind.Station.Value;
				object craftingStation;
				if (!(value3 == "none"))
				{
					GameObject obj3 = Find(value3);
					craftingStation = ((obj3 != null) ? obj3.GetComponent<CraftingStation>() : null);
				}
				else
				{
					craftingStation = null;
				}
				component2.m_craftingStation = (CraftingStation)craftingStation;
				GameObject obj4 = Find(kind.IconItem);
				ItemDrop val3 = ((obj4 != null) ? obj4.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val3 != (Object)null && val3.m_itemData?.m_shared?.m_icons != null && val3.m_itemData.m_shared.m_icons.Length != 0)
				{
					component2.m_icon = val3.m_itemData.m_shared.m_icons[0];
				}
				component2.m_icon = Badged(component2.m_icon);
			}
			Hammer();
		}

		internal static Sprite Badged(Sprite icon)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_0137: 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_0038: Invalid comparison between Unknown and I4
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: 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_0180: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)icon == (Object)null || ours.Contains(icon))
			{
				return icon;
			}
			if (badged.TryGetValue(icon, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				return icon;
			}
			RenderTexture val = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				Texture2D texture = icon.texture;
				if ((Object)(object)texture == (Object)null)
				{
					return icon;
				}
				Rect val2;
				try
				{
					val2 = icon.textureRect;
				}
				catch
				{
					val2 = icon.rect;
				}
				val = (RenderTexture.active = RenderTexture.GetTemporary(128, 128, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2));
				GL.Clear(true, true, Color.clear);
				Graphics.Blit((Texture)(object)texture, val, new Vector2(((Rect)(ref val2)).width / (float)((Texture)texture).width, ((Rect)(ref val2)).height / (float)((Texture)texture).height), new Vector2(((Rect)(ref val2)).x / (float)((Texture)texture).width, ((Rect)(ref val2)).y / (float)((Texture)texture).height));
				RenderTexture.active = val;
				Texture2D val3 = new Texture2D(128, 128, (TextureFormat)4, false)
				{
					name = "deep_icon_" + ((Object)icon).name,
					wrapMode = (TextureWrapMode)1,
					filterMode = (FilterMode)1
				};
				val3.ReadPixels(new Rect(0f, 0f, 128f, 128f), 0, 0, false);
				Color32[] pixels = val3.GetPixels32();
				byte[] array = new byte[pixels.Length * 4];
				for (int i = 0; i < pixels.Length; i++)
				{
					Color32 val4 = pixels[i];
					array[i * 4] = val4.r;
					array[i * 4 + 1] = val4.g;
					array[i * 4 + 2] = val4.b;
					array[i * 4 + 3] = val4.a;
				}
				SlotBadge.Apply(array, 128, bottomUp: true);
				for (int j = 0; j < pixels.Length; j++)
				{
					pixels[j] = new Color32(array[j * 4], array[j * 4 + 1], array[j * 4 + 2], array[j * 4 + 3]);
				}
				val3.SetPixels32(pixels);
				val3.Apply(false, true);
				Sprite val5 = Sprite.Create(val3, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), icon.pixelsPerUnit * 128f / Mathf.Max(1f, ((Rect)(ref val2)).width));
				((Object)val5).name = ((Object)val3).name;
				badged[icon] = val5;
				ours.Add(val5);
				return val5;
			}
			catch (Exception ex)
			{
				Plugin.Warn("icon badge for " + ((Object)icon).name + ": " + ex.Message);
				badged[icon] = icon;
				return icon;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val);
				}
			}
		}

		internal static void Hammer()
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("Hammer") : null);
			PieceTable val2 = ((!((Object)(object)val != (Object)null)) ? null : val.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			bool flag = false;
			foreach (Kind item in Kinds.Every())
			{
				if (Built.TryGetValue(item.Id, out var value) && !((Object)(object)value == (Object)null))
				{
					bool flag2 = item.On;
					bool flag3 = val2.m_pieces.Contains(value);
					if (flag2 && !flag3)
					{
						val2.m_pieces.Add(value);
						flag = true;
					}
					else if (!flag2 && flag3)
					{
						val2.m_pieces.Remove(value);
						flag = true;
					}
				}
			}
			if (flag)
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					Traverse.Create((object)localPlayer).Method("UpdateAvailablePiecesList", Array.Empty<object>()).GetValue();
				}
			}
		}
	}
	public static class SlotBadge
	{
		public const float Share = 0.48f;

		private static readonly byte[] Fill = new byte[3] { 22, 20, 18 };

		private static readonly byte[] Frame = new byte[3] { 214, 176, 104 };

		private static readonly byte[] Sign = new byte[3] { 248, 238, 214 };

		public static void Apply(byte[] rgba, int size, bool bottomUp)
		{
			if (rgba == null || size < 8 || rgba.Length < size * size * 4)
			{
				return;
			}
			float num = (float)Math.Round((float)size * 0.48f);
			float num2 = Math.Max(1f, (float)size * 0.02f);
			float num3 = (float)size - num2 - num / 2f;
			float num4 = (float)size - num2 - num / 2f;
			float num5 = num / 2f;
			float r = num * 0.14f;
			float num6 = Math.Max(1.5f, num * 0.075f);
			float num7 = Math.Max(1.5f, num * 0.07f);
			float a = num * 0.355f;
			float num8 = Math.Max(1.2f, num * 0.068f);
			float[] p = Lemniscate(a, num3, num4, 256);
			int num9 = Math.Max(0, (int)Math.Floor(num3 - num5 - num7 - 1f));
			for (int i = Math.Max(0, (int)Math.Floor(num4 - num5 - num7 - 1f)); i < size; i++)
			{
				for (int j = num9; j < size; j++)
				{
					float num10 = (float)j + 0.5f;
					float num11 = (float)i + 0.5f;
					float num12 = RoundBox(num10 - num3, num11 - num4, num5, r);
					int i2 = ((bottomUp ? (size - 1 - i) : i) * size + j) * 4;
					if (num12 > 0f)
					{
						float num13 = Clamp01(1f - num12 / num7) * 0.55f;
						if (num13 > 0f)
						{
							Blend(rgba, i2, 0, 0, 0, num13);
						}
						continue;
					}
					float num14 = Clamp01(0f - num12);
					float num15 = Clamp01(num12 + num6 + 0.5f);
					float num16 = (num11 - (num4 - num5)) / num;
					byte r2 = (byte)((float)(int)Fill[0] + 18f * (1f - num16));
					byte g = (byte)((float)(int)Fill[1] + 16f * (1f - num16));
					byte b = (byte)((float)(int)Fill[2] + 12f * (1f - num16));
					Blend(rgba, i2, r2, g, b, 0.95f * num14);
					if (num15 > 0f)
					{
						Blend(rgba, i2, Frame[0], Frame[1], Frame[2], num15 * num14);
					}
					if (!(num15 >= 1f))
					{
						float num17 = Nearest(p, num10, num11);
						float num18 = Clamp01(num8 + 1.6f - num17 + 0.5f) * 0.8f;
						if (num18 > 0f)
						{
							Blend(rgba, i2, 0, 0, 0, num18 * (1f - num15));
						}
						float num19 = Clamp01(num8 - num17 + 0.5f);
						if (num19 > 0f)
						{
							Blend(rgba, i2, Sign[0], Sign[1], Sign[2], num19 * (1f - num15));
						}
					}
				}
			}
		}

		private static float[] Lemniscate(float a, float cx, float cy, int n)
		{
			float[] array = new float[n * 2];
			for (int i = 0; i < n; i++)
			{
				double num = Math.PI * 2.0 * (double)i / (double)n;
				double num2 = Math.Sin(num);
				double num3 = Math.Cos(num);
				double num4 = 1.0 + num2 * num2;
				array[i * 2] = (float)((double)cx + (double)a * num3 / num4);
				array[i * 2 + 1] = (float)((double)cy + (double)a * num2 * num3 / num4 * 1.15);
			}
			return array;
		}

		private static float Nearest(float[] p, float x, float y)
		{
			float num = float.MaxValue;
			for (int i = 0; i < p.Length; i += 2)
			{
				float num2 = p[i] - x;
				float num3 = p[i + 1] - y;
				float num4 = num2 * num2 + num3 * num3;
				if (num4 < num)
				{
					num = num4;
				}
			}
			return (float)Math.Sqrt(num);
		}

		private static float RoundBox(float x, float y, float half, float r)
		{
			float val = Math.Abs(x) - half + r;
			float num = Math.Abs(y) - half + r;
			float num2 = Math.Max(val, 0f);
			float num3 = Math.Max(num, 0f);
			return (float)Math.Sqrt(num2 * num2 + num3 * num3) + Math.Min(Math.Max(val, num), 0f) - r;
		}

		private static float Clamp01(float v)
		{
			if (!(v < 0f))
			{
				if (!(v > 1f))
				{
					return v;
				}
				return 1f;
			}
			return 0f;
		}

		private static void Blend(byte[] p, int i, byte r, byte g, byte b, float k)
		{
			if (!(k <= 0f))
			{
				if (k > 1f)
				{
					k = 1f;
				}
				float num = (float)(int)p[i + 3] / 255f;
				float num2 = k + num * (1f - k);
				if (!(num2 <= 0f))
				{
					p[i] = (byte)Math.Round(((float)(int)r * k + (float)(int)p[i] * num * (1f - k)) / num2);
					p[i + 1] = (byte)Math.Round(((float)(int)g * k + (float)(int)p[i + 1] * num * (1f - k)) / num2);
					p[i + 2] = (byte)Math.Round(((float)(int)b * k + (float)(int)p[i + 2] * num * (1f - k)) / num2);
					p[i + 3] = (byte)Math.Round(num2 * 255f);
				}
			}
		}
	}
	internal static class Trophies
	{
		internal sealed class Entry
		{
			internal string Prefab;

			internal string Name;

			internal Sprite Icon;
		}

		private static readonly string[] Order = new string[54]
		{
			"TrophyBoar", "TrophyNeck", "TrophyDeer", "TrophyEikthyr", "TrophyGreydwarf", "TrophyGreydwarfBrute", "TrophyGreydwarfShaman", "TrophySkeleton", "TrophyGhost", "TrophyBjorn",
			"TrophyForestTroll", "TrophyTheElder", "TrophyDraugr", "TrophyDraugrElite", "TrophyLeech", "TrophyBlob", "TrophySkeletonPoison", "TrophySurtling", "TrophyWraith", "TrophyAbomination",
			"TrophyKvastur", "TrophyBonemass", "TrophySerpent", "TrophyWolf", "TrophyFenring", "TrophyUlv", "TrophyCultist", "TrophyHatchling", "TrophySGolem", "TrophyDragonQueen",
			"TrophyDeathsquito", "TrophyGoblin", "TrophyGoblinBrute", "TrophyGoblinShaman", "TrophyLox", "TrophyGrowth", "TrophyBjornUndead", "TrophyGoblinKing", "TrophySeeker", "TrophySeekerBrute",
			"TrophyTick", "TrophyHare", "TrophyGjall", "TrophyDvergr", "TrophySeekerQueen", "TrophyAsksvin", "TrophyVolture", "TrophyCharredMelee", "TrophyCharredArcher", "TrophyCharredMage",
			"TrophyMorgen", "TrophyBonemawSerpent", "TrophyFallenValkyrie", "TrophyFader"
		};

		internal static readonly List<Entry> List = new List<Entry>();

		internal static Dictionary<string, int> Slots;

		private static ObjectDB builtFor;

		internal static void Build(bool force = false)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Invalid comparison between Unknown and I4
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || instance.m_items == null || instance.m_items.Count == 0 || (!force && (Object)(object)builtFor == (Object)(object)instance && List.Count > 0))
			{
				return;
			}
			Dictionary<string, Entry> dictionary = new Dictionary<string, Entry>(StringComparer.Ordinal);
			foreach (GameObject item in instance.m_items)
			{
				if (!((Object)(object)item == (Object)null))
				{
					SharedData val = item.GetComponent<ItemDrop>()?.m_itemData?.m_shared;
					if (val != null && (int)val.m_itemType == 13 && !string.IsNullOrEmpty(val.m_name) && !dictionary.ContainsKey(((Object)item).name))
					{
						dictionary[((Object)item).name] = new Entry
						{
							Prefab = ((Object)item).name,
							Name = val.m_name,
							Icon = ((val.m_icons != null && val.m_icons.Length != 0) ? val.m_icons[0] : null)
						};
					}
				}
			}
			List<Entry> list = new List<Entry>();
			string[] order = Order;
			foreach (string key in order)
			{
				if (dictionary.TryGetValue(key, out var value))
				{
					list.Add(value);
					dictionary.Remove(key);
				}
			}
			List<Entry> list2 = new List<Entry>(dictionary.Values);
			list2.Sort((Entry a, Entry b) => string.CompareOrdinal(a.Prefab, b.Prefab));
			list.AddRange(list2);
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.Ordinal);
			List.Clear();
			foreach (Entry item2 in list)
			{
				if (!dictionary2.ContainsKey(item2.Name))
				{
					dictionary2[item2.Name] = List.Count;
					List.Add(item2);
				}
			}
			Slots = dictionary2;
			builtFor = instance;
			Plugin.Log($"trophy chest: {List.Count} kinds of trophies ({list.Count - list2.Count} of the game's order, {list2.Count} others)");
		}

		internal static int Collected(Inventory inventory)
		{
			if (Slots == null)
			{
				return 0;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (ItemData item in inventory.m_inventory)
			{
				if (item.m_stack > 0 && Slots.ContainsKey(item.m_shared.m_name))
				{
					hashSet.Add(item.m_shared.m_name);
				}
			}
			return hashSet.Count;
		}
	}
	internal static class TrophyStand
	{
		[HarmonyPatch(typeof(ItemStand), "Interact")]
		private static class Use
		{
			private static bool Prefix(ItemStand __instance, Humanoid user, bool hold, bool alt, ref bool __result)
			{
				Container val = Ours(__instance);
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				if (alt)
				{
					if (!hold)
					{
						Turn(__instance, val, user);
					}
					__result = true;
					return false;
				}
				__result = val.Interact(user, hold, false);
				return false;
			}
		}

		[HarmonyPatch(typeof(ItemStand), "UseItem")]
		private static class UseHotbar
		{
			private static bool Prefix(ItemStand __instance, ref bool __result)
			{
				if ((Object)(object)Ours(__instance) == (Object)null)
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(ItemStand), "GetHoverText")]
		private static class HoverText
		{
			private static void Postfix(ItemStand __instance, ref string __result)
			{
				Container val = Ours(__instance);
				if (!((Object)(object)val == (Object)null))
				{
					__result = val.GetHoverText() + Localization.instance.Localize("\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $deep_change_model");
				}
			}
		}

		[HarmonyPatch(typeof(ItemStand), "GetHoverName")]
		private static class HoverName
		{
			private static void Postfix(ItemStand __instance, ref string __result)
			{
				Container val = Ours(__instance);
				if ((Object)(object)val != (Object)null)
				{
					__result = val.GetHoverName();
				}
			}
		}

		[HarmonyPatch(typeof(ItemStand), "DropItem")]
		private static class NoDrop
		{
			private static bool Prefix(ItemStand __instance)
			{
				return (Object)(object)Ours(__instance) == (Object)null;
			}
		}

		internal static Container Ours(ItemStand stand)
		{
			if ((Object)(object)stand == (Object)null)
			{
				return null;
			}
			Container component = ((Component)stand).GetComponent<Container>();
			if (!((Object)(object)component != (Object)null) || !(component.m_name == Kinds.Trophy.Name))
			{
				return null;
			}
			return component;
		}

		private static List<GameObject> Models(Container c)
		{
			List<GameObject> list = new List<GameObject>();
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || c.m_inventory == null)
			{
				return list;
			}
			List<ItemData> list2 = new List<ItemData>(c.m_inventory.m_inventory);
			list2.Sort((ItemData a, ItemData b) => (a.m_gridPos.y == b.m_gridPos.y) ? a.m_gridPos.x.CompareTo(b.m_gridPos.x) : a.m_gridPos.y.CompareTo(b.m_gridPos.y));
			foreach (ItemData item in list2)
			{
				GameObject val = null;
				foreach (Trophies.Entry item2 in Trophies.List)
				{
					if (item2.Name == item.m_shared.m_name)
					{
						val = instance.GetItemPrefab(item2.Prefab);
						break;
					}
				}
				if ((Object)(object)val == (Object)null && (Object)(object)item.m_dropPrefab != (Object)null)
				{
					val = instance.GetItemPrefab(((Object)item.m_dropPrefab).name);
				}
				if (!((Object)(object)val == (Object)null) && !list.Contains(val) && !((Object)(object)ItemStand.GetAttachPrefab(val) == (Object)null))
				{
					list.Add(val);
				}
			}
			return list;
		}

		private static void Turn(ItemStand stand, Container c, Humanoid user)
		{
			ZNetView nview = stand.m_nview;
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return;
			}
			List<GameObject> list = Models(c);
			if (list.Count == 0)
			{
				if (user != null)
				{
					((Character)user).Message((MessageType)2, "$deep_no_trophies", 0, (Sprite)null, false);
				}
				return;
			}
			int num = nview.GetZDO().GetInt(ZDOVars.s_item, 0);
			int num2 = -1;
			for (int i = 0; i < list.Count; i++)
			{
				if (StringExtensionMethods.GetStableHashCode(((Object)list[i]).name) == num)
				{
					num2 = i;
					break;
				}
			}
			int num3 = num2 + 1;
			if (num3 >= list.Count)
			{
				nview.InvokeRPC("RPC_DestroyAttachment", Array.Empty<object>());
				if (user != null)
				{
					((Character)user).Message((MessageType)2, "$deep_no_model", 0, (Sprite)null, false);
				}
				return;
			}
			GameObject val = list[num3];
			nview.InvokeRPC(ZNetView.Everybody, "SetVisualItem", new object[4]
			{
				StringExtensionMethods.GetStableHashCode(((Object)val).name),
				0,
				1,
				0
			});
			string text = val.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_name;
			if (text != null && user != null)
			{
				((Character)user).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}
	}
	internal static class Words
	{
		private static readonly Action<Localization, string, string> AddWord = AccessTools.MethodDelegate<Action<Localization, string, string>>(AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null), (object)null, true);

		private static readonly (string key, string en, string ru)[] Texts = new(string, string, string)[10]
		{
			("deep_total", "Total", "Всего"),
			("deep_cells", "Cells used", "Занято ячеек"),
			("deep_noremove", "Can be dismantled only when empty", "Разобрать можно только пустым"),
			("deep_refused", "This storage does not take that item", "Сюда этот предмет не принимают"),
			("deep_noroom", "Not enough room", "Не хватает места"),
			("deep_trophy_missing", "Not collected yet", "Ещё не добыт"),
			("deep_collected", "Kinds collected", "Собрано видов"),
			("deep_change_model", "Change trophy", "Сменить трофей"),
			("deep_no_trophies", "Put a trophy in first", "Сначала положите трофей"),
			("deep_no_model", "No trophy shown", "Без трофея")
		};

		internal static void Add(Localization localization, string language)
		{
			if (localization == null || AddWord == null)
			{
				return;
			}
			bool flag = string.Equals(language, "Russian", StringComparison.OrdinalIgnoreCase);
			Kind[] all = Kinds.All;
			foreach (Kind kind in all)
			{
				AddWord(localization, kind.Id, flag ? kind.Ru : kind.En);
				AddWord(localization, kind.Id + "_desc", flag ? kind.DescRu : kind.DescEn);
			}
			(string, string, string)[] texts = Texts;
			for (int i = 0; i < texts.Length; i++)
			{
				var (arg, text, text2) = texts[i];
				AddWord(localization, arg, flag ? text2 : text);
			}
			foreach (Kind copy in Kinds.Copies)
			{
				if (!((Object)(object)copy.SourcePiece == (Object)null))
				{
					string text3 = localization.Localize(copy.SourcePiece.m_name);
					AddWord(localization, copy.Id, Cells.CopyName(text3, flag));
					AddWord(localization, copy.Id + "_desc", flag ? ("Копия «" + text3 + "»: столько же ячеек, но в ячейке нет предела стопки (до 1 млрд). Один вид предмета в ячейке, принимает любые предметы.") : ("A copy of the " + text3 + ": as many cells, but a cell has no stack limit (up to 1 billion). One kind of item per cell, takes any item."));
				}
			}
		}

		internal static void Refresh()
		{
			Localization instance = Localization.instance;
			if (instance != null)
			{
				Add(instance, instance.GetSelectedLanguage());
			}
		}
	}
}