Decompiled source of GrillspettItemDrawers v1.0.0

plugins/ItemDrawers.Core.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;

[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("ItemDrawers.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+7be62b9b999934a60580658f7b1b2e447be02a32")]
[assembly: AssemblyProduct("ItemDrawers.Core")]
[assembly: AssemblyTitle("ItemDrawers.Core")]
[assembly: AssemblyVersion("1.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 ItemDrawers.Core
{
	public readonly struct IconSize
	{
		public readonly string Name;

		public readonly int Width;

		public readonly int Height;

		public IconSize(string name, int width, int height)
		{
			Name = name;
			Width = width;
			Height = height;
		}
	}
	public readonly struct AtlasRect
	{
		public readonly int X;

		public readonly int Y;

		public readonly int Width;

		public readonly int Height;

		public AtlasRect(int x, int y, int width, int height)
		{
			X = x;
			Y = y;
			Width = width;
			Height = height;
		}
	}
	public sealed class AtlasLayout
	{
		public int Width { get; }

		public int Height { get; }

		public IReadOnlyDictionary<string, AtlasRect> Rects { get; }

		public AtlasLayout(int width, int height, IReadOnlyDictionary<string, AtlasRect> rects)
		{
			Width = width;
			Height = height;
			Rects = rects;
		}

		public bool TryGetUv(string name, out float u0, out float v0, out float u1, out float v1)
		{
			u0 = (v0 = (u1 = (v1 = 0f)));
			if (name == null || !Rects.TryGetValue(name, out var value))
			{
				return false;
			}
			u0 = (float)value.X / (float)Width;
			v0 = (float)value.Y / (float)Height;
			u1 = (float)(value.X + value.Width) / (float)Width;
			v1 = (float)(value.Y + value.Height) / (float)Height;
			return true;
		}
	}
	public static class ChunkSplitter
	{
		public static IReadOnlyList<int> Chunks(int amount, int stackSize)
		{
			List<int> list = new List<int>();
			if (amount <= 0)
			{
				return list;
			}
			int num = ((stackSize < 1) ? 1 : stackSize);
			int num2 = amount;
			while (num2 > 0)
			{
				int num3 = ((num2 < num) ? num2 : num);
				list.Add(num3);
				num2 -= num3;
			}
			return list;
		}
	}
	public static class DrawerMeshBuilder
	{
		private const float UvScale = 1f;

		private static readonly int[] Signs = new int[2] { -1, 1 };

		public static MeshData Build(DrawerProportions p)
		{
			MeshData.Builder builder = new MeshData.Builder();
			float width = p.Width;
			float height = p.Height;
			float depth = p.Depth;
			float num = Math.Min(p.FrameThickness, Math.Min(width, height) / 2f - 0.02f);
			float num2 = Math.Min(p.RecessDepth, depth * 0.5f);
			float bevel = p.Bevel;
			AddChamferBox(builder, 0f, 0f, (0f - num2) / 2f, width, height, depth - num2, bevel);
			float cz = depth / 2f - num2 / 2f;
			AddChamferBox(builder, 0f, height / 2f - num / 2f, cz, width, num, num2, bevel);
			AddChamferBox(builder, 0f, (0f - height) / 2f + num / 2f, cz, width, num, num2, bevel);
			float num3 = height - 2f * num;
			if (num3 > 0.01f)
			{
				AddChamferBox(builder, (0f - width) / 2f + num / 2f, 0f, cz, num, num3, num2, bevel);
				AddChamferBox(builder, width / 2f - num / 2f, 0f, cz, num, num3, num2, bevel);
			}
			AddHandle(builder, p, num, num2);
			return builder.Build();
		}

		private static void AddHandle(MeshData.Builder gb, DrawerProportions p, float frame, float recess)
		{
			float num = p.Depth / 2f - recess;
			float num2 = p.Height - 2f * frame;
			switch (p.Handle)
			{
			case HandleStyle.Bar:
			{
				float w2 = Math.Min(p.HandleWidth, p.Width - 2f * frame - 0.02f);
				float cy = (0f - num2) / 2f + p.HandleSection * 1.4f;
				AddChamferBox(gb, 0f, cy, num + p.HandleProud / 2f, w2, p.HandleSection, p.HandleProud, Math.Min(p.Bevel, p.HandleSection / 2.5f));
				break;
			}
			case HandleStyle.Knobs:
			{
				float num3 = Math.Min(p.HandleWidth / 2f, p.Width / 2f - frame - p.HandleSection);
				for (int i = -1; i <= 1; i += 2)
				{
					AddChamferBox(gb, num3 * (float)i, 0f, num + p.HandleProud / 2f, p.HandleSection, p.HandleSection, p.HandleProud, p.HandleSection / 3f);
				}
				break;
			}
			case HandleStyle.Pull:
			{
				float w = Math.Min(p.HandleWidth, p.Width - 2f * frame);
				AddChamferBox(gb, 0f, (0f - p.Height) / 2f + frame + p.HandleSection / 2f, p.Depth / 2f - p.HandleProud / 2f, w, p.HandleSection, p.HandleProud, p.Bevel);
				break;
			}
			case HandleStyle.None:
				break;
			}
		}

		public static MeshData ChamferBox(float cx, float cy, float cz, float w, float h, float d, float chamfer)
		{
			MeshData.Builder builder = new MeshData.Builder();
			AddChamferBox(builder, cx, cy, cz, w, h, d, chamfer);
			return builder.Build();
		}

		private static void AddChamferBox(MeshData.Builder gb, float cx, float cy, float cz, float w, float h, float d, float chamfer)
		{
			float num = w / 2f;
			float num2 = h / 2f;
			float num3 = d / 2f;
			float num4 = Math.Max(0f, Math.Min(chamfer, Math.Min(num, Math.Min(num2, num3)) * 0.98f));
			float[] extent = new float[3] { num, num2, num3 };
			float[] inner = new float[3]
			{
				num - num4,
				num2 - num4,
				num3 - num4
			};
			float[] centre = new float[3] { cx, cy, cz };
			int[][] array = new int[4][]
			{
				new int[2] { -1, -1 },
				new int[2] { 1, -1 },
				new int[2] { 1, 1 },
				new int[2] { -1, 1 }
			};
			int[] signs;
			for (int i = 0; i < 3; i++)
			{
				signs = Signs;
				foreach (int num5 in signs)
				{
					int num6 = (i + 1) % 3;
					int num7 = (i + 2) % 3;
					float[][] array2 = new float[4][];
					for (int k = 0; k < 4; k++)
					{
						int[] array3 = new int[3];
						array3[i] = num5;
						array3[num6] = array[k][0];
						array3[num7] = array[k][1];
						array2[k] = Point(i, array3);
					}
					float[] array4 = new float[3];
					array4[i] = num5;
					gb.Quad(array2[0], array2[1], array2[2], array2[3], array4, 1f);
				}
			}
			for (int l = 0; l < 3; l++)
			{
				int num8 = (l + 1) % 3;
				int num9 = (l + 2) % 3;
				signs = Signs;
				foreach (int num10 in signs)
				{
					int[] signs2 = Signs;
					foreach (int num11 in signs2)
					{
						float[][] array5 = new float[2][];
						float[][] array6 = new float[2][];
						for (int n = 0; n < 2; n++)
						{
							int[] array7 = new int[3];
							array7[l] = Signs[n];
							array7[num8] = num10;
							array7[num9] = num11;
							array5[n] = Point(num8, array7);
							array6[n] = Point(num9, array7);
						}
						float[] array8 = new float[3];
						array8[num8] = num10;
						array8[num9] = num11;
						gb.Quad(array5[0], array5[1], array6[1], array6[0], array8, 1f);
					}
				}
			}
			signs = Signs;
			foreach (int num12 in signs)
			{
				int[] signs2 = Signs;
				foreach (int num13 in signs2)
				{
					int[] signs3 = Signs;
					foreach (int num15 in signs3)
					{
						int[] s = new int[3] { num12, num13, num15 };
						float[] hint = new float[3] { num12, num13, num15 };
						gb.TriangleHinted(Point(0, s), Point(1, s), Point(2, s), hint, 1f);
					}
				}
			}
			float[] Point(int axis, int[] array10)
			{
				float[] array9 = new float[3];
				for (int num16 = 0; num16 < 3; num16++)
				{
					array9[num16] = centre[num16] + (float)array10[num16] * ((num16 == axis) ? extent[num16] : inner[num16]);
				}
				return array9;
			}
		}
	}
	public enum HandleStyle
	{
		None,
		Bar,
		Knobs,
		Pull
	}
	public sealed class DrawerProportions
	{
		public float Width = 0.66f;

		public float Height = 0.66f;

		public float Depth = 0.66f;

		public float FrameThickness = 0.033f;

		public float RecessDepth = 0.0198f;

		public float Bevel = 0.00396f;

		public float HandleWidth = 0.264f;

		public float HandleSection = 0.0429f;

		public float HandleProud = 0.0231f;

		public HandleStyle Handle = HandleStyle.Bar;

		public float LabelScale = 0.98f;

		public float LabelSize
		{
			get
			{
				float num = Width - 2f * FrameThickness;
				float num2 = Height - 2f * FrameThickness;
				if (Handle == HandleStyle.Bar)
				{
					num2 -= HandleSection * 3f;
				}
				float num3 = ((num < num2) ? num : num2) * LabelScale;
				if (!(num3 < 0.05f))
				{
					return num3;
				}
				return 0.05f;
			}
		}
	}
	public readonly struct DrawerSnapshot : IEquatable<DrawerSnapshot>
	{
		public readonly string ItemName;

		public readonly int Amount;

		public bool IsAssigned => !string.IsNullOrEmpty(ItemName);

		public bool IsEmpty => Amount <= 0;

		public DrawerSnapshot(string itemName, int amount)
		{
			ItemName = itemName ?? "";
			Amount = ((amount >= 0) ? amount : 0);
		}

		public bool Equals(DrawerSnapshot other)
		{
			if (string.Equals(ItemName, other.ItemName, StringComparison.Ordinal))
			{
				return Amount == other.Amount;
			}
			return false;
		}

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

		public override int GetHashCode()
		{
			return ((ItemName?.GetHashCode() ?? 0) * 397) ^ Amount;
		}

		public override string ToString()
		{
			if (!IsAssigned)
			{
				return "(empty drawer)";
			}
			return $"{ItemName} x{Amount}";
		}
	}
	public static class DrawerTextureGenerator
	{
		private readonly struct Knot
		{
			public readonly float X;

			public readonly float Y;

			public readonly float Radius;

			public readonly float Strength;

			public Knot(float x, float y, float radius, float strength)
			{
				X = x;
				Y = y;
				Radius = radius;
				Strength = strength;
			}
		}

		public static TextureData Generate(TextureTier tier, int width, int height, int seed)
		{
			if (width < 2 || height < 2)
			{
				throw new ArgumentException($"Texture must be at least 2x2, got {width}x{height}.");
			}
			float[] heights = BuildHeightField(tier, width, height, seed);
			byte[] albedo = BuildAlbedo(tier, heights, width, height);
			byte[] normal = BuildNormal(heights, width, height, NormalStrength(tier));
			return new TextureData(width, height, albedo, normal);
		}

		private static float[] BuildHeightField(TextureTier tier, int width, int height, int seed)
		{
			return tier switch
			{
				TextureTier.Wood => BuildWoodHeight(width, height, seed), 
				TextureTier.Stone => BuildStoneHeight(width, height, seed), 
				TextureTier.BlackMarble => BuildMarbleHeight(width, height, seed), 
				_ => BuildWoodHeight(width, height, seed), 
			};
		}

		private static float[] BuildWoodHeight(int width, int height, int seed)
		{
			float[] array = new float[width * height];
			Knot[] knots = MakeKnots(seed, width, height, 3, 6f, 14f);
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					float num = PeriodicNoise.Fbm(j, i, width, height, seed + 11, 2, 7, 2f, 0.6f) * 1.3f;
					float num2 = (float)i * 7f / (float)height + num;
					float num3 = num2 - (float)Math.Floor(num2);
					float num4 = Math.Min(num3, 1f - num3);
					float num5 = 1f - Clamp01(num4 / 0.08f);
					float num6 = PeriodicNoise.Fbm(j, i, width, height, seed + 23, 4, 48, 2.1f, 0.55f);
					float num7 = PeriodicNoise.Fbm(j, i, width, height, seed + 37, 3, 5);
					float num8 = KnotContribution(knots, j, i, width, height);
					float v = 0.55f + num7 * 0.08f + num6 * 0.018f - num5 * 0.14f + num8;
					array[i * width + j] = Clamp01(v);
				}
			}
			return array;
		}

		private static float[] BuildStoneHeight(int width, int height, int seed)
		{
			float[] array = new float[width * height];
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					float num = PeriodicNoise.Fbm(j, i, width, height, seed + 5, 3, 6);
					float num2 = PeriodicNoise.Fbm(j, i, width, height, seed + 61, 3, 34);
					float v = 0.5f + num * 0.15f + num2 * 0.045f;
					array[i * width + j] = Clamp01(v);
				}
			}
			return array;
		}

		private static float[] BuildMarbleHeight(int width, int height, int seed)
		{
			float[] array = new float[width * height];
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					float value = PeriodicNoise.Fbm(j, i, width, height, seed + 7, 3, 5, 2.3f);
					float num = (float)Math.Pow(Clamp01((1f - Math.Abs(value) - 0.82f) / 0.18f), 2.0);
					float num2 = PeriodicNoise.Fbm(j, i, width, height, seed + 89, 2, 40);
					float v = 0.16f + num * 0.22f + num2 * 0.02f;
					array[i * width + j] = Clamp01(v);
				}
			}
			return array;
		}

		private static Knot[] MakeKnots(int seed, int width, int height, int count, float minRadius, float maxRadius)
		{
			Random random = new Random(seed + 999);
			Knot[] array = new Knot[count];
			float num = (float)width / 2f;
			float num2 = (float)height / 2f;
			float num3 = (float)width * 0.22f;
			float num4 = (float)height * 0.22f;
			for (int i = 0; i < count; i++)
			{
				float num5 = 0f;
				float num6 = 0f;
				for (int j = 0; j < 20; j++)
				{
					num5 = (float)(random.NextDouble() * (double)width);
					num6 = (float)(random.NextDouble() * (double)height);
					if (!(Math.Abs(num5 - num) < num3) || !(Math.Abs(num6 - num2) < num4))
					{
						break;
					}
				}
				float radius = minRadius + (float)random.NextDouble() * (maxRadius - minRadius);
				float strength = 0.03f + (float)random.NextDouble() * 0.03f;
				array[i] = new Knot(num5, num6, radius, strength);
			}
			return array;
		}

		private static float KnotContribution(Knot[] knots, int x, int y, int width, int height)
		{
			float num = 0f;
			for (int i = 0; i < knots.Length; i++)
			{
				Knot knot = knots[i];
				float num2 = PeriodicNoise.ToroidalDistance(x, y, knot.X, knot.Y, width, height);
				if (!(num2 >= knot.Radius))
				{
					float num3 = num2 / knot.Radius;
					float num4 = (float)Math.Pow(1f - num3, 2.0);
					num -= knot.Strength * num4;
				}
			}
			return num;
		}

		private static (float r, float g, float b) HueRatio(TextureTier tier)
		{
			return tier switch
			{
				TextureTier.Wood => (r: 1f, g: 0.84f, b: 0.66f), 
				TextureTier.Stone => (r: 0.97f, g: 0.98f, b: 1f), 
				TextureTier.BlackMarble => (r: 0.86f, g: 0.95f, b: 1f), 
				_ => (r: 1f, g: 0.8f, b: 0.56f), 
			};
		}

		public static float MidLightness(TextureTier tier)
		{
			var (num, num2) = LightnessRange(tier);
			return (num + num2) / 2f;
		}

		private static (float min, float max) LightnessRange(TextureTier tier)
		{
			return tier switch
			{
				TextureTier.Wood => (min: 0.24f, max: 0.6f), 
				TextureTier.Stone => (min: 0.34f, max: 0.64f), 
				TextureTier.BlackMarble => (min: 0.04f, max: 0.3f), 
				_ => (min: 0.28f, max: 0.66f), 
			};
		}

		private static byte[] BuildAlbedo(TextureTier tier, float[] heights, int width, int height)
		{
			(float r, float g, float b) tuple = HueRatio(tier);
			float item = tuple.r;
			float item2 = tuple.g;
			float item3 = tuple.b;
			(float min, float max) tuple2 = LightnessRange(tier);
			float item4 = tuple2.min;
			float item5 = tuple2.max;
			byte[] array = new byte[width * height * 4];
			for (int i = 0; i < heights.Length; i++)
			{
				float num = item4 + heights[i] * (item5 - item4);
				int num2 = i * 4;
				array[num2] = ToByte(num * item);
				array[num2 + 1] = ToByte(num * item2);
				array[num2 + 2] = ToByte(num * item3);
				array[num2 + 3] = byte.MaxValue;
			}
			return array;
		}

		private static float NormalStrength(TextureTier tier)
		{
			return tier switch
			{
				TextureTier.Wood => 3f, 
				TextureTier.Stone => 1.6f, 
				TextureTier.BlackMarble => 1.1f, 
				_ => 2f, 
			};
		}

		private static byte[] BuildNormal(float[] heights, int width, int height, float strength)
		{
			byte[] array = new byte[width * height * 4];
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					float num = At(heights, j - 1, i - 1, width, height);
					float num2 = At(heights, j, i - 1, width, height);
					float num3 = At(heights, j + 1, i - 1, width, height);
					float num4 = At(heights, j - 1, i, width, height);
					float num5 = At(heights, j + 1, i, width, height);
					float num6 = At(heights, j - 1, i + 1, width, height);
					float num7 = At(heights, j, i + 1, width, height);
					float num8 = At(heights, j + 1, i + 1, width, height);
					float num9 = num3 + 2f * num5 + num8 - (num + 2f * num4 + num6);
					float num10 = num6 + 2f * num7 + num8 - (num + 2f * num2 + num3);
					float num11 = (0f - num9) * strength;
					float num12 = (0f - num10) * strength;
					float num13 = 1f;
					float num14 = (float)Math.Sqrt(num11 * num11 + num12 * num12 + num13 * num13);
					num11 /= num14;
					num12 /= num14;
					num13 /= num14;
					int num15 = (i * width + j) * 4;
					array[num15] = ToByte(num11 * 0.5f + 0.5f);
					array[num15 + 1] = ToByte(num12 * 0.5f + 0.5f);
					array[num15 + 2] = ToByte(num13 * 0.5f + 0.5f);
					array[num15 + 3] = byte.MaxValue;
				}
			}
			return array;
		}

		private static float At(float[] field, int x, int y, int width, int height)
		{
			int num = (x % width + width) % width;
			int num2 = (y % height + height) % height;
			return field[num2 * width + num];
		}

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

		private static byte ToByte(float v)
		{
			v = Clamp01(v);
			return (byte)Math.Round(v * 255f);
		}
	}
	public static class IconAtlasPacker
	{
		private const int Padding = 2;

		public static AtlasLayout Pack(IReadOnlyList<IconSize> icons, int maxDimension = 4096)
		{
			if (icons == null)
			{
				throw new ArgumentNullException("icons");
			}
			if (icons.Count == 0)
			{
				return new AtlasLayout(1, 1, new Dictionary<string, AtlasRect>());
			}
			int num = maxDimension - 2;
			foreach (IconSize icon in icons)
			{
				if (icon.Width <= 0 || icon.Height <= 0)
				{
					throw new ArgumentException($"Icon '{icon.Name}' has invalid dimensions {icon.Width}×{icon.Height}. " + "Icon width and height must be positive.");
				}
				if (icon.Width > num || icon.Height > num)
				{
					throw new ArgumentException($"Icon '{icon.Name}' has dimensions {icon.Width}×{icon.Height}, " + $"but maximum icon size for maxDimension={maxDimension} is {num}×{num} " + $"(atlas dimension - {2} pixel padding).");
				}
			}
			List<IconSize> sorted = icons.OrderByDescending((IconSize i) => i.Height).ToList();
			for (int num2 = 64; num2 <= maxDimension; num2 *= 2)
			{
				if (TryPackInto(sorted, num2, out var rects))
				{
					return new AtlasLayout(num2, num2, rects);
				}
			}
			throw new InvalidOperationException($"Cannot fit {icons.Count} icons into a {maxDimension}×{maxDimension} atlas.");
		}

		private static bool TryPackInto(List<IconSize> sorted, int size, out Dictionary<string, AtlasRect> rects)
		{
			rects = new Dictionary<string, AtlasRect>(sorted.Count);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (IconSize item in sorted)
			{
				int num4 = item.Width + 2;
				int num5 = item.Height + 2;
				if (num4 > size || num5 > size)
				{
					return false;
				}
				if (num3 + num4 > size)
				{
					num += num2;
					num2 = 0;
					num3 = 0;
				}
				if (num + num5 > size)
				{
					return false;
				}
				rects[item.Name] = new AtlasRect(num3, num, item.Width, item.Height);
				num3 += num4;
				if (num5 > num2)
				{
					num2 = num5;
				}
			}
			return true;
		}
	}
	public sealed class MeshData
	{
		internal sealed class Builder
		{
			private readonly List<float> _pos = new List<float>(4096);

			private readonly List<float> _nor = new List<float>(4096);

			private readonly List<float> _uv = new List<float>(2731);

			public void Triangle(float[] a, float[] b, float[] c, float uvScale)
			{
				float num = b[0] - a[0];
				float num2 = b[1] - a[1];
				float num3 = b[2] - a[2];
				float num4 = c[0] - a[0];
				float num5 = c[1] - a[1];
				float num6 = c[2] - a[2];
				float num7 = num2 * num6 - num3 * num5;
				float num8 = num3 * num4 - num * num6;
				float num9 = num * num5 - num2 * num4;
				float num10 = (float)Math.Sqrt(num7 * num7 + num8 * num8 + num9 * num9);
				if (!(num10 < 1E-09f))
				{
					num7 /= num10;
					num8 /= num10;
					num9 /= num10;
					float num11 = Math.Abs(num7);
					float num12 = Math.Abs(num8);
					float num13 = Math.Abs(num9);
					int num14;
					int num15;
					if (num11 >= num12 && num11 >= num13)
					{
						num14 = 2;
						num15 = 1;
					}
					else if (num12 >= num13)
					{
						num14 = 0;
						num15 = 2;
					}
					else
					{
						num14 = 0;
						num15 = 1;
					}
					float[][] array = new float[3][] { a, b, c };
					foreach (float[] array2 in array)
					{
						_pos.Add(array2[0]);
						_pos.Add(array2[1]);
						_pos.Add(array2[2]);
						_nor.Add(num7);
						_nor.Add(num8);
						_nor.Add(num9);
						_uv.Add(array2[num14] * uvScale);
						_uv.Add(array2[num15] * uvScale);
					}
				}
			}

			public void Quad(float[] a, float[] b, float[] c, float[] d, float[] hint, float uvScale)
			{
				float num = b[0] - a[0];
				float num2 = b[1] - a[1];
				float num3 = b[2] - a[2];
				float num4 = c[0] - a[0];
				float num5 = c[1] - a[1];
				float num6 = c[2] - a[2];
				float num7 = num2 * num6 - num3 * num5;
				float num8 = num3 * num4 - num * num6;
				float num9 = num * num5 - num2 * num4;
				if (num7 * hint[0] + num8 * hint[1] + num9 * hint[2] < 0f)
				{
					float[] array = b;
					b = d;
					d = array;
				}
				Triangle(a, b, c, uvScale);
				Triangle(a, c, d, uvScale);
			}

			public void TriangleHinted(float[] a, float[] b, float[] c, float[] hint, float uvScale)
			{
				float num = b[0] - a[0];
				float num2 = b[1] - a[1];
				float num3 = b[2] - a[2];
				float num4 = c[0] - a[0];
				float num5 = c[1] - a[1];
				float num6 = c[2] - a[2];
				float num7 = num2 * num6 - num3 * num5;
				float num8 = num3 * num4 - num * num6;
				float num9 = num * num5 - num2 * num4;
				if (num7 * hint[0] + num8 * hint[1] + num9 * hint[2] < 0f)
				{
					float[] array = b;
					b = c;
					c = array;
				}
				Triangle(a, b, c, uvScale);
			}

			public MeshData Build()
			{
				return new MeshData(_pos.ToArray(), _nor.ToArray(), _uv.ToArray());
			}
		}

		public float[] Vertices { get; }

		public float[] Normals { get; }

		public float[] Uvs { get; }

		public int VertexCount => Vertices.Length / 3;

		public int TriangleCount => VertexCount / 3;

		public MeshData(float[] vertices, float[] normals, float[] uvs)
		{
			Vertices = vertices;
			Normals = normals;
			Uvs = uvs;
		}
	}
	public static class PeriodicNoise
	{
		public static float Sample(float x, float y, int cells, int seed)
		{
			if (cells < 1)
			{
				cells = 1;
			}
			float num = (float)Math.Floor(x);
			float num2 = (float)Math.Floor(y);
			int num3 = Mod((int)num, cells);
			int num4 = Mod((int)num2, cells);
			int x2 = Mod(num3 + 1, cells);
			int y2 = Mod(num4 + 1, cells);
			float t = x - num;
			float t2 = y - num2;
			float t3 = Fade(t);
			float t4 = Fade(t2);
			float a = HashValue(num3, num4, seed);
			float b = HashValue(x2, num4, seed);
			float a2 = HashValue(num3, y2, seed);
			float b2 = HashValue(x2, y2, seed);
			float a3 = Lerp(a, b, t3);
			float b3 = Lerp(a2, b2, t3);
			return Lerp(a3, b3, t4);
		}

		public static float Fbm(float px, float py, int width, int height, int seed, int octaves, int baseCells, float lacunarity = 2f, float gain = 0.5f)
		{
			float num = 0f;
			float num2 = 1f;
			float num3 = 0f;
			int num4 = Math.Max(1, baseCells);
			for (int i = 0; i < octaves; i++)
			{
				float x = px * (float)num4 / (float)width;
				float y = py * (float)num4 / (float)height;
				num += Sample(x, y, num4, seed + i * 101) * num2;
				num3 += num2;
				num2 *= gain;
				num4 = Math.Max(1, (int)Math.Round((float)num4 * lacunarity));
			}
			if (!(num3 > 0f))
			{
				return 0f;
			}
			return num / num3;
		}

		public static float ToroidalDistance(float ax, float ay, float bx, float by, int width, int height)
		{
			float num = WrapDelta(ax - bx, width);
			float num2 = WrapDelta(ay - by, height);
			return (float)Math.Sqrt(num * num + num2 * num2);
		}

		private static float WrapDelta(float d, int period)
		{
			d %= (float)period;
			if (d > (float)period / 2f)
			{
				d -= (float)period;
			}
			if (d < (float)(-period) / 2f)
			{
				d += (float)period;
			}
			return d;
		}

		private static int Mod(int a, int m)
		{
			int num = a % m;
			if (num >= 0)
			{
				return num;
			}
			return num + m;
		}

		private static float Fade(float t)
		{
			return t * t * t * (t * (t * 6f - 15f) + 10f);
		}

		private static float Lerp(float a, float b, float t)
		{
			return a + t * (b - a);
		}

		private static float HashValue(int x, int y, int seed)
		{
			int num = x * 374761393 + y * 668265263 + seed * 1274126177;
			int num2 = (num ^ (num >>> 13)) * 1274126177;
			return (float)(uint)(num2 ^ (num2 >>> 16)) / 4.2949673E+09f * 2f - 1f;
		}
	}
	public sealed class SpatialGrid<T>
	{
		private readonly struct Cell : IEquatable<Cell>
		{
			public readonly int X;

			public readonly int Y;

			public readonly int Z;

			public Cell(int x, int y, int z)
			{
				X = x;
				Y = y;
				Z = z;
			}

			public bool Equals(Cell o)
			{
				if (X == o.X && Y == o.Y)
				{
					return Z == o.Z;
				}
				return false;
			}

			public override bool Equals(object o)
			{
				if (o is Cell o2)
				{
					return Equals(o2);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (X * 73856093) ^ (Y * 19349663) ^ (Z * 83492791);
			}
		}

		private readonly float _cellSize;

		private readonly Dictionary<Cell, List<T>> _cells = new Dictionary<Cell, List<T>>();

		private readonly Dictionary<T, (Cell cell, float x, float y, float z)> _index = new Dictionary<T, (Cell, float, float, float)>();

		public int Count => _index.Count;

		public SpatialGrid(float cellSize)
		{
			if (cellSize <= 0f)
			{
				throw new ArgumentOutOfRangeException("cellSize");
			}
			_cellSize = cellSize;
		}

		private Cell CellOf(float x, float y, float z)
		{
			return new Cell((int)Math.Floor(x / _cellSize), (int)Math.Floor(y / _cellSize), (int)Math.Floor(z / _cellSize));
		}

		public void Insert(T item, float x, float y, float z)
		{
			if (_index.ContainsKey(item))
			{
				Move(item, x, y, z);
				return;
			}
			Cell cell = CellOf(x, y, z);
			if (!_cells.TryGetValue(cell, out var value))
			{
				value = new List<T>(4);
				_cells[cell] = value;
			}
			value.Add(item);
			_index[item] = (cell, x, y, z);
		}

		public bool Remove(T item)
		{
			if (!_index.TryGetValue(item, out (Cell, float, float, float) value))
			{
				return false;
			}
			if (_cells.TryGetValue(value.Item1, out var value2))
			{
				value2.Remove(item);
				if (value2.Count == 0)
				{
					_cells.Remove(value.Item1);
				}
			}
			_index.Remove(item);
			return true;
		}

		public void Move(T item, float x, float y, float z)
		{
			Remove(item);
			Insert(item, x, y, z);
		}

		public void Query(float x, float y, float z, float radius, List<T> results)
		{
			if (results == null)
			{
				throw new ArgumentNullException("results");
			}
			if (radius <= 0f)
			{
				return;
			}
			int num = (int)Math.Ceiling(radius / _cellSize);
			Cell cell = CellOf(x, y, z);
			float num2 = radius * radius;
			for (int i = -num; i <= num; i++)
			{
				for (int j = -num; j <= num; j++)
				{
					for (int k = -num; k <= num; k++)
					{
						Cell key = new Cell(cell.X + i, cell.Y + j, cell.Z + k);
						if (!_cells.TryGetValue(key, out var value))
						{
							continue;
						}
						for (int l = 0; l < value.Count; l++)
						{
							T val = value[l];
							(Cell cell, float x, float y, float z) tuple = _index[val];
							float num3 = tuple.x - x;
							float num4 = tuple.y - y;
							float num5 = tuple.z - z;
							if (num3 * num3 + num4 * num4 + num5 * num5 <= num2)
							{
								results.Add(val);
							}
						}
					}
				}
			}
		}
	}
	public sealed class TextureData
	{
		public int Width { get; }

		public int Height { get; }

		public byte[] Albedo { get; }

		public byte[] Normal { get; }

		public TextureData(int width, int height, byte[] albedo, byte[] normal)
		{
			Width = width;
			Height = height;
			Albedo = albedo;
			Normal = normal;
		}
	}
	public enum TextureTier
	{
		Wood,
		Stone,
		BlackMarble
	}
}

plugins/ItemDrawers.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using ItemDrawers.Core;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ItemDrawers")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+7be62b9b999934a60580658f7b1b2e447be02a32")]
[assembly: AssemblyProduct("ItemDrawers")]
[assembly: AssemblyTitle("ItemDrawers")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ItemDrawers.Game
{
	internal static class DebugCommands
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__2_0;

			public static ConsoleEvent <>9__2_1;

			internal void <Register>b__2_0(ConsoleEventArgs args)
			{
				//IL_00b4: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Expected O, but got Unknown
				//IL_0112: Unknown result type (might be due to invalid IL or missing references)
				//IL_0114: Unknown result type (might be due to invalid IL or missing references)
				//IL_0127: Unknown result type (might be due to invalid IL or missing references)
				//IL_012c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0131: Unknown result type (might be due to invalid IL or missing references)
				//IL_014a: 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_0154: Unknown result type (might be due to invalid IL or missing references)
				//IL_0157: Unknown result type (might be due to invalid IL or missing references)
				//IL_015b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0160: Unknown result type (might be due to invalid IL or missing references)
				//IL_0165: Unknown result type (might be due to invalid IL or missing references)
				//IL_016a: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return;
				}
				int num = ((args.Length > 1) ? int.Parse(args[1]) : 10);
				int num2 = ((args.Length > 2) ? int.Parse(args[2]) : 10);
				DrawerTier drawerTier = DrawerTier.Wood;
				if (args.Length > 3)
				{
					if (args[3].Equals("stone", StringComparison.OrdinalIgnoreCase))
					{
						drawerTier = DrawerTier.Stone;
					}
					else if (args[3].StartsWith("black", StringComparison.OrdinalIgnoreCase))
					{
						drawerTier = DrawerTier.BlackMarble;
					}
				}
				GameObject prefab = ZNetScene.instance.GetPrefab(DrawerTiers.PrefabName(drawerTier));
				if ((Object)(object)prefab == (Object)null)
				{
					args.Context.AddString("Drawer prefab not found");
					return;
				}
				Transform transform = ((Component)Player.m_localPlayer).transform;
				Vector3 val = transform.position + transform.forward * 6f;
				Vector3 right = transform.right;
				int num3 = 0;
				DrawerProportions val2 = new DrawerProportions();
				float num4 = val2.Width + 0.02f;
				float num5 = val2.Height + 0.02f;
				for (int i = 0; i < num2; i++)
				{
					for (int j = 0; j < num; j++)
					{
						Vector3 val3 = val + right * (((float)j - (float)(num - 1) / 2f) * num4) + Vector3.up * ((float)i * num5 + val2.Height / 2f);
						DrawerComponent component = Object.Instantiate<GameObject>(prefab, val3, Quaternion.LookRotation(-transform.forward, Vector3.up)).GetComponent<DrawerComponent>();
						if ((Object)(object)component != (Object)null)
						{
							string itemName = SampleItems[(j + i * num) % SampleItems.Length];
							component.TryDepositExternally(itemName, 250 + (j * 7 + i * 13) % 500, out var _);
						}
						num3++;
					}
				}
				args.Context.AddString($"Built {num3} drawers ({num}x{num2}, {drawerTier})");
			}

			internal void <Register>b__2_1(ConsoleEventArgs args)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				int count = DrawerComponent.All.Count;
				int num = 0;
				int num2 = 0;
				foreach (DrawerComponent item in DrawerComponent.All)
				{
					DrawerSnapshot snapshot = item.Snapshot;
					if (((DrawerSnapshot)(ref snapshot)).IsAssigned)
					{
						num++;
					}
					num2 += snapshot.Amount;
				}
				args.Context.AddString($"drawers loaded : {count}");
				args.Context.AddString($"assigned       : {num}");
				args.Context.AddString($"items held     : {num2}");
				args.Context.AddString($"atlas built    : {DrawerIconAtlas.IsBuilt}");
			}
		}

		private static readonly string[] SampleItems = new string[6] { "Wood", "Stone", "Coal", "Iron", "Resin", "Flint" };

		private const float WallGap = 0.02f;

		public static void Register()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_006c: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			object obj = <>c.<>9__2_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					//IL_00b4: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
					//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
					//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
					//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
					//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
					//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
					//IL_00e4: Expected O, but got Unknown
					//IL_0112: Unknown result type (might be due to invalid IL or missing references)
					//IL_0114: Unknown result type (might be due to invalid IL or missing references)
					//IL_0127: Unknown result type (might be due to invalid IL or missing references)
					//IL_012c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0131: Unknown result type (might be due to invalid IL or missing references)
					//IL_014a: 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_0154: Unknown result type (might be due to invalid IL or missing references)
					//IL_0157: Unknown result type (might be due to invalid IL or missing references)
					//IL_015b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0160: Unknown result type (might be due to invalid IL or missing references)
					//IL_0165: Unknown result type (might be due to invalid IL or missing references)
					//IL_016a: Unknown result type (might be due to invalid IL or missing references)
					if (!((Object)(object)Player.m_localPlayer == (Object)null))
					{
						int num = ((args.Length > 1) ? int.Parse(args[1]) : 10);
						int num2 = ((args.Length > 2) ? int.Parse(args[2]) : 10);
						DrawerTier drawerTier = DrawerTier.Wood;
						if (args.Length > 3)
						{
							if (args[3].Equals("stone", StringComparison.OrdinalIgnoreCase))
							{
								drawerTier = DrawerTier.Stone;
							}
							else if (args[3].StartsWith("black", StringComparison.OrdinalIgnoreCase))
							{
								drawerTier = DrawerTier.BlackMarble;
							}
						}
						GameObject prefab = ZNetScene.instance.GetPrefab(DrawerTiers.PrefabName(drawerTier));
						if ((Object)(object)prefab == (Object)null)
						{
							args.Context.AddString("Drawer prefab not found");
						}
						else
						{
							Transform transform = ((Component)Player.m_localPlayer).transform;
							Vector3 val3 = transform.position + transform.forward * 6f;
							Vector3 right = transform.right;
							int num3 = 0;
							DrawerProportions val4 = new DrawerProportions();
							float num4 = val4.Width + 0.02f;
							float num5 = val4.Height + 0.02f;
							for (int i = 0; i < num2; i++)
							{
								for (int j = 0; j < num; j++)
								{
									Vector3 val5 = val3 + right * (((float)j - (float)(num - 1) / 2f) * num4) + Vector3.up * ((float)i * num5 + val4.Height / 2f);
									DrawerComponent component = Object.Instantiate<GameObject>(prefab, val5, Quaternion.LookRotation(-transform.forward, Vector3.up)).GetComponent<DrawerComponent>();
									if ((Object)(object)component != (Object)null)
									{
										string itemName = SampleItems[(j + i * num) % SampleItems.Length];
										component.TryDepositExternally(itemName, 250 + (j * 7 + i * 13) % 500, out var _);
									}
									num3++;
								}
							}
							args.Context.AddString($"Built {num3} drawers ({num}x{num2}, {drawerTier})");
						}
					}
				};
				<>c.<>9__2_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("rid_wall", "rid_wall <cols> <rows> [wood|stone|blackmarble] - build a test wall of drawers", (ConsoleEvent)obj, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__2_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate(ConsoleEventArgs args)
				{
					//IL_0023: Unknown result type (might be due to invalid IL or missing references)
					//IL_0028: Unknown result type (might be due to invalid IL or missing references)
					//IL_0038: Unknown result type (might be due to invalid IL or missing references)
					int count = DrawerComponent.All.Count;
					int num = 0;
					int num2 = 0;
					foreach (DrawerComponent item in DrawerComponent.All)
					{
						DrawerSnapshot snapshot = item.Snapshot;
						if (((DrawerSnapshot)(ref snapshot)).IsAssigned)
						{
							num++;
						}
						num2 += snapshot.Amount;
					}
					args.Context.AddString($"drawers loaded : {count}");
					args.Context.AddString($"assigned       : {num}");
					args.Context.AddString($"items held     : {num2}");
					args.Context.AddString($"atlas built    : {DrawerIconAtlas.IsBuilt}");
				};
				<>c.<>9__2_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("rid_stats", "rid_stats - report drawer counts and rendering cost", (ConsoleEvent)obj2, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}
	}
	internal static class DrawerAssignUI
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Close;
		}

		private const float PanelWidth = 260f;

		private const float PanelHeight = 340f;

		private const float RowHeight = 32f;

		private static GameObject _panel;

		private static Transform _content;

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

		private static DrawerComponent _openDrawer;

		private static Player _openPlayer;

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

		public static void EnsureBuilt()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: 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_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Expected O, but got Unknown
			if (!((Object)(object)_panel != (Object)null) && GUIManager.Instance != null && !((Object)(object)GUIManager.CustomGUIFront == (Object)null))
			{
				GUIManager instance = GUIManager.Instance;
				_panel = instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 260f, 340f);
				_panel.SetActive(false);
				((Object)instance.CreateText("Assign item", _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -18f), instance.AveriaSerifBold, 18, Color.white, true, Color.black, 240f, 24f, false)).name = "Title";
				GameObject obj = instance.CreateScrollView(_panel.transform, false, true, 8f, 2f, ColorBlock.defaultColorBlock, new Color(0f, 0f, 0f, 0.4f), 240f, 250f);
				RectTransform val = (RectTransform)obj.transform;
				val.anchorMin = new Vector2(0.5f, 1f);
				val.anchorMax = new Vector2(0.5f, 1f);
				val.pivot = new Vector2(0.5f, 1f);
				val.anchoredPosition = new Vector2(0f, -48f);
				_content = obj.transform.Find("Scroll View/Viewport/Content");
				ButtonClickedEvent onClick = instance.CreateButton("Cancel", _panel.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 20f), 100f, 28f).GetComponent<Button>().onClick;
				object obj2 = <>O.<0>__Close;
				if (obj2 == null)
				{
					UnityAction val2 = Close;
					<>O.<0>__Close = val2;
					obj2 = (object)val2;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj2);
			}
		}

		public static void Open(DrawerComponent drawer, Player player)
		{
			//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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: 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_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Expected O, but got Unknown
			EnsureBuilt();
			if ((Object)(object)_panel == (Object)null || (Object)(object)_content == (Object)null)
			{
				return;
			}
			DrawerSnapshot snapshot = drawer.Snapshot;
			if (((DrawerSnapshot)(ref snapshot)).IsAssigned)
			{
				((Character)player).Message((MessageType)2, "Already holds " + ItemFacts.LocalizedName(snapshot.ItemName) + " -- Shift+Interact to add more", 0, (Sprite)null, false);
				return;
			}
			Dictionary<string, int> dictionary = ItemFacts.StorableItemCounts(((Humanoid)player).GetInventory());
			if (dictionary.Count == 0)
			{
				((Character)player).Message((MessageType)2, "Nothing storable to assign", 0, (Sprite)null, false);
				return;
			}
			ClearRows();
			foreach (KeyValuePair<string, int> item in dictionary.OrderBy((KeyValuePair<string, int> kv) => ItemFacts.LocalizedName(kv.Key)))
			{
				string itemName = item.Key;
				int value = item.Value;
				GameObject val = GUIManager.Instance.CreateButton($"{ItemFacts.LocalizedName(itemName)}  x{value}", _content, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), Vector2.zero, 220f, 32f);
				LayoutElement obj = val.AddComponent<LayoutElement>();
				obj.preferredHeight = 32f;
				obj.minHeight = 32f;
				AddRowIcon(val, itemName);
				((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
				{
					OnRowClicked(itemName);
				});
				_rows.Add(val);
			}
			_openDrawer = drawer;
			_openPlayer = player;
			_panel.SetActive(true);
			GUIManager.BlockInput(true);
		}

		public static void Close()
		{
			if (!((Object)(object)_panel == (Object)null) && _panel.activeSelf)
			{
				_panel.SetActive(false);
				GUIManager.BlockInput(false);
				_openDrawer = null;
				_openPlayer = null;
				ClearRows();
			}
		}

		public static void CloseIfShowing(DrawerComponent drawer)
		{
			if ((Object)(object)_openDrawer == (Object)(object)drawer)
			{
				Close();
			}
		}

		private static void OnRowClicked(string itemName)
		{
			DrawerComponent openDrawer = _openDrawer;
			Player openPlayer = _openPlayer;
			Close();
			if ((Object)(object)openDrawer != (Object)null && (Object)(object)openPlayer != (Object)null)
			{
				openDrawer.AssignAndDeposit(openPlayer, itemName);
			}
		}

		private static void ClearRows()
		{
			foreach (GameObject row in _rows)
			{
				if ((Object)(object)row != (Object)null)
				{
					Object.Destroy((Object)(object)row);
				}
			}
			_rows.Clear();
		}

		private static void AddRowIcon(GameObject row, string itemName)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0082: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			float num = 24f;
			GameObject val = new GameObject("Icon", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(row.transform, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = new Vector2(0f, 0.5f);
			val2.anchorMax = new Vector2(0f, 0.5f);
			val2.pivot = new Vector2(0f, 0.5f);
			val2.anchoredPosition = new Vector2(4f, 0f);
			val2.sizeDelta = new Vector2(num, num);
			Image component = val.GetComponent<Image>();
			component.sprite = ItemFacts.Icon(itemName);
			component.preserveAspect = true;
			val.SetActive((Object)(object)component.sprite != (Object)null);
			Text componentInChildren = row.GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				RectTransform rectTransform = ((Graphic)componentInChildren).rectTransform;
				rectTransform.offsetMin = new Vector2(4f + num + 4f, rectTransform.offsetMin.y);
			}
		}
	}
	public class DrawerComponent : Container, Interactable, Hoverable
	{
		public static readonly List<DrawerComponent> All = new List<DrawerComponent>();

		private const string KeyAssignedItem = "AssignedItem";

		private static readonly int AssignedItemHash = StringExtensionMethods.GetStableHashCode("AssignedItem");

		private const string OldKeyPrefab = "Prefab";

		private const string OldKeyAmount = "Amount";

		private static readonly int OldPrefabHash = StringExtensionMethods.GetStableHashCode("Prefab");

		private static readonly int OldAmountHash = StringExtensionMethods.GetStableHashCode("Amount");

		private static readonly int CreatorHash = StringExtensionMethods.GetStableHashCode("creator");

		internal const string CommitFailedMessage = "Try again";

		private static readonly ConditionalWeakTable<Inventory, DrawerComponent> InventoryOwners = new ConditionalWeakTable<Inventory, DrawerComponent>();

		private ZNetView _view;

		private ZDOID _zdoId = ZDOID.None;

		private bool _enforcingType;

		internal ZDOID ZdoId => _zdoId;

		internal DrawerTier Tier { get; private set; }

		public DrawerRenderer Face { get; private set; }

		public DrawerSnapshot Snapshot
		{
			get
			{
				//IL_0021: 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_006d: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_view == (Object)null || !_view.IsValid())
				{
					return new DrawerSnapshot("", 0);
				}
				string text = _view.GetZDO().GetString(AssignedItemHash, "");
				if (string.IsNullOrEmpty(text))
				{
					return new DrawerSnapshot("", 0);
				}
				Inventory inventory = ((Container)this).GetInventory();
				int num = ((inventory != null) ? ItemFacts.CountByPrefab(inventory, text) : 0);
				return new DrawerSnapshot(text, num);
			}
		}

		public int Capacity => DrawerConfig.SlotsFor(Tier) * ItemFacts.MaxStackSize(Snapshot.ItemName);

		internal string DiagId
		{
			get
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				if (!((ZDOID)(ref _zdoId)).IsNone())
				{
					return $"{((Object)((Component)this).gameObject).name}#{_zdoId}";
				}
				return ((Object)((Component)this).gameObject).name;
			}
		}

		internal static bool InventoryOwnersLookup(Inventory inventory, out DrawerComponent drawer)
		{
			return InventoryOwners.TryGetValue(inventory, out drawer);
		}

		private void Awake()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			_view = ((Component)this).GetComponent<ZNetView>();
			Face = ((Component)this).GetComponentInChildren<DrawerRenderer>();
			if (!((Object)(object)_view == (Object)null) && _view.IsValid())
			{
				_zdoId = _view.GetZDO().m_uid;
				Tier = TierFromPrefabName(((Object)((Component)this).gameObject).name);
				base.m_width = DrawerConfig.SlotsFor(Tier);
				base.m_height = 1;
				base.m_name = DrawerTiers.DisplayName(Tier);
				base.m_privacy = (PrivacySetting)2;
				EnsureCreator();
				((Container)this).Awake();
				Inventory inventory = ((Container)this).GetInventory();
				if (inventory != null)
				{
					InventoryOwners.Remove(inventory);
					InventoryOwners.Add(inventory, this);
					MigrateOldFormatIfNeeded(inventory);
					All.Add(this);
					DrawerManager.Instance?.Register(this);
				}
			}
		}

		private void MigrateOldFormatIfNeeded(Inventory inventory)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_view == (Object)null || !_view.IsValid() || !_view.IsOwner())
			{
				return;
			}
			ZDO zDO = _view.GetZDO();
			string text = zDO.GetString(OldPrefabHash, "");
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			int num = zDO.GetInt(OldAmountHash, 0);
			if (num > 0 && ItemFacts.IsStorable(text))
			{
				int num2 = DepositByPrefab(inventory, text, num);
				int num3 = num - num2;
				if (num3 > 0)
				{
					ItemFacts.SpillAtPosition(((Component)this).transform.position, text, num3);
				}
			}
			zDO.Set(AssignedItemHash, text);
			zDO.Set(OldAmountHash, 0, false);
			zDO.Set(OldPrefabHash, "");
			DrawerPlugin.Log.LogInfo((object)$"Migrated drawer '{DiagId}' from the old single-stack format ({num} {text}).");
		}

		private void EnsureCreator()
		{
			if ((Object)(object)_view == (Object)null || !_view.IsValid())
			{
				return;
			}
			ZDO zDO = _view.GetZDO();
			if (_view.IsOwner() && zDO.GetLong(CreatorHash, 0L) == 0L)
			{
				PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null);
				if (val != null)
				{
					zDO.Set(CreatorHash, val.GetPlayerID());
				}
			}
		}

		private void OnDestroy()
		{
			All.Remove(this);
			DrawerManager.Instance?.Unregister(this);
			DrawerAssignUI.CloseIfShowing(this);
			DrawerTakeAmountUI.CloseIfShowing(this);
		}

		private static DrawerTier TierFromPrefabName(string name)
		{
			DrawerTier[] all = DrawerTiers.All;
			foreach (DrawerTier drawerTier in all)
			{
				if (name.StartsWith(DrawerTiers.PrefabName(drawerTier)))
				{
					return drawerTier;
				}
			}
			return DrawerTier.Wood;
		}

		public void RefreshFace()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Face == (Object)null))
			{
				DrawerSnapshot snapshot = Snapshot;
				Face.Show(snapshot.ItemName, snapshot.Amount);
			}
		}

		private void ClaimForWrite()
		{
			if ((Object)(object)_view != (Object)null && _view.IsValid() && !_view.IsOwner())
			{
				_view.ClaimOwnership();
			}
		}

		private static int RemoveByPrefab(Inventory inv, string itemName, int amount)
		{
			if (amount <= 0)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData item in new List<ItemData>(inv.GetAllItems()))
			{
				if (num >= amount)
				{
					break;
				}
				if (!(ItemFacts.PrefabNameOf(item) != itemName))
				{
					int num2 = Math.Min(item.m_stack, amount - num);
					if (inv.RemoveItem(item, num2))
					{
						num += num2;
					}
				}
			}
			return num;
		}

		private static int DepositByPrefab(Inventory inv, string itemName, int amount)
		{
			GameObject val = ItemFacts.Prefab(itemName);
			if ((Object)(object)val == (Object)null || amount <= 0)
			{
				return 0;
			}
			int num = ItemFacts.MaxStackSize(itemName);
			int num2 = ItemFacts.CountByPrefab(inv, itemName);
			foreach (int item in ChunkSplitter.Chunks(amount, num))
			{
				inv.AddItem(val, item);
			}
			return ItemFacts.CountByPrefab(inv, itemName) - num2;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			if (hold)
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if ((Object)(object)_view == (Object)null || !_view.IsValid())
			{
				return false;
			}
			ClaimForWrite();
			DrawerSnapshot snapshot = Snapshot;
			Inventory inventory = ((Container)this).GetInventory();
			if (inventory == null)
			{
				return true;
			}
			bool button = ZInput.GetButton("Crouch");
			bool button2 = ZInput.GetButton("Run");
			if (button && button2)
			{
				if (!((DrawerSnapshot)(ref snapshot)).IsAssigned || ((DrawerSnapshot)(ref snapshot)).IsEmpty)
				{
					return true;
				}
				if (!DrawerAssignUI.IsOpen && !DrawerTakeAmountUI.IsOpen)
				{
					DrawerTakeAmountUI.Open(this, val, snapshot);
				}
				return true;
			}
			if (button)
			{
				if (!((DrawerSnapshot)(ref snapshot)).IsAssigned)
				{
					return true;
				}
				if (((DrawerSnapshot)(ref snapshot)).IsEmpty)
				{
					_view.GetZDO().Set(AssignedItemHash, "");
					RefreshFace();
					return true;
				}
				if ((Object)(object)ItemFacts.Drop(snapshot.ItemName) == (Object)null)
				{
					((Character)val).Message((MessageType)2, "Cannot identify this item", 0, (Sprite)null, false);
					return true;
				}
				int num = RemoveByPrefab(inventory, snapshot.ItemName, 1);
				if (num > 0)
				{
					ItemFacts.GiveToPlayer(val, snapshot.ItemName, num);
					RefreshFace();
				}
				return true;
			}
			if (button2)
			{
				return DepositEverythingMatching(val, snapshot);
			}
			if (!((DrawerSnapshot)(ref snapshot)).IsAssigned)
			{
				return true;
			}
			if ((Object)(object)ItemFacts.Drop(snapshot.ItemName) == (Object)null)
			{
				((Character)val).Message((MessageType)2, "Cannot identify this item", 0, (Sprite)null, false);
				return true;
			}
			int val2 = ItemFacts.MaxStackSize(snapshot.ItemName);
			int num2 = RemoveByPrefab(inventory, snapshot.ItemName, Math.Min(val2, snapshot.Amount));
			if (num2 > 0)
			{
				ItemFacts.GiveToPlayer(val, snapshot.ItemName, num2);
				RefreshFace();
			}
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null || item == null)
			{
				return false;
			}
			if ((Object)(object)_view == (Object)null || !_view.IsValid())
			{
				((Character)val).Message((MessageType)2, "Try again", 0, (Sprite)null, false);
				return true;
			}
			ClaimForWrite();
			if (item.m_shared.m_maxStackSize <= 1)
			{
				((Character)val).Message((MessageType)2, "Drawers only hold stackable items", 0, (Sprite)null, false);
				return true;
			}
			string text = ItemFacts.PrefabNameOf(item);
			if (text == null)
			{
				((Character)val).Message((MessageType)2, "Cannot identify this item", 0, (Sprite)null, false);
				return true;
			}
			DrawerSnapshot snapshot = Snapshot;
			if (((DrawerSnapshot)(ref snapshot)).IsAssigned && snapshot.ItemName != text)
			{
				((Character)val).Message((MessageType)2, "This drawer holds " + ItemFacts.LocalizedName(snapshot.ItemName), 0, (Sprite)null, false);
				return true;
			}
			Inventory inventory = ((Container)this).GetInventory();
			if (inventory == null)
			{
				((Character)val).Message((MessageType)2, "Try again", 0, (Sprite)null, false);
				return true;
			}
			bool flag = !((DrawerSnapshot)(ref snapshot)).IsAssigned;
			if (flag)
			{
				_view.GetZDO().Set(AssignedItemHash, text);
			}
			int num = DepositByPrefab(inventory, text, item.m_stack);
			if (num <= 0)
			{
				if (flag)
				{
					_view.GetZDO().Set(AssignedItemHash, "");
				}
				((Character)val).Message((MessageType)2, "This drawer is full", 0, (Sprite)null, false);
				return true;
			}
			((Humanoid)val).GetInventory().RemoveItem(item, num);
			RefreshFace();
			return true;
		}

		private bool DepositEverythingMatching(Player player, DrawerSnapshot current)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (!((DrawerSnapshot)(ref current)).IsAssigned)
			{
				((Character)player).Message((MessageType)2, "Not assigned yet", 0, (Sprite)null, false);
				return true;
			}
			return DepositAllOfItemInternal(player, current.ItemName, announce: true);
		}

		public void AssignAndDeposit(Player player, string itemName)
		{
			if (!string.IsNullOrEmpty(itemName))
			{
				DepositAllOfItemInternal(player, itemName, announce: false);
			}
		}

		private bool DepositAllOfItemInternal(Player player, string itemName, bool announce)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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)
			if ((Object)(object)_view == (Object)null || !_view.IsValid())
			{
				((Character)player).Message((MessageType)2, "Try again", 0, (Sprite)null, false);
				return true;
			}
			ClaimForWrite();
			DrawerSnapshot snapshot = Snapshot;
			if (((DrawerSnapshot)(ref snapshot)).IsAssigned && snapshot.ItemName != itemName)
			{
				((Character)player).Message((MessageType)2, "This drawer holds " + ItemFacts.LocalizedName(snapshot.ItemName), 0, (Sprite)null, false);
				return true;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<ItemData> list = new List<ItemData>();
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (!(ItemFacts.PrefabNameOf(allItem) != itemName) && !ExtraSlotsCompat.IsInReservedSlot(allItem))
				{
					list.Add(allItem);
					num += allItem.m_stack;
				}
			}
			if (num <= 0)
			{
				((Character)player).Message((MessageType)2, "You have none of those", 0, (Sprite)null, false);
				return true;
			}
			Inventory inventory2 = ((Container)this).GetInventory();
			if (inventory2 == null)
			{
				((Character)player).Message((MessageType)2, "Try again", 0, (Sprite)null, false);
				return true;
			}
			bool flag = !((DrawerSnapshot)(ref snapshot)).IsAssigned;
			if (flag)
			{
				_view.GetZDO().Set(AssignedItemHash, itemName);
			}
			int num2 = DepositByPrefab(inventory2, itemName, num);
			if (num2 <= 0)
			{
				if (flag)
				{
					_view.GetZDO().Set(AssignedItemHash, "");
				}
				((Character)player).Message((MessageType)2, "This drawer is full", 0, (Sprite)null, false);
				return true;
			}
			int num3 = num2;
			foreach (ItemData item in list)
			{
				if (num3 <= 0)
				{
					break;
				}
				int num4 = ((item.m_stack < num3) ? item.m_stack : num3);
				if (inventory.RemoveItem(item, num4))
				{
					num3 -= num4;
				}
			}
			RefreshFace();
			if (announce)
			{
				((Character)player).Message((MessageType)1, $"Stored {num2} {ItemFacts.LocalizedName(itemName)}", 0, (Sprite)null, false);
			}
			return true;
		}

		public bool TryWithdrawExact(Player player, string itemName, int amount)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_view == (Object)null || !_view.IsValid() || (Object)(object)player == (Object)null)
			{
				return false;
			}
			DrawerSnapshot snapshot = Snapshot;
			if (!((DrawerSnapshot)(ref snapshot)).IsAssigned || snapshot.ItemName != itemName || amount <= 0)
			{
				return false;
			}
			if ((Object)(object)ItemFacts.Drop(itemName) == (Object)null)
			{
				return false;
			}
			ClaimForWrite();
			Inventory inventory = ((Container)this).GetInventory();
			if (inventory == null)
			{
				return false;
			}
			int num = RemoveByPrefab(inventory, itemName, Math.Min(amount, snapshot.Amount));
			if (num <= 0)
			{
				return false;
			}
			ItemFacts.GiveToPlayer(player, itemName, num);
			RefreshFace();
			return true;
		}

		public bool TryWithdrawExternally(int requested, out int taken)
		{
			//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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			taken = 0;
			DrawerSnapshot snapshot = Snapshot;
			if (!((DrawerSnapshot)(ref snapshot)).IsAssigned || requested <= 0)
			{
				return false;
			}
			Inventory inventory = ((Container)this).GetInventory();
			if (inventory == null)
			{
				return false;
			}
			ClaimForWrite();
			taken = RemoveByPrefab(inventory, snapshot.ItemName, Math.Min(requested, snapshot.Amount));
			if (taken <= 0)
			{
				return false;
			}
			RefreshFace();
			return true;
		}

		public bool TryDepositExternally(string itemName, int amount, out int accepted)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			accepted = 0;
			if (!ItemFacts.IsStorable(itemName) || amount <= 0)
			{
				return false;
			}
			DrawerSnapshot snapshot = Snapshot;
			if (((DrawerSnapshot)(ref snapshot)).IsAssigned && snapshot.ItemName != itemName)
			{
				return false;
			}
			Inventory inventory = ((Container)this).GetInventory();
			if (inventory == null || (Object)(object)_view == (Object)null || !_view.IsValid())
			{
				return false;
			}
			ClaimForWrite();
			bool flag = !((DrawerSnapshot)(ref snapshot)).IsAssigned;
			if (flag)
			{
				_view.GetZDO().Set(AssignedItemHash, itemName);
			}
			accepted = DepositByPrefab(inventory, itemName, amount);
			if (accepted <= 0)
			{
				if (flag)
				{
					_view.GetZDO().Set(AssignedItemHash, "");
				}
				return false;
			}
			RefreshFace();
			return true;
		}

		internal void EnforceSingleItemType()
		{
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			if (_enforcingType || (Object)(object)_view == (Object)null || !_view.IsValid())
			{
				return;
			}
			Inventory inventory = ((Container)this).GetInventory();
			if (inventory == null)
			{
				return;
			}
			_enforcingType = true;
			try
			{
				ClaimForWrite();
				ZDO zDO = _view.GetZDO();
				string text = zDO.GetString(AssignedItemHash, "");
				if (string.IsNullOrEmpty(text))
				{
					string text2 = null;
					foreach (ItemData allItem in inventory.GetAllItems())
					{
						text2 = ItemFacts.PrefabNameOf(allItem);
						if (text2 != null)
						{
							break;
						}
					}
					if (text2 == null)
					{
						return;
					}
					text = text2;
					zDO.Set(AssignedItemHash, text);
				}
				List<ItemData> list = null;
				foreach (ItemData allItem2 in inventory.GetAllItems())
				{
					if (!(ItemFacts.PrefabNameOf(allItem2) == text))
					{
						(list ?? (list = new List<ItemData>())).Add(allItem2);
					}
				}
				if (list == null)
				{
					return;
				}
				foreach (ItemData item in list)
				{
					string text3 = ItemFacts.PrefabNameOf(item);
					int stack = item.m_stack;
					inventory.RemoveItem(item);
					if (text3 != null)
					{
						ItemFacts.SpillAtPosition(((Component)this).transform.position, text3, stack);
					}
				}
				RefreshFace();
			}
			finally
			{
				_enforcingType = false;
			}
		}

		public string GetHoverText()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			DrawerSnapshot snapshot = Snapshot;
			if (!((DrawerSnapshot)(ref snapshot)).IsAssigned)
			{
				string text = ((object)DrawerConfig.AssignKey.Value/*cast due to .constrained prefix*/).ToString();
				return Localization.instance.Localize(DrawerTiers.DisplayName(Tier) + "\n[<color=yellow><b>" + text + "</b></color>] Assign from inventory\n[<color=yellow><b>1-8</b></color>] Assign from hotbar");
			}
			string arg = ItemFacts.LocalizedName(snapshot.ItemName);
			return Localization.instance.Localize($"{arg}  <color=orange>{snapshot.Amount}</color>/{Capacity}\n" + "[<color=yellow><b>E</b></color>] Take stack\n[<color=yellow><b>Ctrl+E</b></color>] Take one\n[<color=yellow><b>Shift+E</b></color>] Store all\n[<color=yellow><b>Ctrl+Shift+E</b></color>] Take amount");
		}

		public string GetHoverName()
		{
			return DrawerTiers.DisplayName(Tier);
		}
	}
	[HarmonyPatch(typeof(Inventory), "Changed", new Type[]
	{
		typeof(bool),
		typeof(bool)
	})]
	internal static class DrawerTypeEnforcementPatch
	{
		private static bool Prepare()
		{
			return ValheimCompat.RequireMethod(typeof(Inventory), "Changed");
		}

		private static void Postfix(Inventory __instance)
		{
			if (DrawerComponent.InventoryOwnersLookup(__instance, out var drawer))
			{
				drawer.EnforceSingleItemType();
			}
		}
	}
	[HarmonyPatch(typeof(Container), "CanBeRemoved")]
	internal static class DrawerCanBeRemovedPatch
	{
		private static bool Prepare()
		{
			return ValheimCompat.RequireMethod(typeof(Container), "CanBeRemoved");
		}

		private static bool Prefix(Container __instance, ref bool __result)
		{
			if (!(__instance is DrawerComponent drawerComponent))
			{
				return true;
			}
			Inventory inventory = ((Container)drawerComponent).GetInventory();
			__result = inventory == null || inventory.NrOfItems() == 0;
			return false;
		}
	}
	public static class DrawerConfig
	{
		public static ConfigEntry<int> WoodSlots;

		public static ConfigEntry<int> StoneSlots;

		public static ConfigEntry<int> BlackMarbleSlots;

		public static ConfigEntry<bool> AutoPickupEnabled;

		public static ConfigEntry<float> PickupRadius;

		public static ConfigEntry<float> PickupScanRange;

		public static ConfigEntry<float> PickupInterval;

		public static ConfigEntry<float> LabelDistance;

		public static ConfigEntry<KeyCode> AssignKey;

		public static void Bind(ConfigFile config)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_0105: 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_0112: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			WoodSlots = config.Bind<int>("Slots", "Wood", DrawerTiers.DefaultSlots(DrawerTier.Wood), new ConfigDescription("How many real item slots a wood drawer has.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			StoneSlots = config.Bind<int>("Slots", "Stone", DrawerTiers.DefaultSlots(DrawerTier.Stone), new ConfigDescription("How many real item slots a stone drawer has.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			BlackMarbleSlots = config.Bind<int>("Slots", "BlackMarble", DrawerTiers.DefaultSlots(DrawerTier.BlackMarble), new ConfigDescription("How many real item slots a black marble drawer has.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			AutoPickupEnabled = config.Bind<bool>("Pickup", "Enabled", true, new ConfigDescription("Drawers absorb matching items dropped nearby.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			PickupRadius = config.Bind<float>("Pickup", "Radius", 40f, new ConfigDescription("How far from a drawer a dropped item is absorbed, in metres.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			PickupScanRange = config.Bind<float>("Pickup", "ScanRange", 40f, new ConfigDescription("How far around you dropped items are considered at all. One query covers every drawer, so this is cheap.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			PickupInterval = config.Bind<float>("Pickup", "Interval", 0.5f, new ConfigDescription("Seconds between pickup passes.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			LabelDistance = config.Bind<float>("Display", "LabelDistance", 30f, "Beyond this distance drawer icons and counts switch off. A wall of text nobody can read is wasted work.");
			AssignKey = config.Bind<KeyCode>("Controls", "AssignDrawerKey", (KeyCode)111, "Key to open a picker, while looking at an unassigned drawer, listing what you're carrying so you can assign it without needing a hotbar slot. Already-assigned drawers are unaffected -- use Shift+Interact to add more of what they already hold.");
		}

		public static int SlotsFor(DrawerTier tier)
		{
			return tier switch
			{
				DrawerTier.Wood => WoodSlots?.Value ?? DrawerTiers.DefaultSlots(tier), 
				DrawerTier.Stone => StoneSlots?.Value ?? DrawerTiers.DefaultSlots(tier), 
				DrawerTier.BlackMarble => BlackMarbleSlots?.Value ?? DrawerTiers.DefaultSlots(tier), 
				_ => DrawerTiers.DefaultSlots(tier), 
			};
		}
	}
	internal static class DrawerFont
	{
		private static TMP_FontAsset _cached;

		private static bool _loggedFailure;

		public static TMP_FontAsset Shared
		{
			get
			{
				if ((Object)(object)_cached != (Object)null)
				{
					return _cached;
				}
				TMP_FontAsset val = ((GUIManager.Instance != null) ? GUIManager.Instance.TMP_AveriaSansLibre : null);
				if ((Object)(object)val != (Object)null)
				{
					_cached = val;
					return _cached;
				}
				TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>();
				foreach (TMP_Text val2 in array)
				{
					if ((Object)(object)val2 != (Object)null && (Object)(object)val2.font != (Object)null)
					{
						_cached = val2.font;
						return _cached;
					}
				}
				TMP_FontAsset[] array2 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				if (array2.Length != 0)
				{
					_cached = array2[0];
					return _cached;
				}
				try
				{
					TMP_FontAsset defaultFontAsset = TMP_Settings.defaultFontAsset;
					if ((Object)(object)defaultFontAsset != (Object)null)
					{
						_cached = defaultFontAsset;
						return _cached;
					}
				}
				catch (Exception)
				{
				}
				if (!_loggedFailure)
				{
					_loggedFailure = true;
					DrawerPlugin.Log.LogError((object)"No TMP font asset found anywhere (checked Jotunn.GUIManager.TMP_AveriaSansLibre, every live TMP_Text, Resources.FindObjectsOfTypeAll<TMP_FontAsset>, and TMP_Settings.defaultFontAsset). Drawer count labels will not render any text until this resolves. This mod ships no font of its own by design.");
				}
				return null;
			}
		}
	}
	public static class DrawerIconAtlas
	{
		private static AtlasLayout _layout;

		private static Texture2D _texture;

		private static bool _buildFailureLogged;

		private static readonly string[] ShaderCandidates = new string[3] { "Unlit/Transparent", "Sprites/Default", "UI/Default" };

		public static Material SharedMaterial { get; private set; }

		public static bool IsBuilt
		{
			get
			{
				if (_layout != null)
				{
					return (Object)(object)SharedMaterial != (Object)null;
				}
				return false;
			}
		}

		public static void Build()
		{
			if (IsBuilt)
			{
				return;
			}
			try
			{
				BuildInternal();
			}
			catch (Exception arg)
			{
				_layout = null;
				SharedMaterial = null;
				if (!_buildFailureLogged)
				{
					_buildFailureLogged = true;
					DrawerPlugin.Log.LogError((object)("Icon atlas build threw; leaving it unbuilt. Will keep retrying quietly on " + $"later calls, but will not log this again: {arg}"));
				}
			}
		}

		private static void BuildInternal()
		{
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Expected O, but got Unknown
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				DrawerPlugin.Log.LogWarning((object)"ObjectDB not ready; icon atlas deferred.");
				return;
			}
			List<IconSize> list = new List<IconSize>();
			Dictionary<string, Sprite> dictionary = new Dictionary<string, Sprite>();
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				ItemDrop val = (((Object)(object)item == (Object)null) ? null : item.GetComponent<ItemDrop>());
				if (!((Object)(object)val == (Object)null) && val.m_itemData.m_shared.m_maxStackSize > 1)
				{
					Sprite icon;
					try
					{
						icon = val.m_itemData.GetIcon();
					}
					catch (Exception ex)
					{
						DrawerPlugin.Log.LogWarning((object)("Skipping '" + ((Object)item).name + "' in the icon atlas: GetIcon() threw (" + ex.GetType().Name + ": " + ex.Message + ")."));
						continue;
					}
					if (!((Object)(object)icon == (Object)null) && !((Object)(object)icon.texture == (Object)null) && !dictionary.ContainsKey(((Object)item).name))
					{
						dictionary[((Object)item).name] = icon;
						string name = ((Object)item).name;
						Rect textureRect = icon.textureRect;
						int num = (int)((Rect)(ref textureRect)).width;
						textureRect = icon.textureRect;
						list.Add(new IconSize(name, num, (int)((Rect)(ref textureRect)).height));
					}
				}
			}
			if (list.Count == 0)
			{
				DrawerPlugin.Log.LogError((object)"Icon atlas build found 0 storable items in ObjectDB.m_items -- called too early, before item registration finished. Not marking the atlas built; a later call to Build() (see DrawerIconAtlas.TryGetUv's retry) will try again.");
				return;
			}
			_layout = IconAtlasPacker.Pack((IReadOnlyList<IconSize>)list, 4096);
			_texture = new Texture2D(_layout.Width, _layout.Height, (TextureFormat)4, true)
			{
				name = "rid_icon_atlas",
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)1
			};
			Color32[] pixels = (Color32[])(object)new Color32[_layout.Width * _layout.Height];
			_texture.SetPixels32(pixels);
			foreach (KeyValuePair<string, AtlasRect> rect in _layout.Rects)
			{
				if (dictionary.TryGetValue(rect.Key, out var value) && TryReadSprite(value, out var pixels2, out var width, out var height))
				{
					_texture.SetPixels32(rect.Value.X, rect.Value.Y, width, height, pixels2);
				}
			}
			_texture.Apply(true, true);
			string source;
			Shader val2 = ResolveIconShader(out source);
			if ((Object)(object)val2 == (Object)null)
			{
				DrawerPlugin.Log.LogError((object)("No usable shader found for the drawer icon atlas material (tried " + string.Join(", ", ShaderCandidates) + "). Drawer icons will not render until this is fixed."));
				Object.Destroy((Object)(object)_texture);
				_texture = null;
				_layout = null;
			}
			else
			{
				SharedMaterial = new Material(val2)
				{
					name = "rid_icon_material",
					mainTexture = (Texture)(object)_texture
				};
				SharedMaterial.renderQueue = 2450;
				DrawerPlugin.Log.LogInfo((object)($"Icon atlas built: {_layout.Rects.Count} icons in {_layout.Width}x{_layout.Height}, " + "material shader = " + source));
			}
		}

		private static Shader ResolveIconShader(out string source)
		{
			string[] shaderCandidates = ShaderCandidates;
			foreach (string text in shaderCandidates)
			{
				Shader val = Shader.Find(text);
				if ((Object)(object)val != (Object)null)
				{
					source = "Shader.Find(\"" + text + "\")";
					return val;
				}
				DrawerPlugin.Log.LogWarning((object)("Shader.Find(\"" + text + "\") returned null; trying next candidate."));
			}
			source = null;
			return null;
		}

		private static bool TryReadSprite(Sprite sprite, out Color32[] pixels, out int width, out int height)
		{
			//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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			pixels = null;
			Rect textureRect = sprite.textureRect;
			width = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
			height = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
			if (width <= 0 || height <= 0)
			{
				return false;
			}
			RenderTexture active = RenderTexture.active;
			RenderTexture temporary = RenderTexture.GetTemporary(((Texture)sprite.texture).width, ((Texture)sprite.texture).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0);
			try
			{
				Graphics.Blit((Texture)(object)sprite.texture, temporary);
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(width, height, (TextureFormat)4, false);
				val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)width, (float)height), 0, 0);
				val.Apply();
				pixels = val.GetPixels32();
				Object.Destroy((Object)(object)val);
				return true;
			}
			catch (Exception ex)
			{
				DrawerPlugin.Log.LogWarning((object)("Could not read icon for atlas: " + ex.Message));
				return false;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		public static bool TryGetUv(string item, out Vector2 min, out Vector2 max)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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)
			min = Vector2.zero;
			max = Vector2.one;
			if (!IsBuilt)
			{
				Build();
			}
			if (_layout == null)
			{
				return false;
			}
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			float num4 = default(float);
			if (!_layout.TryGetUv(item, ref num, ref num2, ref num3, ref num4))
			{
				return false;
			}
			min = new Vector2(num, num2);
			max = new Vector2(num3, num4);
			return true;
		}
	}
	public class DrawerManager : MonoBehaviour
	{
		private readonly SpatialGrid<DrawerComponent> _grid = new SpatialGrid<DrawerComponent>(8f);

		private readonly List<DrawerComponent> _all = new List<DrawerComponent>();

		private readonly HashSet<DrawerComponent> _dirty = new HashSet<DrawerComponent>();

		private float _cullTimer;

		private int _syncCursor;

		private float _pickupTimer;

		private readonly List<DrawerComponent> _pickupScratch = new List<DrawerComponent>(16);

		public static DrawerManager Instance { get; private set; }

		public static void Create()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (!((Object)(object)Instance != (Object)null))
			{
				GameObject val = new GameObject("RidDrawerManager");
				Object.DontDestroyOnLoad((Object)val);
				Instance = val.AddComponent<DrawerManager>();
			}
		}

		public void Register(DrawerComponent drawer)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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)
			if (!((Object)(object)drawer == (Object)null) && !_all.Contains(drawer))
			{
				_all.Add(drawer);
				Vector3 position = ((Component)drawer).transform.position;
				_grid.Insert(drawer, position.x, position.y, position.z);
				MarkDirty(drawer);
			}
		}

		public void Unregister(DrawerComponent drawer)
		{
			if (!((Object)(object)drawer == (Object)null))
			{
				_all.Remove(drawer);
				_dirty.Remove(drawer);
				_grid.Remove(drawer);
			}
		}

		public void MarkDirty(DrawerComponent drawer)
		{
			if ((Object)(object)drawer != (Object)null)
			{
				_dirty.Add(drawer);
			}
		}

		public void QueryNear(Vector3 position, float radius, List<DrawerComponent> results)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			_grid.Query(position.x, position.y, position.z, radius, results);
		}

		private void Update()
		{
			if (_dirty.Count > 0)
			{
				FlushDirty();
			}
			SyncSomeFaces();
			CheckAssignDrawerKey();
			DrawerTakeAmountUI.PollKeyboardInput();
			_cullTimer -= Time.deltaTime;
			if (_cullTimer <= 0f)
			{
				_cullTimer = 0.5f;
				UpdateLabelVisibility();
			}
			_pickupTimer -= Time.deltaTime;
			if (_pickupTimer <= 0f)
			{
				_pickupTimer = DrawerConfig.PickupInterval.Value;
				if (DrawerConfig.AutoPickupEnabled.Value)
				{
					RunAutoPickup();
				}
			}
		}

		private void RunAutoPickup()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || _all.Count == 0)
			{
				return;
			}
			List<ItemDrop> s_instances = ItemDrop.s_instances;
			if (s_instances == null || s_instances.Count == 0)
			{
				return;
			}
			float value = DrawerConfig.PickupRadius.Value;
			float value2 = DrawerConfig.PickupScanRange.Value;
			float num = value2 * value2;
			Vector3 position = ((Component)localPlayer).transform.position;
			for (int i = 0; i < s_instances.Count; i++)
			{
				ItemDrop val = s_instances[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - position;
				if (((Vector3)(ref val2)).sqrMagnitude > num || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid() || val.m_itemData == null || val.m_itemData.m_shared.m_maxStackSize <= 1)
				{
					continue;
				}
				string text = (((Object)(object)val.m_itemData.m_dropPrefab != (Object)null) ? ((Object)val.m_itemData.m_dropPrefab).name : ((Object)val).name.Replace("(Clone)", ""));
				_pickupScratch.Clear();
				QueryNear(((Component)val).transform.position, value, _pickupScratch);
				DrawerComponent drawerComponent = null;
				for (int j = 0; j < _pickupScratch.Count; j++)
				{
					DrawerComponent drawerComponent2 = _pickupScratch[j];
					if (!((Object)(object)drawerComponent2 == (Object)null))
					{
						DrawerSnapshot snapshot = drawerComponent2.Snapshot;
						if (((DrawerSnapshot)(ref snapshot)).IsAssigned && !(snapshot.ItemName != text))
						{
							drawerComponent = drawerComponent2;
							break;
						}
					}
				}
				if ((Object)(object)drawerComponent == (Object)null)
				{
					continue;
				}
				int accepted;
				if (!val.CanPickup(true))
				{
					val.RequestOwn();
				}
				else if (drawerComponent.TryDepositExternally(text, val.m_itemData.m_stack, out accepted) && accepted > 0)
				{
					ItemData itemData = val.m_itemData;
					itemData.m_stack -= accepted;
					if (val.m_itemData.m_stack <= 0)
					{
						ZNetScene.instance.Destroy(((Component)val).gameObject);
					}
					else
					{
						val.Save();
					}
				}
			}
		}

		private void FlushDirty()
		{
			foreach (DrawerComponent item in _dirty)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.RefreshFace();
				}
			}
			_dirty.Clear();
		}

		private void SyncSomeFaces()
		{
			if (_all.Count == 0)
			{
				return;
			}
			int num = Mathf.Max(1, _all.Count / 30);
			for (int i = 0; i < num; i++)
			{
				if (_syncCursor >= _all.Count)
				{
					_syncCursor = 0;
				}
				DrawerComponent drawerComponent = _all[_syncCursor++];
				if (!((Object)(object)drawerComponent == (Object)null))
				{
					if ((Object)(object)drawerComponent.Face != (Object)null && drawerComponent.Face.NeedsFont)
					{
						drawerComponent.Face.TryConfigureCountText();
					}
					drawerComponent.RefreshFace();
				}
			}
		}

		private void CheckAssignDrawerKey()
		{
			string assignDrawerButtonName = DrawerPlugin.AssignDrawerButtonName;
			if (assignDrawerButtonName == null || !ZInput.GetButtonDown(assignDrawerButtonName) || DrawerAssignUI.IsOpen || DrawerTakeAmountUI.IsOpen)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
				DrawerComponent drawerComponent = ((hoverObject != null) ? hoverObject.GetComponent<DrawerComponent>() : null);
				if ((Object)(object)drawerComponent != (Object)null)
				{
					DrawerAssignUI.Open(drawerComponent, localPlayer);
				}
			}
		}

		private void UpdateLabelVisibility()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)main).transform.position;
			float value = DrawerConfig.LabelDistance.Value;
			float num = value * value;
			for (int i = 0; i < _all.Count; i++)
			{
				DrawerComponent drawerComponent = _all[i];
				if (!((Object)(object)drawerComponent == (Object)null))
				{
					DrawerRenderer face = drawerComponent.Face;
					if (face != null)
					{
						Vector3 val = ((Component)drawerComponent).transform.position - position;
						face.SetLabelVisible(((Vector3)(ref val)).sqrMagnitude <= num);
					}
				}
			}
		}
	}
	public static class DrawerMaterialTextures
	{
		private const int Size = 512;

		private const int WoodSeed = 1;

		private const int StoneSeed = 2;

		private const int MarbleSeed = 3;

		private static readonly Dictionary<DrawerTier, (Texture2D albedo, Texture2D normal)> _cache = new Dictionary<DrawerTier, (Texture2D, Texture2D)>();

		private static readonly Dictionary<DrawerTier, byte[]> _albedoBytes = new Dictionary<DrawerTier, byte[]>();

		private static readonly Dictionary<(DrawerTier, int), Texture2D> _brightCache = new Dictionary<(DrawerTier, int), Texture2D>();

		private static Texture2D _metal;

		public static (Texture2D albedo, Texture2D normal) Get(DrawerTier tier)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (_cache.TryGetValue(tier, out (Texture2D, Texture2D) value))
			{
				return value;
			}
			TextureData val = DrawerTextureGenerator.Generate(ToTextureTier(tier), 512, 512, SeedFor(tier));
			_albedoBytes[tier] = val.Albedo;
			(Texture2D, Texture2D) tuple = (BuildTexture(val.Albedo, "albedo", tier, linear: false), BuildTexture(val.Normal, "normal", tier, linear: true));
			_cache[tier] = tuple;
			return tuple;
		}

		public static Texture2D GetAtLightness(DrawerTier tier, float target)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Get(tier);
			int num = Mathf.RoundToInt(target * 1000f);
			if (_brightCache.TryGetValue((tier, num), out var value))
			{
				return value;
			}
			float num2 = DrawerTextureGenerator.MidLightness(ToTextureTier(tier));
			float num3 = ((num2 > 0.0001f) ? (target / num2) : 1f);
			byte[] array = _albedoBytes[tier];
			byte[] array2 = new byte[array.Length];
			for (int i = 0; i < array.Length; i += 4)
			{
				array2[i] = Saturate((float)(int)array[i] * num3);
				array2[i + 1] = Saturate((float)(int)array[i + 1] * num3);
				array2[i + 2] = Saturate((float)(int)array[i + 2] * num3);
				array2[i + 3] = array[i + 3];
			}
			Texture2D val = BuildTexture(array2, $"albedo_bright{num}", tier, linear: false);
			_brightCache[(tier, num)] = val;
			return val;
		}

		private static byte Saturate(float v)
		{
			return (byte)((v >= 255f) ? 255f : ((v <= 0f) ? 0f : v));
		}

		public static Texture2D Metal()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			if ((Object)(object)_metal != (Object)null)
			{
				return _metal;
			}
			byte[] array = new byte[64];
			for (int i = 0; i < array.Length; i += 4)
			{
				array[i] = 197;
				array[i + 1] = 205;
				array[i + 2] = 214;
				array[i + 3] = byte.MaxValue;
			}
			_metal = new Texture2D(4, 4, (TextureFormat)4, true, false)
			{
				name = "rid_handle_metal",
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)1
			};
			_metal.SetPixelData<byte>(array, 0, 0);
			_metal.Apply(true, true);
			return _metal;
		}

		private static TextureTier ToTextureTier(DrawerTier tier)
		{
			return (TextureTier)(tier switch
			{
				DrawerTier.Wood => 0, 
				DrawerTier.Stone => 1, 
				DrawerTier.BlackMarble => 2, 
				_ => 0, 
			});
		}

		private static int SeedFor(DrawerTier tier)
		{
			return tier switch
			{
				DrawerTier.Wood => 1, 
				DrawerTier.Stone => 2, 
				DrawerTier.BlackMarble => 3, 
				_ => 1, 
			};
		}

		private static Texture2D BuildTexture(byte[] rgba, string kind, DrawerTier tier, bool linear)
		{
			//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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			Texture2D val = new Texture2D(512, 512, (TextureFormat)4, true, linear)
			{
				name = $"rid_drawer_{tier}_{kind}",
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)1
			};
			val.SetPixelData<byte>(rgba, 0, 0);
			val.Apply(true, true);
			return val;
		}
	}
	internal static class MeshDataExtensions
	{
		public static Mesh ToUnityMesh(this MeshData data, string name)
		{
			//IL_0060: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_00bc: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_014d: Expected O, but got Unknown
			Vector3[] array = (Vector3[])(object)new Vector3[data.VertexCount];
			Vector3[] array2 = (Vector3[])(object)new Vector3[data.VertexCount];
			Vector2[] array3 = (Vector2[])(object)new Vector2[data.VertexCount];
			int[] array4 = new int[data.VertexCount];
			for (int i = 0; i < data.VertexCount; i++)
			{
				array[i] = new Vector3(data.Vertices[i * 3], data.Vertices[i * 3 + 1], data.Vertices[i * 3 + 2]);
				array2[i] = new Vector3(data.Normals[i * 3], data.Normals[i * 3 + 1], data.Normals[i * 3 + 2]);
				array3[i] = new Vector2(data.Uvs[i * 2], data.Uvs[i * 2 + 1]);
			}
			for (int j = 0; j < data.TriangleCount; j++)
			{
				array4[j * 3] = j * 3;
				array4[j * 3 + 1] = j * 3 + 1;
				array4[j * 3 + 2] = j * 3 + 2;
			}
			Mesh val = new Mesh
			{
				name = name
			};
			val.SetVertices(array);
			val.SetNormals(array2);
			val.SetUVs(0, array3);
			val.SetTriangles(array4, 0);
			val.RecalculateTangents();
			val.RecalculateBounds();
			val.UploadMeshData(false);
			return val;
		}
	}
	public static class DrawerPieces
	{
		private static Mesh _sharedMesh;

		private static GameObject _prefabTemplateContainer;

		private static Mesh _sharedHandleMesh;

		private const float FaceplateLightness = 0.16f;

		private static GameObject PrefabTemplateContainer()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)_prefabTemplateContainer == (Object)null)
			{
				_prefabTemplateContainer = new GameObject("rid_prefab_template_container");
				_prefabTemplateContainer.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_prefabTemplateContainer);
			}
			return _prefabTemplateContainer;
		}

		public static void RegisterAll()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			DrawerProportions val = new DrawerProportions();
			_sharedMesh = DrawerMeshBuilder.Build(new DrawerProportions
			{
				Handle = (HandleStyle)0
			}).ToUnityMesh("rid_drawer");
			_sharedHandleMesh = BuildHandleMesh(val);
			DrawerTier[] all = DrawerTiers.All;
			foreach (DrawerTier drawerTier in all)
			{
				try
				{
					RegisterOne(drawerTier, val);
				}
				catch (Exception arg)
				{
					DrawerPlugin.Log.LogError((object)$"{drawerTier}: registration threw and was skipped: {arg}");
				}
			}
		}

		private static Mesh BuildHandleMesh(DrawerProportions p)
		{
			float num = Math.Min(p.FrameThickness, Math.Min(p.Width, p.Height) / 2f - 0.02f);
			float num2 = Math.Min(p.RecessDepth, p.Depth * 0.5f);
			float num3 = p.Depth / 2f - num2;
			float num4 = Math.Min(p.HandleWidth, p.Width - 2f * num - 0.02f);
			float num5 = Math.Min(p.Bevel, p.HandleSection / 2.5f);
			return DrawerMeshBuilder.ChamferBox(0f, HandleCenterY(p, num), num3 + p.HandleProud / 2f, num4, p.HandleSection, p.HandleProud, num5).ToUnityMesh("rid_drawer_handle");
		}

		private static float HandleCenterY(DrawerProportions p, float frame)
		{
			return (0f - (p.Height - 2f * frame)) / 2f + p.HandleSection * 2.4f;
		}

		private static void RegisterOne(DrawerTier tier, DrawerProportions proportions)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_003e: 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_007f: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			GameObject val = BuildPrefab(tier, _sharedMesh, proportions);
			if (!((Object)(object)val == (Object)null))
			{
				PieceConfig val2 = new PieceConfig
				{
					Name = DrawerTiers.DisplayName(tier),
					Description = "Holds a great many of a single item.",
					PieceTable = PieceTables.Hammer,
					CraftingStation = CraftingStations.Workbench,
					Requirements = ((IEnumerable<(string, int)>)DrawerTiers.Recipe(tier)).Select((Func<(string, int), RequirementConfig>)(((string Item, int Amount) r) => new RequirementConfig(r.Item, r.Amount, 0, true))).ToArray()
				};
				CustomPiece val3 = new CustomPiece(val, false, val2);
				if (!val3.IsValid())
				{
					DrawerPlugin.Log.LogError((object)(DrawerTiers.PrefabName(tier) + " FAILED Jotunn validation; not registered. See the Jotunn error immediately above for which check failed."));
				}
				else if (!PieceManager.Instance.AddPiece(val3))
				{
					DrawerPlugin.Log.LogError((object)("AddPiece rejected " + DrawerTiers.PrefabName(tier) + "."));
				}
				else
				{
					DrawerPlugin.Log.LogInfo((object)("Registered " + DrawerTiers.PrefabName(tier)));
				}
			}
		}

		public static GameObject BuildPrefab(DrawerTier tier, Mesh sharedMesh, DrawerProportions proportions)
		{
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Expected O, but got Unknown
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: 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_0251: Expected O, but got Unknown
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_048f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Expected O, but got Unknown
			//IL_04cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e9: Expected O, but got Unknown
			//IL_0616: Unknown result type (might be due to invalid IL or missing references)
			//IL_0621: Unknown result type (might be due to invalid IL or missing references)
			//IL_0590: Unknown result type (might be due to invalid IL or missing references)
			//IL_0595: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a8: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = null;
			MeshRenderer val2 = null;
			Piece val3 = null;
			string arg = null;
			string[] array = DrawerTiers.MaterialDonors(tier);
			foreach (string text in array)
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab(text);
				if ((Object)(object)prefab == (Object)null)
				{
					DrawerPlugin.Log.LogInfo((object)$"{tier}: donor '{text}' not found, trying next.");
					continue;
				}
				MeshRenderer componentInChildren = prefab.GetComponentInChildren<MeshRenderer>();
				Piece component = prefab.GetComponent<Piece>();
				if ((Object)(object)componentInChildren == (Object)null || (Object)(object)((Renderer)componentInChildren).sharedMaterial == (Object)null || (Object)(object)component == (Object)null || (Object)(object)component.m_icon == (Object)null)
				{
					DrawerPlugin.Log.LogInfo((object)($"{tier}: donor '{text}' unusable " + "(renderer=" + (((Object)(object)componentInChildren == (Object)null) ? "none" : "ok") + ", material=" + (((Object)(object)componentInChildren == (Object)null || (Object)(object)((Renderer)componentInChildren).sharedMaterial == (Object)null) ? "none" : "ok") + ", piece=" + (((Object)(object)component == (Object)null) ? "none" : "ok") + ", icon=" + (((Object)(object)component == (Object)null || (Object)(object)component.m_icon == (Object)null) ? "none" : "ok") + "), trying next."));
					continue;
				}
				val = prefab;
				val2 = componentInChildren;
				val3 = component;
				arg = text;
				break;
			}
			if ((Object)(object)val == (Object)null)
			{
				DrawerPlugin.Log.LogError((object)($"No usable material donor for {tier}. Tried: " + string.Join(", ", DrawerTiers.MaterialDonors(tier)) + ". This tier will be missing from the build menu."));
				return null;
			}
			GameObject val4 = new GameObject(DrawerTiers.PrefabName(tier));
			val4.transform.SetParent(PrefabTemplateContainer().transform, false);
			GameObject val5 = new GameObject("body");
			val5.transform.SetParent(val4.transform, false);
			val5.AddComponent<MeshFilter>().sharedMesh = sharedMesh;
			MeshRenderer val6 = val5.AddComponent<MeshRenderer>();
			Material val7 = new Material(((Renderer)val2).sharedMaterial.shader)
			{
				name = $"rid_drawer_{tier}_mat"
			};
			if (val7.HasProperty("_Color"))
			{
				val7.SetColor("_Color", Color.white);
			}
			bool flag = val7.HasProperty("_TriplanarScale");
			bool flag2 = false;
			if (flag)
			{
				val7.EnableKeyword("_TRIPLANARMAP_ON");
				val7.SetFloat("_TriplanarScale", 1f);
				flag2 = val7.HasProperty("_TriplanarLocalPos");
				if (flag2)
				{
					val7.SetFloat("_TriplanarLocalPos", 1f);
				}
				else
				{
					DrawerPlugin.Log.LogWarning((object)($"{tier}: shader has no _TriplanarLocalPos; triplanar mapping " + "will stay projected in world space, which makes each placed drawer's surfaces sample the normal map differently."));
				}
			}
			else
			{
				DrawerPlugin.Log.LogWarning((object)$"{tier}: shader has no _TriplanarScale; leaving UV mapping in place.");
			}
			(Texture2D albedo, Texture2D normal) tuple = DrawerMaterialTextures.Get(tier);
			Texture2D item = tuple.albedo;
			Texture2D item2 = tuple.normal;
			bool flag3 = val7.HasProperty("_MainTex");
			if (flag3)
			{
				val7.SetTexture("_MainTex", (Texture)(object)item);
			}
			bool flag4 = val7.HasProperty("_BumpMap");
			if (flag4)
			{
				val7.SetTexture("_BumpMap", (Texture)(object)item2);
				val7.EnableKeyword("_NORMALMAP");
			}
			string text2 = ((flag3 && flag4) ? "albedo+normal" : (flag3 ? "albedo only (shader has no _BumpMap)" : "NONE (shader has neither _MainTex nor _BumpMap)"));
			DrawerPlugin.Log.LogInfo((object)($"{tier}: donor='{arg}', shader='{((Object)((Renderer)val2).sharedMaterial.shader).name}', " + "triplanar=" + (flag ? "on" : "off") + ", triplanarLocalPos=" + (flag2 ? "on" : "off") + ", textures=" + text2 + ", keywords=[" + string.Join(",", val7.shaderKeywords) + "]"));
			((Renderer)val6).sharedMaterial = val7;
			((Renderer)val6).shadowCastingMode = (ShadowCastingMode)1;
			Material val8 = null;
			if (flag3)
			{
				val8 = new Material(val7)
				{
					name = ((Object)val7).name + "_faceplate"
				};
				val8.SetTexture("_MainTex", (Texture)(object)DrawerMaterialTextures.GetAtLightness(tier, 0.16f));
			}
			val4.AddComponent<BoxCollider>().size = new Vector3(0.66f, 0.66f, 0.66f);
			AddSnapPoints(val4, proportions);
			val4.AddComponent<ZNetView>().m_persistent = true;
			val4.AddComponent<DrawerComponent>();
			if ((Object)(object)_sharedHandleMesh != (Object)null && flag3)
			{
				Material val9 = new Material(val7)
				{
					name = ((Object)val7).name + "_handle"
				};
				val9.SetTexture("_MainTex", (Texture)(object)DrawerMaterialTextures.Metal());
				if (val9.HasProperty("_BumpMap"))
				{
					val9.SetTexture("_BumpMap", (Texture)null);
					val9.DisableKeyword("_NORMALMAP");
				}
				array = new string[2] { "_Glossiness", "_Smoothness" };
				foreach (string text3 in array)
				{
					if (val9.HasProperty(text3))
					{
						val9.SetFloat(text3, 0.65f);
					}
				}
				if (val9.HasProperty("_Metallic"))
				{
					val9.SetFloat("_Metallic", 0.8f);
				}
				GameObject val10 = new GameObject("handle");
				val10.transform.SetParent(val4.transform, false);
				val10.AddComponent<MeshFilter>().sharedMesh = _sharedHandleMesh;
				MeshRenderer obj = val10.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterial = val9;
				((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
			}
			DrawerRenderer.Attach(val4, proportions, val8);
			Piece obj2 = val4.AddComponent<Piece>();
			obj2.m_name = DrawerTiers.DisplayName(tier);
			obj2.m_description = "Holds a great many of a single item.";
			obj2.m_icon = RenderIconFromMesh(sharedMesh, val7, tier) ?? val3.m_icon;
			obj2.m_enabled = true;
			obj2.m_category = (PieceCategory)4;
			obj2.m_usage = (UsageTagFlags)1152;
			obj2.m_comfort = 0;
			WearNTear obj3 = val4.AddComponent<WearNTear>();
			obj3.m_health = ((tier == DrawerTier.Wood) ? 200f : 400f);
			obj3.m_noSupportWear = false;
			obj3.m_noRoofWear = tier != DrawerTier.Wood;
			obj3.m_destroyedEffect = val.GetComponent<WearNTear>()?.m_destroyedEffect;
			obj3.m_hitEffect = val.GetComponent<WearNTear>()?.m_hitEffect;
			return val4;
		}

		private static void AddSnapPoints(GameObject go, DrawerProportions p)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			float num = p.Width / 2f;
			float num2 = p.Height / 2f;
			float num3 = p.Depth / 2f;
			Vector3[] array = (Vector3[])(object)new Vector3[6]
			{
				new Vector3(0f, num2, 0f),
				new Vector3(0f, 0f - num2, 0f),
				new Vector3(num, 0f, 0f),
				new Vector3(0f - num, 0f, 0f),
				new Vector3(0f, 0f, num3),
				new Vector3(0f, 0f, 0f - num3)
			};
			List<Vector3> list = new List<Vector3>(8);
			float[] array2 = new float[2] { -1f, 1f };
			foreach (float num4 in array2)
			{
				float[] array3 = new float[2] { -1f, 1f };
				foreach (float num5 in array3)
				{
					float[] array4 = new float[2] { -1f, 1f };
					foreach (float num6 in array4)
					{
						list.Add(new Vector3(num4 * num, num5 * num2, num6 * num3));
					}
				}
			}
			int num7 = 1;
			Vector3[] array5 = array;
			foreach (Vector3 localPosition in array5)
			{
				GameObject val = new GameObject($"snappoint_{num7++}")
				{
					tag = "snappoint"
				};
				val.transform.SetParent(go.transform, false);
				val.transform.localPosition = localPosition;
			}
			foreach (Vector3 item in list)
			{
				GameObject val2 = new GameObject($"snappoint_{num7++}")
				{
					tag = "snappoint"
				};
				val2.transform.SetParent(go.transform, false);
				val2.transform.localPosition = item;
			}
		}

		private static Sprite RenderIconFromMesh(Mesh mesh, Material material, DrawerTier tier)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("rid_icon_source");
			try
			{
				GameObject val2 = new GameObject("body");
				val2.transform.SetParent(val.transform, false);
				val2.AddComponent<MeshFilter>().sharedMesh = mesh;
				((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterial = material;
				return RenderIcon(val, tier);
			}
			finally
			{
				Object.Destroy((Object)(object)val);
			}
		}

		private static Sprite RenderIcon(GameObject prefab, DrawerTier tier)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			try
			{
				RenderRequest val = new RenderRequest(prefab)
				{
					Rotation = RenderManager.IsometricRotation,
					Width = 128,
					Height = 128
				};
				Sprite obj = RenderManager.Instance.Render(val);
				if ((Object)(object)obj == (Object)null)
				{
					DrawerPlugin.Log.LogWarning((object)$"RenderManager returned no sprite for {tier}; falling back to donor icon.");
				}
				return obj;
			}
			catch (Exception ex)
			{
				DrawerPlugin.Log.LogWarning((object)$"RenderManager threw rendering {tier}'s icon ({ex.Message}); falling back to donor icon.");
				return null;
			}
		}
	}
	[BepInPlugin("com.grillspett.itemdrawers", "GrillspettItemDrawers", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class DrawerPlugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Converter<Piece, string> <>9__14_2;

			public static ConsoleEvent <>9__14_0;

			internal void <RegisterDiagCommand>b__14_0(ConsoleEventArgs args)
			{
				//IL_06aa: Unknown result type (might be due to invalid IL or missing references)
				//IL_06b1: 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_0431: Unknown result type (might be due to invalid IL or missing references)
				//IL_05ec: Unknown result type (might be due to invalid IL or missing references)
				//IL_05f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
				//IL_0550: 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)
				<>c__DisplayClass14_0 <>c__DisplayClass14_ = default(<>c__DisplayClass14_0);
				<>c__DisplayClass14_.args = args;
				DrawerTier[] all = DrawerTiers.All;
				for (int i = 0; i < all.Length; i++)
				{
					string text = DrawerTiers.PrefabName(all[i]);
					<RegisterDiagCommand>g__Say|14_1("--- " + text + " ---", ref <>c__DisplayClass14_);
					GameObject prefab = PrefabManager.Instance.GetPrefab(text);
					Piece val = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<Piece>());
					if ((Object)(object)val == (Object)null)
					{
						<RegisterDiagCommand>g__Say|14_1("prefab or Piece MISSING", ref <>c__DisplayClass14_);
						continue;
					}
					<RegisterDiagCommand>g__Say|14_1(string.Format("m_enabled={0}  m_category={1}  m_name='{2}'  m_icon={3}", val.m_enabled, val.m_category, val.m_name, ((Object)(object)val.m_icon == (Object)null) ? "NULL" : ((Object)val.m_icon).name), ref <>c__DisplayClass14_);
					<RegisterDiagCommand>g__Say|14_1($"m_usage={val.m_usage}  (this is what 1.0's build-menu tabs filter on)", ref <>c__DisplayClass14_);
					<RegisterDiagCommand>g__Say|14_1("m_craftingStation=" + (((Object)(object)val.m_craftingStation == (Object)null) ? "none" : val.m_craftingStation.m_name), ref <>c__DisplayClass14_);
					Requirement[] resources = val.m_resources;
					<RegisterDiagCommand>g__Say|14_1($"requirements={((resources != null) ? resources.Length : 0)}", ref <>c__DisplayClass14_);
					if (resources != null)
					{
						Requirement[] array = resources;
						foreach (Requirement val2 in array)
						{
							<RegisterDiagCommand>g__Say|14_1(string.Format("   res={0} x{1}", ((Object)(object)val2.m_resItem == (Object)null) ? "UNRESOLVED" : val2.m_resItem.m_itemData.m_shared.m_name, val2.m_amount), ref <>c__DisplayClass14_);
						}
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						<RegisterDiagCommand>g__Say|14_1("no local player", ref <>c__DisplayClass14_);
						continue;
					}
					<RegisterDiagCommand>g__Say|14_1($"IsRecipeKnown('{val.m_name}')={localPlayer.IsRecipeKnown(val.m_name)}", ref <>c__DisplayClass14_);
					<RegisterDiagCommand>g__Say|14_1($"HaveRequirements(IsKnown)={localPlayer.HaveRequirements(val, (RequirementMode)1)}", ref <>c__DisplayClass14_);
					if ((Object)(object)val.m_craftingStation != (Object)null)
					{
						bool flag = localPlayer.m_knownStations.ContainsKey(val.m_craftingStation.m_name);
						bool flag2 = Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(val.m_craftingStation.m_name, ((Component)localPlayer).transform.position));
						<RegisterDiagCommand>g__Say|14_1($"station '{val.m_craftingStation.m_name}': known={flag} inRange={flag2}" + (flag ? "" : "  <-- BLOCKS IsKnown; build a workbench and stand near it"), ref <>c__DisplayClass14_);
					}
					<RegisterDiagCommand>g__Say|14_1($"HaveRequirements(CanBuild)={localPlayer.HaveRequirements(val, (RequirementMode)0)}", ref <>c__DisplayClass14_);
					PieceTable pieceTable = PieceManager.Instance.GetPieceTable(PieceTables.Hammer);
					PieceTable buildPieces = localPlayer.m_buildPieces;
					<RegisterDiagCommand>g__Say|14_1("jotunnTable=" + (((Object)(object)pieceTable == (Object)null) ? "null" : ((Object)pieceTable).name) + "  playerTable=" + (((Object)(object)buildPieces == (Object)null) ? "null" : ((Object)buildPieces).name) + "  " + $"SAME INSTANCE={pieceTable == buildPieces}", ref <>c__DisplayClass14_);
					if ((Object)(object)buildPieces == (Object)null)
					{
						<RegisterDiagCommand>g__Say|14_1("player has no build table equipped", ref <>c__DisplayClass14_);
					}
					else
					{
						<RegisterDiagCommand>g__Say|14_1($"[player table] in m_pieces={buildPieces.m_pieces.Contains(prefab)}  " + $"in m_enabledPieces={buildPieces.m_enabledPieces.Contains(val)}  " + $"in m_availablePieces={buildPieces.m_availablePieces.Contains(val)}", ref <>c__DisplayClass14_);
					}
				}
				Player localPlayer2 = Player.m_localPlayer;
				PieceTable val3 = (((Object)(object)localPlayer2 == (Object)null) ? null : localPlayer2.m_buildPieces);
				if ((Object)(object)val3 == (Object)null)
				{
					<RegisterDiagCommand>g__Say|14_1("no player / no build table for category dump", ref <>c__DisplayClass14_);
				}
				else
				{
					<RegisterDiagCommand>g__Say|14_1($"[player table] selectedCategory={val3.GetSelectedCategory()}  " + "categories=[" + string.Join(", ", val3.m_categories) + "]", ref <>c__DisplayClass14_);
					for (int k = 0; k < val3.m_availablePiecesByCategory.Count; k++)
					{
						List<Piece> list = val3.m_availablePiecesByCategory[k];
						if (list.Count != 0)
						{
							List<string> values = list.ConvertAll((Piece p) => (!((Object)(object)p == (Object)null)) ? p.m_name : "<null>");
							<RegisterDiagCommand>g__Say|14_1(string.Format("[player table] bucket {0} ({1}) x{2}: {3}", k, (object)(PieceCategory)k, list.Count, string.Join(" | ", values)), ref <>c__DisplayClass14_);
						}
					}
				}
				<RegisterDiagCommand>g__Say|14_1("--- Drawer inventories (nearby) ---", ref <>c__DisplayClass14_);
				if ((Object)(object)localPlayer2 == (Object)null || (Object)(object)DrawerManager.Instance == (Object)null)
				{
					<RegisterDiagCommand>g__Say|14_1("no local player or DrawerManager -- cannot enumerate nearby drawers", ref <>c__DisplayClass14_);
					return;
				}
				List<DrawerComponent> list2 = new List<DrawerComponent>();
				DrawerManager.Instance.QueryNear(((Component)localPlayer2).transform.position, 20f, list2);
				<RegisterDiagCommand>g__Say|14_1($"drawers within 20m of player: {list2.Count}  (DrawerComponent.All total: {DrawerComponent.All.Count})", ref <>c__DisplayClass14_);
				foreach (DrawerComponent item in list2)
				{
					bool flag3 = DrawerComponent.All.Contains(item);
					Inventory inventory = ((Container)item).GetInventory();
					string text2 = ((inventory == null) ? "GetInventory()=NULL <-- base.Awake() likely did not run for this drawer" : $"GetInventory()=non-null, {inventory.NrOfItems()} real stack(s), {inventory.GetWidth()} slot(s) total");
					DrawerSnapshot snapshot = item.Snapshot;
					string text3 = "unknown";
					string text4 = "unknown";
					try
					{
						ZNetView val4 = AccessTools.FieldRefAccess<Container, ZNetView>((Container)(object)item, "m_nview");
						if (