Decompiled source of Supermans Storage Custom Storage v1.5.0

SupermansCustomStorage.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.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 CustomStorage
{
	internal static class BlueprintPiece
	{
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDBAwakePatch
		{
			private static void Postfix()
			{
				Register();
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class ObjectDBCopyPatch
		{
			private static void Postfix()
			{
				Register();
			}
		}

		[HarmonyPatch(typeof(Player), "UpdateAvailablePiecesList")]
		private static class KnownPatch
		{
			private static void Prefix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Plugin.ModEnabled.Value)
				{
					Register();
					__instance.m_knownRecipes.Add("Storage Rack");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		private static class TryPlacePatch
		{
			private static bool Prefix(Piece piece, ref bool __result)
			{
				if ((Object)(object)piece == (Object)null || (Object)(object)piece != (Object)(object)TemplatePiece)
				{
					return true;
				}
				if (!DesignWindow.IsOpen && Time.unscaledTime - DesignWindow.ClosedAt > 0.4f)
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static class PlacePatch
		{
			private static bool Prefix(Player __instance, Piece piece, Vector3 pos, Quaternion rot)
			{
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)piece == (Object)null || (Object)(object)piece != (Object)(object)TemplatePiece)
				{
					return true;
				}
				if (Current == null || Current.Parts.Count == 0)
				{
					((Character)__instance).Message((MessageType)2, "Can't lay out this rack: " + (Current?.Warning ?? "no layout"), 0, (Sprite)null, false);
					return false;
				}
				Blueprints.Add(Blueprint.FromLayout(Current, pos, rot, null), broadcast: true);
				((Character)__instance).Message((MessageType)2, "Blueprint laid out - hit the pieces with your hammer to build", 0, (Sprite)null, false);
				return false;
			}
		}

		internal const string PieceName = "Storage Rack";

		internal static GameObject Template;

		internal static Piece TemplatePiece;

		internal static Layout.Result Current;

		internal static Dictionary<string, int> CurrentCosts = new Dictionary<string, int>();

		private static GameObject _holder;

		private static bool _dirty;

		private static float _nextRebuild;

		private static void EnsureTemplate()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Template != (Object)null))
			{
				_holder = new GameObject("SupermansCustomStorage_Templates");
				_holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_holder);
				Template = new GameObject("SupermansStorageRackBlueprint");
				Template.transform.SetParent(_holder.transform, false);
				TemplatePiece = Template.AddComponent<Piece>();
				TemplatePiece.m_name = "Storage Rack";
				TemplatePiece.m_category = (PieceCategory)4;
				TemplatePiece.m_enabled = true;
				TemplatePiece.m_resources = (Requirement[])(object)new Requirement[0];
				TemplatePiece.m_allowedInDungeons = true;
				TemplatePiece.m_canRotate = true;
				TemplatePiece.m_clipEverything = true;
			}
		}

		internal static void Register()
		{
			PieceTable val = Layout.HammerTable();
			if (!((Object)(object)val == (Object)null))
			{
				EnsureTemplate();
				bool flag = val.m_pieces.Contains(Template);
				if (Plugin.ModEnabled.Value && !flag)
				{
					val.m_pieces.Add(Template);
					Rebuild();
				}
				else if (!Plugin.ModEnabled.Value && flag)
				{
					val.m_pieces.Remove(Template);
				}
			}
		}

		internal static void MarkDirty()
		{
			_dirty = true;
		}

		internal static void RebuildIfDirty()
		{
			if (_dirty && !(Time.unscaledTime < _nextRebuild))
			{
				_dirty = false;
				_nextRebuild = Time.unscaledTime + 0.08f;
				Rebuild();
			}
		}

		internal static void Rebuild()
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Template == (Object)null || (Object)(object)Layout.HammerTable() == (Object)null)
			{
				return;
			}
			Current = Layout.Generate(Design.FromConfig());
			CurrentCosts = Layout.Costs(Current.Parts);
			for (int num = Template.transform.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)Template.transform.GetChild(num)).gameObject);
			}
			for (int i = 0; i < Current.Snaps.Count; i++)
			{
				GameObject val = new GameObject((i < Current.SnapNames.Count) ? Current.SnapNames[i] : ("Corner " + (i + 1)))
				{
					tag = "snappoint"
				};
				val.transform.SetParent(Template.transform, false);
				val.transform.localPosition = Current.Snaps[i];
			}
			foreach (Part part in Current.Parts)
			{
				GameObject val2 = PrefabFor(part.Prefab);
				if (!((Object)(object)val2 == (Object)null))
				{
					GameObject val3 = new GameObject(part.Prefab);
					val3.transform.SetParent(Template.transform, false);
					val3.transform.localPosition = part.Pos;
					val3.transform.localRotation = Quaternion.Euler(0f, part.Yaw, 0f);
					Visuals.AddHologram(val2, val3.transform, Visuals.Look.Ghost);
				}
			}
			if ((Object)(object)Current.Chest != (Object)null)
			{
				TemplatePiece.m_icon = Current.Chest.GetComponent<Piece>().m_icon;
			}
			TemplatePiece.m_description = "Design a perfectly spaced storage rack, then lay it down as a blueprint and hit it with the hammer to build it.";
			Preview.Rebuild(Current);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && ((Character)localPlayer).InPlaceMode() && (Object)(object)localPlayer.GetSelectedPiece() == (Object)(object)TemplatePiece)
			{
				localPlayer.SetupPlacementGhost();
			}
		}

		internal static string ChestName(Layout.Result r)
		{
			if (!((Object)(object)r?.Chest != (Object)null))
			{
				return "?";
			}
			return Localization.instance.Localize(r.Chest.GetComponent<Piece>().m_name);
		}

		internal static string Describe(Layout.Result r)
		{
			if (r?.Design == null)
			{
				return "";
			}
			Design design = r.Design;
			string text = $"{design.Cols} wide x {design.Rows} high x {design.Depth} deep, {ChestName(r)}, facing {design.Facing}";
			if (design.Pattern != FacingPattern.AllSame)
			{
				text += $" ({design.Pattern} sideways)";
			}
			text += $", frame: {design.Frame}";
			if (r.Size.x > 0f)
			{
				text += $" ({r.Size.x:0.#} x {r.Size.y:0.#} x {r.Size.z:0.#} m)";
			}
			return text;
		}

		internal static GameObject PrefabFor(string name)
		{
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			PieceTable val2 = Layout.HammerTable();
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			foreach (GameObject piece in val2.m_pieces)
			{
				if ((Object)(object)piece != (Object)null && ((Object)piece).name == name)
				{
					return piece;
				}
			}
			return null;
		}

		internal static bool Selected(Player p)
		{
			if ((Object)(object)p != (Object)null && (Object)(object)TemplatePiece != (Object)null && ((Character)p).InPlaceMode())
			{
				return (Object)(object)p.GetSelectedPiece() == (Object)(object)TemplatePiece;
			}
			return false;
		}

		internal static bool PickUp(Player p, Blueprint bp)
		{
			//IL_0073: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)p == (Object)null || bp == null || (Object)(object)p.m_buildPieces == (Object)null || (Object)(object)TemplatePiece == (Object)null)
			{
				return false;
			}
			Design.Parse(bp.Design)?.ApplyToConfig();
			Rebuild();
			p.UpdateAvailablePiecesList();
			Vector2Int selected = default(Vector2Int);
			PieceCategory category = default(PieceCategory);
			if (!p.m_buildPieces.GetPieceIndex(TemplatePiece, ref selected, ref category))
			{
				return false;
			}
			Blueprints.Remove(bp.Id, broadcast: true);
			p.m_buildPieces.SetCategory(category);
			p.m_buildPieces.SetSelected(selected);
			p.m_placeRotation = Mathf.RoundToInt(((Quaternion)(ref bp.Rot)).eulerAngles.y / 22.5f);
			p.SetupPlacementGhost();
			((Character)p).Message((MessageType)2, "Aim to move it, scroll to rotate, click to place", 0, (Sprite)null, false);
			return true;
		}
	}
	internal sealed class Blueprint
	{
		public string Id;

		public string RackId;

		public Vector3 Pos;

		public Quaternion Rot;

		public Vector3 Size;

		public string Label;

		public string Design;

		public List<Part> Parts;

		public List<Vector3> Snaps = new List<Vector3>();

		public GameObject Root;

		public List<Renderer>[] Renderers;

		public List<Transform> SnapTransforms;

		public bool[] Built;

		public Piece[] PartPiece;

		public List<Piece> Obsolete = new List<Piece>();

		public int MinOpenTier;

		public float Radius;

		public float NextRefresh;

		public int BuiltCount;

		public bool BuiltHereLast;

		public Vector3 WorldPos(int i)
		{
			//IL_0001: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			return Pos + Rot * Parts[i].Pos;
		}

		public Quaternion WorldRot(int i)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			return Rot * Quaternion.Euler(0f, Parts[i].Yaw, 0f);
		}

		public bool Buildable(int i)
		{
			if (!Built[i])
			{
				return Parts[i].Tier <= MinOpenTier;
			}
			return false;
		}

		internal static Blueprint FromLayout(Layout.Result r, Vector3 pos, Quaternion rot, string rackId)
		{
			//IL_002c: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			string text = Guid.NewGuid().ToString("N");
			return new Blueprint
			{
				Id = text,
				RackId = (rackId ?? text),
				Pos = pos,
				Rot = rot,
				Size = r.Size,
				Label = BlueprintPiece.Describe(r),
				Design = (r.Design?.Serialize() ?? ""),
				Parts = new List<Part>(r.Parts),
				Snaps = new List<Vector3>(r.Snaps)
			};
		}

		public void Write(ZPackage pkg)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: 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)
			pkg.Write(2);
			pkg.Write(Id);
			pkg.Write(Pos);
			pkg.Write(Rot);
			pkg.Write(Label ?? "");
			pkg.Write(Parts.Count);
			foreach (Part part in Parts)
			{
				pkg.Write(part.Prefab);
				pkg.Write(part.Pos);
				pkg.Write(part.Yaw);
				pkg.Write(part.Tier);
				pkg.Write(part.Blocking);
			}
			pkg.Write(RackId ?? Id);
			pkg.Write(Size);
			pkg.Write(Design ?? "");
			pkg.Write(Snaps.Count);
			foreach (Vector3 snap in Snaps)
			{
				pkg.Write(snap);
			}
		}

		public static Blueprint Read(ZPackage pkg)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			int num = pkg.ReadInt();
			Blueprint blueprint = new Blueprint
			{
				Id = pkg.ReadString(),
				Pos = pkg.ReadVector3(),
				Rot = pkg.ReadQuaternion(),
				Label = pkg.ReadString(),
				Parts = new List<Part>()
			};
			int num2 = pkg.ReadInt();
			for (int i = 0; i < num2; i++)
			{
				blueprint.Parts.Add(new Part
				{
					Prefab = pkg.ReadString(),
					Pos = pkg.ReadVector3(),
					Yaw = pkg.ReadSingle(),
					Tier = pkg.ReadInt(),
					Blocking = pkg.ReadBool()
				});
			}
			blueprint.RackId = blueprint.Id;
			if (num >= 2)
			{
				blueprint.RackId = pkg.ReadString();
				blueprint.Size = pkg.ReadVector3();
				blueprint.Design = pkg.ReadString();
				int num3 = pkg.ReadInt();
				for (int j = 0; j < num3; j++)
				{
					blueprint.Snaps.Add(pkg.ReadVector3());
				}
			}
			return blueprint;
		}
	}
	internal static class Blueprints
	{
		[HarmonyPatch(typeof(Game), "Start")]
		private static class GameStartPatch
		{
			private static void Postfix()
			{
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.Register<ZPackage>("SupermansCustomStorage_Add", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg)
					{
						OnAdd(pkg);
					});
					ZRoutedRpc.instance.Register<string>("SupermansCustomStorage_Remove", (Action<long, string>)delegate(long sender, string id)
					{
						Remove(id, broadcast: false);
					});
					ZRoutedRpc.instance.Register("SupermansCustomStorage_Request", (Action<long>)OnRequest);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class SpawnPatch
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					Load();
					ZRoutedRpc instance = ZRoutedRpc.instance;
					if (instance != null)
					{
						instance.InvokeRoutedRPC(0L, "SupermansCustomStorage_Request", Array.Empty<object>());
					}
				}
			}
		}

		[HarmonyPatch(typeof(Piece), "GetSnapPoints", new Type[]
		{
			typeof(Vector3),
			typeof(float),
			typeof(List<Transform>),
			typeof(List<Piece>)
		})]
		private static class SnapPointsPatch
		{
			private static void Postfix(Vector3 point, float radius, List<Transform> points)
			{
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				float num = radius * radius;
				foreach (Blueprint value in All.Values)
				{
					if (value.SnapTransforms == null)
					{
						continue;
					}
					foreach (Transform snapTransform in value.SnapTransforms)
					{
						if ((Object)(object)snapTransform != (Object)null)
						{
							Vector3 val = snapTransform.position - point;
							if (((Vector3)(ref val)).sqrMagnitude < num)
							{
								points.Add(snapTransform);
							}
						}
					}
				}
			}
		}

		private const string RpcAdd = "SupermansCustomStorage_Add";

		private const string RpcRemove = "SupermansCustomStorage_Remove";

		private const string RpcRequest = "SupermansCustomStorage_Request";

		internal static readonly Dictionary<string, Blueprint> All = new Dictionary<string, Blueprint>();

		private static readonly HashSet<string> Removed = new HashSet<string>();

		private static readonly List<Piece> TempPieces = new List<Piece>();

		private static string _file;

		internal static bool Loaded => _file != null;

		private static string WorldKey()
		{
			World val = WorldGenerator.instance?.m_world;
			if (val == null)
			{
				return null;
			}
			string text = $"{val.m_seedName}_{val.m_seed}";
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				text = text.Replace(oldChar, '_');
			}
			return text;
		}

		private static void Load()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			string text = WorldKey();
			if (text == null)
			{
				return;
			}
			string text2 = Path.Combine(Paths.ConfigPath, "SupermansCustomStorage", text + ".txt");
			if (text2 == _file)
			{
				return;
			}
			Unload();
			_file = text2;
			if (!File.Exists(text2))
			{
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(text2);
				foreach (string text3 in array)
				{
					if (string.IsNullOrWhiteSpace(text3))
					{
						continue;
					}
					if (text3.StartsWith("-"))
					{
						Removed.Add(text3.Substring(1).Trim());
						continue;
					}
					Blueprint blueprint = Blueprint.Read(new ZPackage(text3.Trim()));
					if (!Removed.Contains(blueprint.Id))
					{
						All[blueprint.Id] = blueprint;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't read blueprints: " + ex.Message));
			}
		}

		private static void Save()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			if (_file == null)
			{
				return;
			}
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(_file));
				List<string> list = new List<string>();
				foreach (Blueprint value in All.Values)
				{
					ZPackage val = new ZPackage();
					value.Write(val);
					list.Add(val.GetBase64());
				}
				list.AddRange(Removed.Select((string id) => "-" + id));
				File.WriteAllLines(_file, list);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't save blueprints: " + ex.Message));
			}
		}

		internal static void Unload()
		{
			HideAll();
			All.Clear();
			Removed.Clear();
			_file = null;
		}

		internal static void Add(Blueprint bp, bool broadcast)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			if (bp != null && !Removed.Contains(bp.Id) && !All.ContainsKey(bp.Id))
			{
				All[bp.Id] = bp;
				Save();
				if (broadcast && ZRoutedRpc.instance != null)
				{
					ZPackage val = new ZPackage();
					bp.Write(val);
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SupermansCustomStorage_Add", new object[1] { val });
				}
			}
		}

		internal static void Remove(string id, bool broadcast)
		{
			if (All.TryGetValue(id, out var value))
			{
				Hide(value);
			}
			All.Remove(id);
			if (Removed.Add(id))
			{
				Save();
			}
			if (broadcast && ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SupermansCustomStorage_Remove", new object[1] { id });
			}
		}

		private static void OnAdd(ZPackage pkg)
		{
			if (!Loaded)
			{
				return;
			}
			try
			{
				Add(Blueprint.Read(pkg), broadcast: false);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Bad blueprint from another player: " + ex.Message));
			}
		}

		private static void OnRequest(long sender)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (!Loaded || ZRoutedRpc.instance == null || sender == ZRoutedRpc.instance.m_id)
			{
				return;
			}
			foreach (Blueprint value in All.Values)
			{
				ZPackage val = new ZPackage();
				value.Write(val);
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SupermansCustomStorage_Add", new object[1] { val });
			}
			foreach (string item in Removed)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SupermansCustomStorage_Remove", new object[1] { item });
			}
		}

		internal static void HideAll()
		{
			foreach (Blueprint value in All.Values)
			{
				Hide(value);
			}
		}

		private static void Hide(Blueprint bp)
		{
			if ((Object)(object)bp.Root != (Object)null)
			{
				Object.Destroy((Object)(object)bp.Root);
			}
			bp.Root = null;
			bp.Renderers = null;
			bp.SnapTransforms = null;
		}

		private static void Show(Blueprint bp)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0027: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00e4: 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_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			bp.Root = new GameObject("StorageRackBlueprint_" + bp.Id);
			bp.Root.transform.SetPositionAndRotation(bp.Pos, bp.Rot);
			bp.Renderers = new List<Renderer>[bp.Parts.Count];
			bp.Built = new bool[bp.Parts.Count];
			bp.PartPiece = (Piece[])(object)new Piece[bp.Parts.Count];
			bp.Radius = 1f;
			for (int i = 0; i < bp.Parts.Count; i++)
			{
				Part part = bp.Parts[i];
				bp.Radius = Mathf.Max(bp.Radius, ((Vector3)(ref part.Pos)).magnitude + 2f);
				GameObject val = new GameObject(part.Prefab);
				val.transform.SetParent(bp.Root.transform, false);
				val.transform.localPosition = part.Pos;
				val.transform.localRotation = Quaternion.Euler(0f, part.Yaw, 0f);
				GameObject val2 = BlueprintPiece.PrefabFor(part.Prefab);
				bp.Renderers[i] = (((Object)(object)val2 != (Object)null) ? Visuals.AddHologram(val2, val.transform, Visuals.Look.Locked) : new List<Renderer>());
			}
			bp.SnapTransforms = new List<Transform>();
			foreach (Vector3 snap in bp.Snaps)
			{
				GameObject val3 = new GameObject("_snappoint")
				{
					tag = "snappoint"
				};
				val3.transform.SetParent(bp.Root.transform, false);
				val3.transform.localPosition = snap;
				bp.SnapTransforms.Add(val3.transform);
			}
			bp.NextRefresh = 0f;
		}

		internal static void Tick()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Loaded || (Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			bool value = Plugin.ModEnabled.Value;
			float value2 = Plugin.ShowDistance.Value;
			List<Blueprint> list = null;
			foreach (Blueprint value3 in All.Values)
			{
				if (!value || !(Vector3.Distance(((Component)localPlayer).transform.position, value3.Pos) < value2))
				{
					if ((Object)(object)value3.Root != (Object)null)
					{
						Hide(value3);
					}
					continue;
				}
				if ((Object)(object)value3.Root == (Object)null)
				{
					Show(value3);
				}
				if (Time.time >= value3.NextRefresh)
				{
					value3.NextRefresh = Time.time + 0.5f;
					if (Refresh(value3))
					{
						(list ?? (list = new List<Blueprint>())).Add(value3);
					}
				}
				UpdateLooks(value3);
			}
			if (list == null)
			{
				return;
			}
			foreach (Blueprint item in list)
			{
				if (item.BuiltHereLast)
				{
					Tidy(item, localPlayer);
				}
				Remove(item.Id, broadcast: true);
				((Character)localPlayer).Message((MessageType)2, "Storage rack complete!", 0, (Sprite)null, false);
			}
		}

		internal static bool Refresh(Blueprint bp)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			if (bp.Built == null)
			{
				return false;
			}
			TempPieces.Clear();
			Piece.GetAllPiecesInRadius(bp.Pos, bp.Radius + 10f, TempPieces);
			Dictionary<string, List<Piece>> dictionary = new Dictionary<string, List<Piece>>();
			foreach (Piece tempPiece in TempPieces)
			{
				if (!((Object)(object)tempPiece == (Object)null) && !((Object)(object)tempPiece.m_nview == (Object)null) && tempPiece.m_nview.IsValid())
				{
					string key = Visuals.PrefabName(((Component)tempPiece).gameObject);
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (dictionary[key] = new List<Piece>());
					}
					value.Add(tempPiece);
				}
			}
			HashSet<Piece> used = new HashSet<Piece>();
			bp.BuiltCount = 0;
			bp.MinOpenTier = int.MaxValue;
			for (int i = 0; i < bp.Parts.Count; i++)
			{
				Vector3 wp = bp.WorldPos(i);
				Piece val = null;
				if (dictionary.TryGetValue(bp.Parts[i].Prefab, out var value2))
				{
					val = ((IEnumerable<Piece>)value2).FirstOrDefault((Func<Piece, bool>)delegate(Piece pc)
					{
						//IL_0019: Unknown result type (might be due to invalid IL or missing references)
						//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_0029: Unknown result type (might be due to invalid IL or missing references)
						if (!used.Contains(pc))
						{
							Vector3 val2 = ((Component)pc).transform.position - wp;
							return ((Vector3)(ref val2)).sqrMagnitude < 0.0025f;
						}
						return false;
					});
				}
				if ((Object)(object)val != (Object)null)
				{
					used.Add(val);
				}
				bp.PartPiece[i] = val;
				bp.Built[i] = (Object)(object)val != (Object)null;
				if (bp.Built[i])
				{
					bp.BuiltCount++;
				}
				else if (bp.Parts[i].Blocking)
				{
					bp.MinOpenTier = Mathf.Min(bp.MinOpenTier, bp.Parts[i].Tier);
				}
			}
			bp.Obsolete = TempPieces.Where((Piece pc) => (Object)(object)pc != (Object)null && !used.Contains(pc) && Racks.IdOf(pc) == bp.RackId).ToList();
			for (int num = 0; num < bp.Parts.Count; num++)
			{
				foreach (Renderer item in bp.Renderers[num])
				{
					if ((Object)(object)item != (Object)null)
					{
						item.enabled = !bp.Built[num];
					}
				}
			}
			return bp.BuiltCount == bp.Parts.Count;
		}

		private static void Tidy(Blueprint bp, Player player)
		{
			if (bp.Obsolete.Count == 0)
			{
				return;
			}
			List<Container> to = (from p in bp.PartPiece
				where (Object)(object)p != (Object)null
				select ((Component)p).GetComponentInChildren<Container>() into c
				where (Object)(object)c != (Object)null
				select c).ToList();
			foreach (Piece item in from p in bp.Obsolete
				where (Object)(object)p != (Object)null
				orderby ((Component)p).transform.position.y descending
				select p)
			{
				Racks.MoveItems(((Component)item).GetComponentInChildren<Container>(), to, player);
				Racks.RemovePiece(item);
			}
			Piece[] partPiece = bp.PartPiece;
			foreach (Piece val in partPiece)
			{
				if ((Object)(object)val != (Object)null)
				{
					Racks.Tag(val, bp);
				}
			}
		}

		private static void UpdateLooks(Blueprint bp)
		{
			for (int i = 0; i < bp.Parts.Count; i++)
			{
				if (!bp.Built[i])
				{
					Visuals.SetLook(look: (Builder.TargetBp != bp || Builder.TargetPart != i) ? (bp.Buildable(i) ? Visuals.Look.Ready : Visuals.Look.Locked) : (Builder.TargetCanBuild ? Visuals.Look.Target : Visuals.Look.Blocked), renderers: bp.Renderers[i]);
				}
			}
		}
	}
	internal static class Builder
	{
		private enum Result
		{
			Built,
			Locked,
			NoStation,
			NoMaterials,
			NoAccess,
			NoStamina,
			Error
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static class UpdatePlacementPatch
		{
			private static bool Prefix(Player __instance, bool takeInput)
			{
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: 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_01bf: Unknown result type (might be due to invalid IL or missing references)
				if (!HammerOut(__instance) || !takeInput || Hud.IsPieceSelectionVisible() || Plugin.TypingOrMenu())
				{
					if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
					{
						ClearTarget();
						AimedRack = null;
					}
					return true;
				}
				UpdateTarget(__instance);
				if (TargetBp == null)
				{
					if (Time.time >= _nextAim)
					{
						_nextAim = Time.time + 0.2f;
						AimedRack = Racks.Aimed(__instance);
					}
					return true;
				}
				AimedRack = null;
				if ((int)Plugin.RemoveBlueprintKey.Value != 0 && Input.GetKeyDown(Plugin.RemoveBlueprintKey.Value))
				{
					Blueprints.Remove(TargetBp.Id, broadcast: true);
					((Character)__instance).Message((MessageType)2, "Blueprint removed", 0, (Sprite)null, false);
					ClearTarget();
					return false;
				}
				if (((!ZInput.IsGamepadActive() && ZInput.GetButtonUp("Remove")) || ZInput.GetButtonUp("JoyRemove")) && !ZInput.GetButton("AltPlace") && !ZInput.GetButton("JoyAltKeys"))
				{
					if (_confirmRemove == TargetBp.Id && Time.time < _confirmUntil)
					{
						Blueprints.Remove(TargetBp.Id, broadcast: true);
						((Character)__instance).Message((MessageType)2, "Blueprint removed", 0, (Sprite)null, false);
						_confirmRemove = null;
						ClearTarget();
					}
					else
					{
						_confirmRemove = TargetBp.Id;
						_confirmUntil = Time.time + 3f;
						((Character)__instance).Message((MessageType)2, "Middle-click again to remove this blueprint (built pieces stay)", 0, (Sprite)null, false);
					}
					__instance.m_removePressedTime = -9999f;
					return false;
				}
				if ((ZInput.GetButtonDown("Attack") || ZInput.GetButtonDown("JoyPlace")) && !Hud.InRadial() && Time.time - __instance.m_lastToolUseTime > __instance.m_placeDelay)
				{
					bool all = (int)Plugin.BuildAllKey.Value != 0 && Input.GetKey(Plugin.BuildAllKey.Value);
					Hit(__instance, all);
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static class GhostPatch
		{
			private static void Postfix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && TargetBp != null && (Object)(object)__instance.m_placementGhost != (Object)null)
				{
					__instance.m_placementGhost.SetActive(false);
				}
			}
		}

		internal static Blueprint TargetBp;

		internal static int TargetPart = -1;

		internal static bool TargetCanBuild;

		internal static string TargetInfo;

		internal static RackInfo AimedRack;

		private static string _confirmRemove;

		private static float _confirmUntil;

		private static float _nextAim;

		private static float _nextInfo;

		private static string _info;

		private static bool _canBuild;

		private static bool HammerOut(Player p)
		{
			if ((Object)(object)p != (Object)null && (Object)(object)p == (Object)(object)Player.m_localPlayer && Plugin.ModEnabled.Value && ((Character)p).InPlaceMode() && (Object)(object)p.m_buildPieces != (Object)null && (Object)(object)p.m_buildPieces == (Object)(object)Layout.HammerTable())
			{
				return !BlueprintPiece.Selected(p);
			}
			return false;
		}

		private static void ClearTarget()
		{
			TargetBp = null;
			TargetPart = -1;
			TargetInfo = null;
		}

		internal static bool FindPart(Player p, out Blueprint target, out int part)
		{
			//IL_0028: 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_0038: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			target = null;
			part = -1;
			if ((Object)(object)p == (Object)null || (Object)(object)GameCamera.instance == (Object)null)
			{
				return false;
			}
			Vector3 position = ((Component)GameCamera.instance).transform.position;
			Vector3 forward = ((Component)GameCamera.instance).transform.forward;
			float num = p.m_maxPlaceDistance + 1f;
			float num2 = 50f;
			foreach (Blueprint value in Blueprints.All.Values)
			{
				if ((Object)(object)value.Root == (Object)null || value.Built == null || Vector3.Distance(((Character)p).m_eye.position, value.Pos) > value.Radius + num + 5f)
				{
					continue;
				}
				for (int i = 0; i < value.Parts.Count; i++)
				{
					if (!value.Built[i])
					{
						GameObject val = BlueprintPiece.PrefabFor(value.Parts[i].Prefab);
						if (!((Object)(object)val == (Object)null) && RayHitsBox(position, forward, value.WorldPos(i), value.WorldRot(i), Visuals.GetBounds(val), out var t) && !(t >= num2) && !(Vector3.Distance(((Character)p).m_eye.position, position + forward * t) > num))
						{
							num2 = t;
							target = value;
							part = i;
						}
					}
				}
			}
			if (target == null)
			{
				return false;
			}
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(position, forward, ref val2, num2, p.m_placeRayMask) && ((RaycastHit)(ref val2)).distance < num2 - 0.05f)
			{
				target = null;
				part = -1;
				return false;
			}
			return true;
		}

		private static void UpdateTarget(Player p)
		{
			Blueprint targetBp = TargetBp;
			int targetPart = TargetPart;
			ClearTarget();
			if (FindPart(p, out TargetBp, out TargetPart))
			{
				if (TargetBp != targetBp || TargetPart != targetPart || Time.time >= _nextInfo || _info == null)
				{
					_nextInfo = Time.time + 0.25f;
					_canBuild = Check(p, TargetBp, TargetPart, out _info);
				}
				TargetCanBuild = _canBuild;
				TargetInfo = _info;
			}
		}

		private static bool RayHitsBox(Vector3 o, Vector3 d, Vector3 pos, Quaternion rot, Bounds b, out float t)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			Quaternion val = Quaternion.Inverse(rot);
			Vector3 val2 = val * (o - pos);
			Vector3 val3 = val * d;
			float num = 0f;
			float num2 = float.MaxValue;
			for (int i = 0; i < 3; i++)
			{
				Vector3 val4;
				if (Mathf.Abs(((Vector3)(ref val3))[i]) < 1E-06f)
				{
					float num3 = ((Vector3)(ref val2))[i];
					val4 = ((Bounds)(ref b)).min;
					if (!(num3 < ((Vector3)(ref val4))[i]))
					{
						float num4 = ((Vector3)(ref val2))[i];
						val4 = ((Bounds)(ref b)).max;
						if (!(num4 > ((Vector3)(ref val4))[i]))
						{
							continue;
						}
					}
					t = 0f;
					return false;
				}
				val4 = ((Bounds)(ref b)).min;
				float num5 = (((Vector3)(ref val4))[i] - ((Vector3)(ref val2))[i]) / ((Vector3)(ref val3))[i];
				val4 = ((Bounds)(ref b)).max;
				float num6 = (((Vector3)(ref val4))[i] - ((Vector3)(ref val2))[i]) / ((Vector3)(ref val3))[i];
				if (num5 > num6)
				{
					float num7 = num5;
					num5 = num6;
					num6 = num7;
				}
				num = Mathf.Max(num, num5);
				num2 = Mathf.Min(num2, num6);
				if (num > num2)
				{
					t = 0f;
					return false;
				}
			}
			t = num;
			return true;
		}

		private static bool Free(Player p, Piece piece)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (!p.m_noPlacementCost)
			{
				return ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey());
			}
			return true;
		}

		internal static int Have(Player p, string itemName)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			int num = ((Humanoid)p).GetInventory().CountItems(itemName, -1, true);
			if (Plugin.UseNearbyChests.Value)
			{
				num += Storage.Count(itemName, ((Component)p).transform.position, Plugin.StorageRange.Value);
			}
			return num;
		}

		private static bool Check(Player p, Blueprint bp, int i, out string info)
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = BlueprintPiece.PrefabFor(bp.Parts[i].Prefab);
			Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				info = "Unknown piece " + bp.Parts[i].Prefab;
				return false;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<b>").Append(Localization.instance.Localize(val2.m_name)).Append("</b>  ")
				.Append($"<color=#9ad>({bp.BuiltCount}/{bp.Parts.Count} built)</color>\n");
			bool result = true;
			if (!bp.Buildable(i))
			{
				stringBuilder.Append("<color=#f88>Build the pieces under it first</color>\n");
				result = false;
			}
			if ((Object)(object)val2.m_craftingStation != (Object)null && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(val2.m_craftingStation.m_name, bp.WorldPos(i))))
			{
				stringBuilder.Append("<color=#f88>Needs a ").Append(Localization.instance.Localize(val2.m_craftingStation.m_name)).Append(" nearby</color>\n");
				result = false;
			}
			if (Free(p, val2))
			{
				stringBuilder.Append("<color=#8f8>Free</color>\n");
			}
			else
			{
				Requirement[] resources = val2.m_resources;
				foreach (Requirement val3 in resources)
				{
					if (!((Object)(object)val3.m_resItem == (Object)null) && val3.m_amount > 0)
					{
						string name = val3.m_resItem.m_itemData.m_shared.m_name;
						int num = Have(p, name);
						bool flag = num >= val3.m_amount;
						if (!flag)
						{
							result = false;
						}
						stringBuilder.Append(flag ? "<color=#ddd>" : "<color=#f88>").Append(Localization.instance.Localize(name)).Append($" {val3.m_amount}  (have {num})</color>\n");
					}
				}
			}
			stringBuilder.Append("\n[<color=#fd4>Hit</color>] build");
			if ((int)Plugin.UpgradeKey.Value != 0)
			{
				stringBuilder.Append($"   [<color=#fd4>{Plugin.UpgradeKey.Value}</color>] redesign");
			}
			if ((int)Plugin.BuildAllKey.Value != 0)
			{
				stringBuilder.Append($"   [<color=#fd4>{Plugin.BuildAllKey.Value} + Hit</color>] build all you can");
			}
			stringBuilder.Append("   [<color=#fd4>Middle-click</color>] remove blueprint");
			info = stringBuilder.ToString();
			return result;
		}

		private static Result BuildOne(Player p, Blueprint bp, int i, bool animate)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			if (bp.Built[i])
			{
				return Result.Error;
			}
			if (!bp.Buildable(i))
			{
				return Result.Locked;
			}
			GameObject val = BlueprintPiece.PrefabFor(bp.Parts[i].Prefab);
			Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val.GetComponent<ZNetView>() == (Object)null)
			{
				return Result.Error;
			}
			Vector3 val3 = bp.WorldPos(i);
			Quaternion val4 = bp.WorldRot(i);
			if (!PrivateArea.CheckAccess(val3, 0f, true, false))
			{
				return Result.NoAccess;
			}
			if ((Object)(object)val2.m_craftingStation != (Object)null && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(val2.m_craftingStation.m_name, val3)))
			{
				return Result.NoStation;
			}
			ItemData rightItem = ((Humanoid)p).GetRightItem();
			if (rightItem != null && !((Character)p).HaveStamina(rightItem.m_shared.m_attack.m_attackStamina))
			{
				return Result.NoStamina;
			}
			if (!Free(p, val2))
			{
				Requirement[] resources = val2.m_resources;
				foreach (Requirement val5 in resources)
				{
					if ((Object)(object)val5.m_resItem != (Object)null && val5.m_amount > 0 && Have(p, val5.m_resItem.m_itemData.m_shared.m_name) < val5.m_amount)
					{
						return Result.NoMaterials;
					}
				}
				Inventory inventory = ((Humanoid)p).GetInventory();
				resources = val2.m_resources;
				foreach (Requirement val6 in resources)
				{
					if (!((Object)(object)val6.m_resItem == (Object)null) && val6.m_amount > 0)
					{
						string name = val6.m_resItem.m_itemData.m_shared.m_name;
						int num = Mathf.Min(val6.m_amount, inventory.CountItems(name, -1, true));
						if (num > 0)
						{
							inventory.RemoveItem(name, num, -1, true);
						}
						int num2 = val6.m_amount - num;
						if (num2 > 0)
						{
							Storage.Remove(name, num2, ((Component)p).transform.position, Plugin.StorageRange.Value);
						}
					}
				}
			}
			Racks.Pending = bp;
			Racks.LastPlaced = null;
			try
			{
				p.PlacePiece(val2, val3, val4, animate, false);
			}
			finally
			{
				Racks.Pending = null;
			}
			Piece lastPlaced = Racks.LastPlaced;
			ReplaceOld(p, bp, i, lastPlaced);
			bp.BuiltHereLast = true;
			((Character)p).UseStamina(p.GetBuildStamina());
			if (rightItem != null && rightItem.m_shared.m_useDurability)
			{
				rightItem.m_durability -= p.GetPlaceDurability(rightItem) * Game.m_durabilityRate;
			}
			if ((Object)(object)p.m_buildPieces != (Object)null && (int)p.m_buildPieces.m_skill != 0)
			{
				((Character)p).RaiseSkill(p.m_buildPieces.m_skill, 1f);
			}
			Game.instance.IncrementPlayerStat((PlayerStatType)2, 1f, false);
			bp.Built[i] = true;
			bp.PartPiece[i] = lastPlaced;
			bp.BuiltCount++;
			RecalcTier(bp);
			return Result.Built;
		}

		private static void ReplaceOld(Player p, Blueprint bp, int i, Piece placed)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			if (bp.Obsolete.Count == 0)
			{
				return;
			}
			Part part = bp.Parts[i];
			GameObject val = BlueprintPiece.PrefabFor(part.Prefab);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Bounds val2 = Layout.Rotate(Visuals.GetBounds(val), part.Yaw);
			((Bounds)(ref val2)).center = ((Bounds)(ref val2)).center + part.Pos;
			((Bounds)(ref val2)).Expand(-0.06f);
			Quaternion val3 = Quaternion.Inverse(bp.Rot);
			List<Container> list = new List<Container>();
			Container mine = (((Object)(object)placed != (Object)null) ? ((Component)placed).GetComponentInChildren<Container>() : null);
			if ((Object)(object)mine != (Object)null)
			{
				list.Add(mine);
			}
			list.AddRange(from x in bp.PartPiece
				where (Object)(object)x != (Object)null
				select ((Component)x).GetComponentInChildren<Container>() into c
				where (Object)(object)c != (Object)null && (Object)(object)c != (Object)(object)mine
				select c);
			foreach (Piece item in bp.Obsolete.ToList())
			{
				if ((Object)(object)item == (Object)null)
				{
					bp.Obsolete.Remove(item);
					continue;
				}
				GameObject val4 = BlueprintPiece.PrefabFor(Visuals.PrefabName(((Component)item).gameObject));
				if ((Object)(object)val4 == (Object)null)
				{
					val4 = ((Component)item).gameObject;
				}
				Bounds bounds = Visuals.GetBounds(val4);
				Quaternion val5 = val3 * ((Component)item).transform.rotation;
				Bounds val6 = Layout.Rotate(bounds, ((Quaternion)(ref val5)).eulerAngles.y);
				((Bounds)(ref val6)).center = ((Bounds)(ref val6)).center + val3 * (((Component)item).transform.position - bp.Pos);
				((Bounds)(ref val6)).Expand(-0.06f);
				if (((Bounds)(ref val2)).Intersects(val6))
				{
					Racks.MoveItems(((Component)item).GetComponentInChildren<Container>(), list, p);
					Racks.RemovePiece(item);
					bp.Obsolete.Remove(item);
				}
			}
		}

		private static void RecalcTier(Blueprint bp)
		{
			bp.MinOpenTier = int.MaxValue;
			for (int i = 0; i < bp.Parts.Count; i++)
			{
				if (!bp.Built[i] && bp.Parts[i].Blocking)
				{
					bp.MinOpenTier = Mathf.Min(bp.MinOpenTier, bp.Parts[i].Tier);
				}
			}
		}

		private static string Explain(Result r)
		{
			return r switch
			{
				Result.Locked => "Build the pieces under it first", 
				Result.NoStation => "$msg_missingstation", 
				Result.NoMaterials => "$msg_missingrequirement", 
				Result.NoAccess => "$msg_privatezone", 
				Result.NoStamina => "$hud_notenoughstamina", 
				_ => null, 
			};
		}

		private static void Hit(Player p, bool all)
		{
			Blueprint bp = TargetBp;
			int target = TargetPart;
			p.m_lastToolUseTime = Time.time;
			if (!all)
			{
				Result result = BuildOne(p, bp, target, animate: true);
				if (result != Result.Built && Explain(result) != null)
				{
					((Character)p).Message((MessageType)2, Explain(result), 0, (Sprite)null, false);
				}
				Finish(bp);
				return;
			}
			int num = 0;
			Result result2 = Result.Locked;
			bool flag = true;
			while (flag)
			{
				flag = false;
				foreach (int item in (from i in Enumerable.Range(0, bp.Parts.Count).Where(bp.Buildable)
					orderby bp.Parts[i].Tier
					select i).ThenBy(delegate(int i)
				{
					//IL_0007: 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_001d: 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)
					Vector3 val = bp.WorldPos(i) - bp.WorldPos(target);
					return ((Vector3)(ref val)).sqrMagnitude;
				}).ToList())
				{
					result2 = BuildOne(p, bp, item, num == 0);
					switch (result2)
					{
					case Result.Built:
						num++;
						flag = true;
						break;
					case Result.NoStamina:
						flag = false;
						goto end_IL_012b;
					}
					continue;
					end_IL_012b:
					break;
				}
			}
			if (num > 0)
			{
				((Character)p).Message((MessageType)2, string.Format("Built {0} piece{1}", num, (num == 1) ? "" : "s"), 0, (Sprite)null, false);
			}
			else if (Explain(result2) != null)
			{
				((Character)p).Message((MessageType)2, Explain(result2), 0, (Sprite)null, false);
			}
			Finish(bp);
		}

		private static void Finish(Blueprint bp)
		{
			bp.NextRefresh = Time.time + 0.5f;
			_info = null;
		}
	}
	internal sealed class Design
	{
		public ChestType Chest;

		public int Cols;

		public int Rows;

		public int Depth;

		public FrameStyle Frame;

		public bool Dividers;

		public float SideGap;

		public float TopGap;

		public float DepthGap;

		public ChestFacing Facing;

		public FacingPattern Pattern;

		internal static Design FromConfig()
		{
			return new Design
			{
				Chest = Plugin.Chest.Value,
				Cols = Plugin.Columns.Value,
				Rows = Plugin.Rows.Value,
				Depth = Plugin.Depth.Value,
				Frame = Plugin.Frame.Value,
				Dividers = Plugin.Dividers.Value,
				SideGap = Plugin.SideGap.Value,
				TopGap = Plugin.TopGap.Value,
				DepthGap = Plugin.DepthGap.Value,
				Facing = Plugin.Facing.Value,
				Pattern = Plugin.Pattern.Value
			};
		}

		internal void ApplyToConfig()
		{
			Plugin.Chest.Value = Chest;
			Plugin.Columns.Value = Cols;
			Plugin.Rows.Value = Rows;
			Plugin.Depth.Value = Depth;
			Plugin.Frame.Value = Frame;
			Plugin.Dividers.Value = Dividers;
			Plugin.SideGap.Value = SideGap;
			Plugin.TopGap.Value = TopGap;
			Plugin.DepthGap.Value = DepthGap;
			Plugin.Facing.Value = Facing;
			Plugin.Pattern.Value = Pattern;
		}

		public string Serialize()
		{
			CultureInfo invariantCulture = CultureInfo.InvariantCulture;
			return string.Join(",", "2", Chest.ToString(), Cols.ToString(invariantCulture), Rows.ToString(invariantCulture), Depth.ToString(invariantCulture), Frame.ToString(), Dividers ? "1" : "0", SideGap.ToString(invariantCulture), TopGap.ToString(invariantCulture), Facing.ToString(), Pattern.ToString(), DepthGap.ToString(invariantCulture));
		}

		public static Design Parse(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return null;
			}
			try
			{
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				string[] array = s.Split(new char[1] { ',' });
				if (array.Length < 11 || (array[0] != "1" && array[0] != "2"))
				{
					return null;
				}
				return new Design
				{
					Chest = (ChestType)Enum.Parse(typeof(ChestType), array[1]),
					Cols = int.Parse(array[2], invariantCulture),
					Rows = int.Parse(array[3], invariantCulture),
					Depth = int.Parse(array[4], invariantCulture),
					Frame = (FrameStyle)Enum.Parse(typeof(FrameStyle), array[5]),
					Dividers = (array[6] == "1"),
					SideGap = float.Parse(array[7], invariantCulture),
					TopGap = float.Parse(array[8], invariantCulture),
					Facing = (ChestFacing)Enum.Parse(typeof(ChestFacing), array[9]),
					Pattern = (FacingPattern)Enum.Parse(typeof(FacingPattern), array[10]),
					DepthGap = ((array[0] == "2" && array.Length > 11) ? float.Parse(array[11], invariantCulture) : 0.1f)
				};
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class DesignWindow
	{
		private sealed class ChestChoice
		{
			public ChestType Type;

			public GameObject Prefab;
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		private static class MouseCapturePatch
		{
			private static void Postfix()
			{
				if (IsOpen)
				{
					ZCursor.LockState = (CursorLockMode)0;
					ZCursor.Show();
				}
			}
		}

		[HarmonyPatch(typeof(Player), "TakeInput")]
		private static class TakeInputPatch
		{
			private static void Postfix(ref bool __result)
			{
				if (IsOpen)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(Menu), "Update")]
		private static class MenuPatch
		{
			private static bool Prefix()
			{
				if (!IsOpen)
				{
					return ClosedFrame != Time.frameCount;
				}
				return false;
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static WindowFunction <0>__DrawWindow;
		}

		internal static bool IsOpen;

		internal static int ClosedFrame = -1;

		internal static float ClosedAt = -10f;

		private static RackInfo _upgrade;

		private static bool _wasSelected;

		private static bool _pending;

		private static bool _wasHammer;

		private static Rect _rect;

		private static bool _dragging;

		private static float _lastDrag;

		private static GUIStyle _head;

		private static GUIStyle _small;

		private static GUIStyle _rich;

		private const int WindowId = 96799249;

		private static List<ChestChoice> _chests;

		private static readonly Dictionary<string, int> _have = new Dictionary<string, int>();

		private static float _nextHave;

		private static Vector2 _scroll;

		private static int Have(string item)
		{
			if (Time.unscaledTime >= _nextHave)
			{
				_have.Clear();
				_nextHave = Time.unscaledTime + 0.5f;
			}
			if (!_have.TryGetValue(item, out var value))
			{
				Player localPlayer = Player.m_localPlayer;
				value = (_have[item] = (((Object)(object)localPlayer != (Object)null) ? Builder.Have(localPlayer, item) : 0));
			}
			return value;
		}

		internal static void Open(RackInfo upgrade)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			_upgrade = upgrade;
			_chests = null;
			_nextHave = 0f;
			if (upgrade?.Design != null)
			{
				upgrade.Design.ApplyToConfig();
			}
			BlueprintPiece.MarkDirty();
			float num = Mathf.Min(980f, (float)Screen.width - 40f);
			float num2 = Mathf.Min(620f, (float)Screen.height - 40f);
			_rect = new Rect(((float)Screen.width - num) / 2f, ((float)Screen.height - num2) / 2f, num, num2);
			IsOpen = true;
		}

		internal static void Close()
		{
			IsOpen = false;
			_upgrade = null;
			ClosedFrame = Time.frameCount;
			ClosedAt = Time.unscaledTime;
		}

		internal static void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !Plugin.ModEnabled.Value)
			{
				if (IsOpen)
				{
					Close();
				}
				return;
			}
			bool flag = BlueprintPiece.Selected(localPlayer);
			bool wasHammer = ((Character)localPlayer).InPlaceMode();
			if (flag && !_wasSelected && _wasHammer)
			{
				_pending = true;
			}
			_wasHammer = wasHammer;
			if (!flag)
			{
				_pending = false;
			}
			_wasSelected = flag;
			if (IsOpen)
			{
				if (Input.GetKeyDown((KeyCode)27) || ((Character)localPlayer).IsDead())
				{
					Close();
				}
				else
				{
					Preview.Render(Time.unscaledDeltaTime, !_dragging && Time.unscaledTime - _lastDrag > 2f);
				}
			}
			else
			{
				if (Plugin.TypingOrMenu() || Hud.IsPieceSelectionVisible())
				{
					return;
				}
				if (_pending)
				{
					_pending = false;
					Open(null);
				}
				else if (flag && Plugin.KeyDown(Plugin.DesignKey))
				{
					Open(null);
				}
				else if (((Character)localPlayer).InPlaceMode() && (Object)(object)localPlayer.m_buildPieces == (Object)(object)Layout.HammerTable() && Plugin.KeyDown(Plugin.UpgradeKey))
				{
					RackInfo rackInfo = Racks.Aimed(localPlayer);
					if (rackInfo != null)
					{
						Open(rackInfo);
					}
					else
					{
						((Character)localPlayer).Message((MessageType)2, "Look at a storage rack built with this mod to upgrade it", 0, (Sprite)null, false);
					}
				}
			}
		}

		internal static void Draw()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0043: 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_0050: 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_0063: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//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)
			if (IsOpen)
			{
				if (_head == null)
				{
					_head = new GUIStyle(GUI.skin.label)
					{
						fontSize = 15,
						fontStyle = (FontStyle)1,
						richText = true
					};
					_small = new GUIStyle(GUI.skin.label)
					{
						fontSize = 12,
						richText = true,
						wordWrap = true
					};
					_rich = new GUIStyle(GUI.skin.label)
					{
						fontSize = 13,
						richText = true,
						wordWrap = true
					};
				}
				GUI.color = Color.white;
				GUI.backgroundColor = new Color(0.25f, 0.27f, 0.32f, 1f);
				GUI.Box(_rect, GUIContent.none);
				GUI.Box(_rect, GUIContent.none);
				Rect rect = _rect;
				object obj = <>O.<0>__DrawWindow;
				if (obj == null)
				{
					WindowFunction val = DrawWindow;
					<>O.<0>__DrawWindow = val;
					obj = (object)val;
				}
				_rect = GUILayout.Window(96799249, rect, (WindowFunction)obj, (_upgrade?.Blueprint != null) ? "Edit Storage Rack Blueprint" : ((_upgrade != null) ? "Upgrade Storage Rack" : "Storage Rack Designer"), Array.Empty<GUILayoutOption>());
			}
		}

		private static void DrawWindow(int id)
		{
			//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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_060f: Unknown result type (might be due to invalid IL or missing references)
			//IL_064a: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0760: Unknown result type (might be due to invalid IL or missing references)
			//IL_07af: Unknown result type (might be due to invalid IL or missing references)
			//IL_086a: Unknown result type (might be due to invalid IL or missing references)
			Layout.Result current = BlueprintPiece.Current;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(((Rect)(ref _rect)).width * 0.5f) });
			Rect rect = GUILayoutUtility.GetRect(((Rect)(ref _rect)).width * 0.5f - 10f, ((Rect)(ref _rect)).height * 0.55f);
			if ((Object)(object)Preview.Texture != (Object)null)
			{
				GUI.DrawTexture(rect, Preview.Texture, (ScaleMode)2);
			}
			HandleDrag(rect);
			GUILayout.Label("<color=#9ab>Drag the picture to turn it.</color>", _small, Array.Empty<GUILayoutOption>());
			if (current != null)
			{
				GUILayout.Label($"<b>{current.ChestCount}</b> x {BlueprintPiece.ChestName(current)}", _rich, Array.Empty<GUILayoutOption>());
				if (current.Size.x > 0f)
				{
					GUILayout.Label($"Size: {current.Size.x:0.#} m wide, {current.Size.y:0.#} m high, {current.Size.z:0.#} m deep", _rich, Array.Empty<GUILayoutOption>());
				}
				if (current.Legs > 0.02f)
				{
					GUILayout.Label($"<color=#9ab>Bottom shelf sits {current.Legs:0.00} m up on short legs (posts come in whole pole lengths).</color>", _small, Array.Empty<GUILayoutOption>());
				}
				if (current.Note != null)
				{
					GUILayout.Label("<color=#fd8>" + current.Note + "</color>", _small, Array.Empty<GUILayoutOption>());
				}
				if (current.Warning != null)
				{
					GUILayout.Label("<color=#f88>" + current.Warning + "</color>", _rich, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Label("<b>Materials for the whole rack</b>" + ((_upgrade != null) ? " <color=#9ab>(pieces you already have are skipped)</color>" : ""), _rich, Array.Empty<GUILayoutOption>());
				foreach (KeyValuePair<string, int> item in BlueprintPiece.CurrentCosts.OrderBy((KeyValuePair<string, int> k) => k.Key))
				{
					int num = Have(item.Key);
					string text = ((num >= item.Value) ? "#ddd" : "#fb8");
					GUILayout.Label($"<color={text}>{Localization.instance.Localize(item.Key)}: {item.Value}  (you have {num})</color>", _small, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Label("<color=#9ab>You don't need it all now: you build the blueprint piece by piece as you gather materials.</color>", _small, Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndVertical();
			GUILayout.Space(12f);
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			_scroll = GUILayout.BeginScrollView(_scroll, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Chest", _head, Array.Empty<GUILayoutOption>());
			ChestButtons();
			GUILayout.Space(6f);
			GUILayout.Label("Size", _head, Array.Empty<GUILayoutOption>());
			Counter("Wide", Plugin.Columns, 1, 12);
			Counter("High", Plugin.Rows, 1, 8);
			Counter("Deep", Plugin.Depth, 1, 4);
			GUILayout.Space(6f);
			GUILayout.Label("Chests face", _head, Array.Empty<GUILayoutOption>());
			Choice<ChestFacing>(Plugin.Facing, new string[6] { "Front", "Right", "Back", "Left", "Back to back", "Face to face" }, 3);
			GUILayout.Label("<color=#9ab>Back to back / face to face split a rack that's 2+ deep into two halves.</color>", _small, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Straight / sideways mix", _head, Array.Empty<GUILayoutOption>());
			Choice<FacingPattern>(Plugin.Pattern, new string[4] { "All the same", "Alternate rows", "Alternate columns", "Checkerboard" }, 2);
			GUILayout.Space(6f);
			GUILayout.Label("Frame", _head, Array.Empty<GUILayoutOption>());
			Choice<FrameStyle>(Plugin.Frame, new string[3] { "Wood", "Ashwood", "None" }, 3);
			bool flag = GUILayout.Toggle(Plugin.Dividers.Value, " Post between every chest", Array.Empty<GUILayoutOption>());
			if (flag != Plugin.Dividers.Value)
			{
				Plugin.Dividers.Value = flag;
			}
			GUILayout.Space(6f);
			GUILayout.Label("Spacing", _head, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Touching", Array.Empty<GUILayoutOption>()))
			{
				SetSpacing(0f, 0.02f, 0f);
			}
			if (GUILayout.Button("Snug", Array.Empty<GUILayoutOption>()))
			{
				SetSpacing(0.1f, 0.1f, 0.05f);
			}
			if (GUILayout.Button("Roomy", Array.Empty<GUILayoutOption>()))
			{
				SetSpacing(0.35f, 0.35f, 0.25f);
			}
			if (GUILayout.Button("Wide open", Array.Empty<GUILayoutOption>()))
			{
				SetSpacing(0.75f, 0.6f, 0.5f);
			}
			GUILayout.EndHorizontal();
			Spacing("Side to side", Plugin.SideGap);
			Spacing("Above each chest", Plugin.TopGap);
			if (Plugin.Depth.Value > 1)
			{
				Spacing("Front to back", Plugin.DepthGap);
			}
			GUILayout.EndScrollView();
			GUILayout.FlexibleSpace();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.backgroundColor = new Color(0.3f, 0.6f, 0.35f);
			if (GUILayout.Button((_upgrade?.Blueprint != null) ? "Update blueprint" : ((_upgrade != null) ? "Upgrade rack" : "Place blueprint"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) }) && current != null && current.Parts.Count > 0)
			{
				Confirm(current);
			}
			GUI.backgroundColor = new Color(0.75f, 0.25f, 0.2f);
			if (_upgrade?.Blueprint != null)
			{
				Blueprint blueprint = _upgrade.Blueprint;
				GUI.backgroundColor = new Color(0.3f, 0.45f, 0.7f);
				GUI.enabled = blueprint.BuiltCount == 0;
				if (GUILayout.Button("Move / rotate", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Height(36f),
					GUILayout.Width(130f)
				}))
				{
					Player localPlayer = Player.m_localPlayer;
					Close();
					_wasSelected = true;
					if (!BlueprintPiece.PickUp(localPlayer, blueprint) && localPlayer != null)
					{
						((Character)localPlayer).Message((MessageType)2, "Couldn't pick up the blueprint - is the hammer out?", 0, (Sprite)null, false);
					}
				}
				GUI.enabled = true;
				GUI.backgroundColor = new Color(0.75f, 0.25f, 0.2f);
			}
			if (_upgrade?.Blueprint != null && GUILayout.Button("Remove blueprint", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(36f),
				GUILayout.Width(150f)
			}))
			{
				Blueprints.Remove(_upgrade.Blueprint.Id, broadcast: true);
				Player localPlayer2 = Player.m_localPlayer;
				if (localPlayer2 != null)
				{
					((Character)localPlayer2).Message((MessageType)2, "Blueprint removed (built pieces stay)", 0, (Sprite)null, false);
				}
				Close();
			}
			GUI.backgroundColor = new Color(0.45f, 0.3f, 0.3f);
			if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(36f),
				GUILayout.Width(110f)
			}))
			{
				Close();
			}
			GUI.backgroundColor = new Color(0.25f, 0.27f, 0.32f, 1f);
			GUILayout.EndHorizontal();
			if (_upgrade?.Blueprint != null && _upgrade.Blueprint.BuiltCount > 0)
			{
				GUILayout.Label($"<color=#fd8>{_upgrade.Blueprint.BuiltCount} pieces are already built, so this blueprint can't be moved. Remove it and place a new one, or keep building.</color>", _small, Array.Empty<GUILayoutOption>());
			}
			GUILayout.Label((_upgrade?.Blueprint != null) ? "<color=#9ab>Move / rotate picks the blueprint up onto your hammer: aim, scroll to turn it, click to put it down.</color>" : ((_upgrade != null) ? "<color=#9ab>The rack becomes a blueprint. Hit the new pieces with the hammer: old chests are swapped out and their contents move into the new ones.</color>" : "<color=#9ab>Then aim where it goes: it snaps to floors, walls, other racks and blueprints. Scroll to rotate, click to lay it down.</color>"), _small, Array.Empty<GUILayoutOption>());
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 22f));
		}

		private static void SetSpacing(float side, float above, float depth)
		{
			Plugin.SideGap.Value = side;
			Plugin.TopGap.Value = above;
			Plugin.DepthGap.Value = depth;
		}

		private static void Spacing(string label, ConfigEntry<float> entry)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			float num = entry.Value;
			if (GUILayout.Button("-", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) }))
			{
				num -= 0.05f;
			}
			num = GUILayout.HorizontalSlider(num, 0f, 2f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(80f) });
			if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) }))
			{
				num += 0.05f;
			}
			GUILayout.Label((num <= 0.001f) ? "<b>touching</b>" : $"<b>{num * 100f:0} cm</b>", _rich, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			GUILayout.EndHorizontal();
			num = Mathf.Clamp(Mathf.Round(num * 100f) / 100f, 0f, 2f);
			if (Mathf.Abs(num - entry.Value) > 0.004f)
			{
				entry.Value = num;
			}
		}

		private static void Confirm(Layout.Result r)
		{
			Player localPlayer = Player.m_localPlayer;
			if (_upgrade != null && (Object)(object)localPlayer != (Object)null)
			{
				Racks.Upgrade(_upgrade, r, localPlayer);
				Close();
				return;
			}
			Close();
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, "Aim where the rack goes - it snaps to floors, walls and other racks", 0, (Sprite)null, false);
			}
		}

		private static void HandleDrag(Rect view)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			//IL_0011: 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_004e: Invalid comparison between Unknown and I4
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Event current = Event.current;
			if ((int)current.type == 0 && ((Rect)(ref view)).Contains(current.mousePosition))
			{
				_dragging = true;
				current.Use();
			}
			else if ((int)current.type == 1 && _dragging)
			{
				_dragging = false;
				current.Use();
			}
			else if ((int)current.type == 3 && _dragging)
			{
				Preview.Spin(current.delta.x * 0.5f);
				_lastDrag = Time.unscaledTime;
				current.Use();
			}
		}

		private static void ChestButtons()
		{
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			if (_chests == null)
			{
				_chests = (from ChestType t in Enum.GetValues(typeof(ChestType))
					select new ChestChoice
					{
						Type = t,
						Prefab = Layout.FindChest(t)
					} into x
					where (Object)(object)x.Prefab != (Object)null
					select x).ToList();
			}
			List<ChestChoice> chests = _chests;
			int num = 2;
			for (int num2 = 0; num2 < chests.Count; num2 += num)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				for (int num3 = num2; num3 < Mathf.Min(num2 + num, chests.Count); num3++)
				{
					ChestType type = chests[num3].Type;
					Piece component = chests[num3].Prefab.GetComponent<Piece>();
					bool flag = Plugin.Chest.Value == type;
					GUI.backgroundColor = (flag ? new Color(0.35f, 0.55f, 0.85f) : new Color(0.25f, 0.27f, 0.32f, 1f));
					if (GUILayout.Button("        " + Localization.instance.Localize(component.m_name), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(38f) }) && !flag)
					{
						Plugin.Chest.Value = type;
					}
					Rect lastRect = GUILayoutUtility.GetLastRect();
					DrawSprite(new Rect(((Rect)(ref lastRect)).x + 4f, ((Rect)(ref lastRect)).y + 3f, 32f, 32f), component.m_icon);
				}
				GUILayout.EndHorizontal();
			}
			GUI.backgroundColor = new Color(0.25f, 0.27f, 0.32f, 1f);
		}

		private static void DrawSprite(Rect r, Sprite s)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)s == (Object)null) && !((Object)(object)s.texture == (Object)null) && (int)Event.current.type == 7)
			{
				Rect textureRect = s.textureRect;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)s.texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)s.texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)s.texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)s.texture).height);
				GUI.DrawTextureWithTexCoords(r, (Texture)(object)s.texture, val);
			}
		}

		private static void Counter(string label, ConfigEntry<int> entry, int min, int max)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			if (GUILayout.Button("-", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(34f),
				GUILayout.Height(26f)
			}) && entry.Value > min)
			{
				int value = entry.Value;
				entry.Value = value - 1;
			}
			GUILayout.Label($"<b>{entry.Value}</b>", _rich, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(36f) });
			if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(34f),
				GUILayout.Height(26f)
			}) && entry.Value < max)
			{
				int value = entry.Value;
				entry.Value = value + 1;
			}
			GUILayout.EndHorizontal();
		}

		private static void Choice<T>(ConfigEntry<T> entry, string[] labels, int perRow) where T : Enum
		{
			int num = Convert.ToInt32(entry.Value);
			int num2 = GUILayout.SelectionGrid(num, labels, perRow, Array.Empty<GUILayoutOption>());
			if (num2 != num)
			{
				entry.Value = (T)Enum.ToObject(typeof(T), num2);
			}
		}
	}
	internal static class Hint
	{
		private static GUIStyle _style;

		private static string SnapKeys()
		{
			string text = null;
			string text2 = null;
			try
			{
				ZInput instance = ZInput.instance;
				text = ((instance != null) ? instance.GetBoundKeyString("TabLeft", true) : null);
				ZInput instance2 = ZInput.instance;
				text2 = ((instance2 != null) ? instance2.GetBoundKeyString("TabRight", true) : null);
			}
			catch
			{
			}
			if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2))
			{
				return text + " / " + text2;
			}
			return "Q / E";
		}

		internal static void Draw()
		{
			//IL_0117: 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
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: 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_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Expected O, but got Unknown
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ModEnabled.Value || DesignWindow.IsOpen || (Object)(object)Hud.instance == (Object)null || Hud.IsUserHidden())
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || Plugin.TypingOrMenu() || Hud.IsPieceSelectionVisible())
			{
				return;
			}
			string text = null;
			if (Builder.TargetBp != null)
			{
				text = Builder.TargetInfo;
			}
			else if (BlueprintPiece.Selected(localPlayer))
			{
				text = "<b>Storage Rack</b>  " + BlueprintPiece.Describe(BlueprintPiece.Current) + ((BlueprintPiece.Current?.Warning != null) ? ("\n<color=#f88>" + BlueprintPiece.Current.Warning + "</color>") : "") + "\nAim to move it, scroll to rotate, click to place. Snaps to floors, walls, other racks and blueprints.\n[<color=#fd4>" + SnapKeys() + "</color>] pick the corner it snaps by   [<color=#fd4>Shift</color>] hold for no snapping" + (((int)Plugin.DesignKey.Value != 0) ? $"   [<color=#fd4>{Plugin.DesignKey.Value}</color>] change design" : "");
			}
			else if (Builder.AimedRack != null && (int)Plugin.UpgradeKey.Value != 0)
			{
				Design design = Builder.AimedRack.Design;
				text = "<b>Storage rack</b>" + ((design != null) ? $"  {design.Cols} x {design.Rows} x {design.Depth} {design.Chest}" : "") + $"\n[<color=#fd4>{Plugin.UpgradeKey.Value}</color>] upgrade / redesign";
			}
			if (!string.IsNullOrEmpty(text))
			{
				if (_style == null)
				{
					_style = new GUIStyle(GUI.skin.label)
					{
						alignment = (TextAnchor)1,
						richText = true,
						fontSize = 16,
						wordWrap = true
					};
				}
				float num = Mathf.Min(760f, (float)Screen.width - 40f);
				GUIContent val = new GUIContent(text);
				float num2 = _style.CalcHeight(val, num - 20f) + 12f;
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(((float)Screen.width - num) / 2f, (float)Screen.height * 0.58f, num, num2);
				Color color = GUI.color;
				GUI.color = new Color(0f, 0f, 0f, 0.55f);
				GUI.DrawTexture(val2, (Texture)(object)Texture2D.whiteTexture);
				GUI.color = color;
				GUI.Label(new Rect(((Rect)(ref val2)).x + 10f, ((Rect)(ref val2)).y + 6f, ((Rect)(ref val2)).width - 20f, ((Rect)(ref val2)).height - 6f), val, _style);
			}
		}
	}
	internal sealed class Part
	{
		public string Prefab;

		public Vector3 Pos;

		public float Yaw;

		public int Tier;

		public bool Blocking;
	}
	internal static class Layout
	{
		internal sealed class Result
		{
			public List<Part> Parts = new List<Part>();

			public List<Vector3> Snaps = new List<Vector3>();

			public List<string> SnapNames = new List<string>();

			public GameObject Chest;

			public string Warning;

			public Vector3 Size;

			public int ChestCount;

			public Design Design;

			public string Note;

			public float Legs;
		}

		private static readonly Dictionary<ChestType, string> ChestTokens = new Dictionary<ChestType, string>
		{
			{
				ChestType.Wood,
				"$piece_chestwood"
			},
			{
				ChestType.Reinforced,
				"$piece_chest"
			},
			{
				ChestType.BlackMetal,
				"$piece_chestblackmetal"
			},
			{
				ChestType.Barrel,
				"$piece_chestbarrel"
			},
			{
				ChestType.Personal,
				"$piece_chestprivate"
			},
			{
				ChestType.Grausten,
				"$piece_chestgrausten"
			}
		};

		private static readonly Dictionary<FrameStyle, string> FramePrefix = new Dictionary<FrameStyle, string>
		{
			{
				FrameStyle.Wood,
				"wood_"
			},
			{
				FrameStyle.Ashwood,
				"ashwood_"
			}
		};

		private static readonly Dictionary<FrameStyle, string[]> FrameNames = new Dictionary<FrameStyle, string[]>
		{
			{
				FrameStyle.Wood,
				new string[2] { "wood_floor_1x1", "wood_pole" }
			},
			{
				FrameStyle.Ashwood,
				new string[2] { "ashwood_floor_1x1", "ashwood_pole_1m" }
			}
		};

		internal static PieceTable HammerTable()
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("Hammer") : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces;
		}

		private static IEnumerable<GameObject> HammerPieces()
		{
			PieceTable val = HammerTable();
			if ((Object)(object)val == (Object)null)
			{
				yield break;
			}
			foreach (GameObject piece in val.m_pieces)
			{
				if ((Object)(object)piece != (Object)null && (Object)(object)piece != (Object)(object)BlueprintPiece.Template && (Object)(object)piece.GetComponent<Piece>() != (Object)null)
				{
					yield return piece;
				}
			}
		}

		internal static GameObject FindChest(ChestType type)
		{
			string token = ChestTokens[type];
			return HammerPieces().FirstOrDefault((Func<GameObject, bool>)((GameObject go) => go.GetComponent<Piece>().m_name == token && (Object)(object)go.GetComponentInChildren<Container>(true) != (Object)null));
		}

		internal static bool FindFrame(FrameStyle style, out GameObject floor, out GameObject pole)
		{
			floor = (pole = null);
			if (!FramePrefix.TryGetValue(style, out var prefix))
			{
				return false;
			}
			List<GameObject> source = (from go in HammerPieces()
				where ((Object)go).name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
				select go).ToList();
			if (FrameNames.TryGetValue(style, out var names))
			{
				floor = ((IEnumerable<GameObject>)source).FirstOrDefault((Func<GameObject, bool>)((GameObject go) => ((Object)go).name == names[0]));
				pole = ((IEnumerable<GameObject>)source).FirstOrDefault((Func<GameObject, bool>)((GameObject go) => ((Object)go).name == names[1]));
				if ((Object)(object)floor != (Object)null && (Object)(object)pole != (Object)null)
				{
					return true;
				}
			}
			floor = (GameObject)(((Object)(object)floor != (Object)null) ? ((object)floor) : ((object)(from x in (from go in source
					where ((Object)go).name.IndexOf("floor", StringComparison.OrdinalIgnoreCase) >= 0 && ((Object)go).name.IndexOf("deco", StringComparison.OrdinalIgnoreCase) < 0 && ((Object)go).name.IndexOf("tri", StringComparison.OrdinalIgnoreCase) < 0
					select new
					{
						go = go,
						b = Visuals.GetBounds(go)
					}).Where(x =>
				{
					//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_0009: 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_0020: 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_002e: 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_0036: Unknown result type (might be due to invalid IL or missing references)
					//IL_004e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0053: Unknown result type (might be due to invalid IL or missing references)
					//IL_0056: Unknown result type (might be due to invalid IL or missing references)
					Bounds b = x.b;
					if (((Bounds)(ref b)).size.x > 0.8f)
					{
						b = x.b;
						float x2 = ((Bounds)(ref b)).size.x;
						b = x.b;
						if (Mathf.Abs(x2 - ((Bounds)(ref b)).size.z) < 0.15f)
						{
							b = x.b;
							return ((Bounds)(ref b)).size.y < 0.6f;
						}
					}
					return false;
				}).OrderBy(x =>
				{
					//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_0009: Unknown result type (might be due to invalid IL or missing references)
					Bounds b = x.b;
					return ((Bounds)(ref b)).size.x;
				})
				select x.go).FirstOrDefault()));
			pole = (GameObject)(((Object)(object)pole != (Object)null) ? ((object)pole) : ((object)(from x in (from go in source
					where ((Object)go).name.IndexOf("pole", StringComparison.OrdinalIgnoreCase) >= 0 && ((Object)go).name.IndexOf("log", StringComparison.OrdinalIgnoreCase) < 0
					select new
					{
						go = go,
						b = Visuals.GetBounds(go)
					}).Where(x =>
				{
					//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_0009: 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_0020: 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)
					Bounds b = x.b;
					if (((Bounds)(ref b)).size.y > 0.5f)
					{
						b = x.b;
						return ((Bounds)(ref b)).size.x < 0.5f;
					}
					return false;
				}).OrderBy(x =>
				{
					//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_0009: Unknown result type (might be due to invalid IL or missing references)
					Bounds b = x.b;
					return Mathf.Abs(((Bounds)(ref b)).size.y - 1f);
				})
				select x.go).FirstOrDefault()));
			if ((Object)(object)floor != (Object)null)
			{
				return (Object)(object)pole != (Object)null;
			}
			return false;
		}

		internal static Bounds Rotate(Bounds b, float yaw)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			Quaternion val = Quaternion.Euler(0f, yaw, 0f);
			Bounds result = default(Bounds);
			((Bounds)(ref result))..ctor(val * ((Bounds)(ref b)).center, Vector3.zero);
			for (int i = 0; i < 8; i++)
			{
				((Bounds)(ref result)).Encapsulate(val * (((Bounds)(ref b)).center + Vector3.Scale(((Bounds)(ref b)).extents, new Vector3((float)(((i & 1) != 0) ? 1 : (-1)), (float)(((i & 2) != 0) ? 1 : (-1)), (float)(((i & 4) != 0) ? 1 : (-1))))));
			}
			return result;
		}

		private static float ChestYaw(Design d, int k, int c, int z, int deep)
		{
			bool flag = z * 2 < deep - 1;
			return Mathf.Repeat(d.Facing switch
			{
				ChestFacing.Right => 90f, 
				ChestFacing.Back => 180f, 
				ChestFacing.Left => 270f, 
				ChestFacing.BackToBack => flag ? 180f : 0f, 
				ChestFacing.FaceToFace => flag ? 0f : 180f, 
				_ => 0f, 
			} + (float)(d.Pattern switch
			{
				FacingPattern.AlternateRows => k % 2, 
				FacingPattern.AlternateColumns => c % 2, 
				FacingPattern.Checkerboard => (k + c) % 2, 
				_ => 0, 
			}) * 90f, 360f);
		}

		private static bool SnapFootprint(GameObject prefab, out Vector2 size, out Vector2 center)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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)
			//IL_0027: 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)
			//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_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			size = (center = Vector2.zero);
			List<Vector3> list = new List<Vector3>();
			Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
			Transform[] componentsInChildren = prefab.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)(object)prefab.transform && ((Component)val).CompareTag("snappoint"))
				{
					list.Add(((Matrix4x4)(ref worldToLocalMatrix)).MultiplyPoint3x4(val.position));
				}
			}
			if (list.Count < 3)
			{
				return false;
			}
			float num = list.Min((Vector3 v) => v.x);
			float num2 = list.Max((Vector3 v) => v.x);
			float num3 = list.Min((Vector3 v) => v.z);
			float num4 = list.Max((Vector3 v) => v.z);
			size = new Vector2(num2 - num, num4 - num3);
			center = new Vector2((num + num2) / 2f, (num3 + num4) / 2f);
			if (size.x > 0.4f)
			{
				return size.y > 0.4f;
			}
			return false;
		}

		private static void ShiftForDividers(float[] centers, float size, float shelf, float tile, float margin, float pt, float clear, List<float> lines)
		{
			margin = Mathf.Max(0f, margin);
			float num = 0f;
			int num2 = -1;
			List<float> list = new List<float>();
			for (int i = 0; i <= 40; i++)
			{
				float num3 = ((i == 0) ? 0f : ((float)((i + 1) / 2) * (margin / 20f) * ((i % 2 == 1) ? 1f : (-1f))));
				if (Mathf.Abs(num3) > margin + 0.0001f)
				{
					continue;
				}
				list.Clear();
				for (int j = 0; j + 1 < centers.Length; j++)
				{
					float num4 = centers[j] + num3 + size / 2f;
					float num5 = centers[j + 1] + num3 - size / 2f;
					float num6 = (num4 + num5) / 2f;
					float num7 = float.MaxValue;
					float item = 0f;
					for (int k = 1; k < Mathf.RoundToInt(shelf / tile); k++)
					{
						float num8 = (0f - shelf) / 2f + (float)k * tile;
						if (!(num8 - pt / 2f < num4 + clear) && !(num8 + pt / 2f > num5 - clear) && Mathf.Abs(num8 - num6) < num7)
						{
							num7 = Mathf.Abs(num8 - num6);
							item = num8;
						}
					}
					if (num7 < float.MaxValue)
					{
						list.Add(item);
					}
				}
				if (list.Count > num2)
				{
					num2 = list.Count;
					num = num3;
					lines.Clear();
					lines.AddRange(list);
				}
			}
			for (int l = 0; l < centers.Length; l++)
			{
				centers[l] += num;
			}
		}

		internal static Result Generate(Design d)
		{
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: 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_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_044a: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_046a: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			//IL_051c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0528: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_080a: Unknown result type (might be due to invalid IL or missing references)
			//IL_090d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0acb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a01: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a10: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a38: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a43: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a48: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bb2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0af4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0afd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b10: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b1b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b24: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b2f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b34: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cd9: Unknown result type (might be due to invalid IL or missing references)
			Result res = new Result
			{
				Design = d
			};
			GameObject val = FindChest(d.Chest);
			if ((Object)(object)val == (Object)null)
			{
				{
					IEnumerator enumerator = Enum.GetValues(typeof(ChestType)).GetEnumerator();
					try
					{
						while (enumerator.MoveNext() && !((Object)(object)(val = FindChest((ChestType)enumerator.Current)) != (Object)null))
						{
						}
					}
					finally
					{
						IDisposable disposable = enumerato