Decompiled source of VikingQualityOfLife v2.1.2

BepInEx/plugins/ccorp/ccorp.dll

Decompiled 19 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ccorp")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+55ac085e598f45528b30b0721946a085c7dd2397")]
[assembly: AssemblyProduct("ccorp")]
[assembly: AssemblyTitle("ccorp")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ccorp
{
	internal static class AdminSpawnMenu
	{
		private sealed class Entry
		{
			internal string Prefab;

			internal string Name;

			internal Sprite Icon;
		}

		private const int PageSize = 18;

		private static GameObject _root;

		private static GameObject _quantityRoot;

		private static RectTransform _rows;

		private static TMP_Text _status;

		private static TMP_Text _pageText;

		private static TMP_InputField _search;

		private static TMP_InputField _amount;

		private static TMP_FontAsset _font;

		private static readonly List<Entry> Catalog = new List<Entry>();

		private static int _page;

		internal static bool HasQuantityPrompt => (Object)(object)_quantityRoot != (Object)null;

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

		internal static void Show()
		{
			try
			{
				BuildMenu();
			}
			catch
			{
				Close();
				throw;
			}
		}

		private static void BuildMenu()
		{
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			//IL_0215: 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_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: 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_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d8: Expected O, but got Unknown
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_056b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0584: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0630: Unknown result type (might be due to invalid IL or missing references)
			//IL_063f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0663: Unknown result type (might be due to invalid IL or missing references)
			//IL_0672: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Hud.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			Close();
			_font = ((TMP_Text)Hud.instance.m_hoverName).font;
			Catalog.Clear();
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
				if (val?.m_itemData?.m_shared != null)
				{
					ZNetScene instance = ZNetScene.instance;
					if (!((Object)(object)((instance != null) ? instance.GetPrefab(((Object)item).name) : null) == (Object)null) && AdminSpawnMenuInput.IsValid(((Object)item).name, 1))
					{
						Catalog.Add(new Entry
						{
							Prefab = ((Object)item).name,
							Name = (string.IsNullOrEmpty(val.m_itemData.m_shared.m_name) ? ((Object)item).name : Localization.instance.Localize(val.m_itemData.m_shared.m_name)),
							Icon = PickupCatalogSafety.SelectIcon(val.m_itemData.m_shared.m_icons, val.m_itemData.m_variant)
						});
					}
				}
			}
			Catalog.Sort((Entry a, Entry b) => string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase));
			_page = 0;
			_root = new GameObject("ccorp.AdminSpawnMenu", new Type[4]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			Canvas component = _root.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 100;
			CanvasScaler component2 = _root.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1280f, 720f);
			component2.matchWidthOrHeight = 0.5f;
			RectTransform obj = Box(_root.transform, "Shade", Vector2.zero, new Vector2(1280f, 720f), new Color(0f, 0f, 0f, 0.6f));
			obj.anchorMin = Vector2.zero;
			obj.anchorMax = Vector2.one;
			obj.sizeDelta = Vector2.zero;
			RectTransform val2 = Box(_root.transform, "Panel", Vector2.zero, new Vector2(780f, 610f), new Color(0.1f, 0.075f, 0.045f, 0.99f));
			Label((Transform)(object)val2, "Admin item spawn", new Vector2(0f, 264f), new Vector2(650f, 40f), 26f);
			Button((Transform)(object)val2, "Close", new Vector2(330f, 265f), new Vector2(92f, 32f), Close);
			_status = Label((Transform)(object)val2, "", new Vector2(0f, 224f), new Vector2(720f, 34f), 16f);
			RectTransform val3 = Box((Transform)(object)val2, "Search", new Vector2(0f, 180f), new Vector2(720f, 40f), new Color(0.18f, 0.16f, 0.12f));
			_search = ((Component)val3).gameObject.AddComponent<TMP_InputField>();
			RectTransform component3 = new GameObject("Viewport", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			}).GetComponent<RectTransform>();
			((Transform)component3).SetParent((Transform)(object)val3, false);
			component3.anchorMin = Vector2.zero;
			component3.anchorMax = Vector2.one;
			component3.offsetMin = new Vector2(12f, 4f);
			component3.offsetMax = new Vector2(-12f, -4f);
			TMP_Text val4 = Label((Transform)(object)component3, "", Vector2.zero, new Vector2(690f, 32f), 19f);
			val4.alignment = (TextAlignmentOptions)4097;
			val4.richText = false;
			TMP_Text val5 = Label((Transform)(object)component3, "Search item name or prefab...", Vector2.zero, new Vector2(690f, 32f), 19f);
			val5.alignment = (TextAlignmentOptions)4097;
			((Graphic)val5).color = new Color(0.7f, 0.7f, 0.7f);
			_search.textViewport = component3;
			_search.textComponent = (TMP_Text)(TextMeshProUGUI)val4;
			_search.placeholder = (Graphic)(object)val5;
			_search.lineType = (LineType)0;
			_search.characterLimit = 100;
			((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				_page = 0;
				Refresh();
			});
			_rows = new GameObject("Rows", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)_rows).SetParent((Transform)(object)val2, false);
			_rows.sizeDelta = new Vector2(730f, 380f);
			_rows.anchoredPosition = new Vector2(0f, -34f);
			Button((Transform)(object)val2, "< Previous", new Vector2(45f, -250f), new Vector2(130f, 36f), delegate
			{
				_page = Math.Max(0, _page - 1);
				Refresh();
			});
			Button((Transform)(object)val2, "Next >", new Vector2(205f, -250f), new Vector2(130f, 36f), delegate
			{
				_page++;
				Refresh();
			});
			_pageText = Label((Transform)(object)val2, "", new Vector2(325f, -250f), new Vector2(90f, 36f), 16f);
			Label((Transform)(object)val2, "Click an item, enter a quantity and spawn it.  •  F7 / Esc to close", new Vector2(0f, -285f), new Vector2(740f, 25f), 14f);
			Refresh();
			GameCamera instance2 = GameCamera.instance;
			if (instance2 != null)
			{
				instance2.UpdateMouseCapture();
			}
			_search.ActivateInputField();
		}

		private static void Refresh()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: 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)
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			foreach (Transform item in (Transform)_rows)
			{
				((Component)item).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)item).gameObject);
			}
			string query = _search.text ?? "";
			List<Entry> list = Catalog.Where((Entry e) => e.Name.IndexOf(query, StringComparison.CurrentCultureIgnoreCase) >= 0 || e.Prefab.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
			int num = Math.Max(1, (list.Count + 18 - 1) / 18);
			_page = Math.Max(0, Math.Min(_page, num - 1));
			_status.text = $"{list.Count} items  •  Server validates every spawn request";
			_pageText.text = $"{_page + 1}/{num}";
			Vector2 position = default(Vector2);
			for (int num2 = 0; num2 < Math.Min(18, list.Count - _page * 18); num2++)
			{
				Entry entry = list[_page * 18 + num2];
				((Vector2)(ref position))..ctor((float)((num2 % 2 == 0) ? (-182) : 182), (float)(166 - num2 / 2 * 41));
				RectTransform obj = Button((Transform)(object)_rows, "", position, new Vector2(356f, 37f), delegate
				{
					AskQuantity(entry);
				});
				((Graphic)((Component)obj).GetComponent<Image>()).color = new Color(0.19f, 0.17f, 0.12f);
				RectTransform val2 = Box((Transform)(object)obj, "Icon", new Vector2(-155f, 0f), new Vector2(30f, 30f), Color.white);
				((Component)val2).GetComponent<Image>().sprite = entry.Icon;
				if ((Object)(object)entry.Icon == (Object)null)
				{
					((Graphic)((Component)val2).GetComponent<Image>()).color = Color.clear;
				}
				((Component)val2).GetComponent<Image>().preserveAspect = true;
				((Graphic)((Component)val2).GetComponent<Image>()).raycastTarget = false;
				TMP_Text obj2 = Label((Transform)(object)obj, entry.Name, new Vector2(15f, 0f), new Vector2(290f, 32f), 18f);
				obj2.alignment = (TextAlignmentOptions)4097;
				obj2.richText = false;
				obj2.enableAutoSizing = true;
				obj2.fontSizeMin = 12f;
				obj2.fontSizeMax = 18f;
				obj2.overflowMode = (TextOverflowModes)1;
			}
			if (list.Count == 0)
			{
				Label((Transform)(object)_rows, "No matching items.", Vector2.zero, new Vector2(600f, 40f), 20f);
			}
		}

		internal static void Close()
		{
			CancelQuantity();
			if ((Object)(object)_search != (Object)null)
			{
				_search.DeactivateInputField(false);
			}
			if ((Object)(object)_root != (Object)null)
			{
				if ((Object)(object)EventSystem.current != (Object)null)
				{
					EventSystem.current.SetSelectedGameObject((GameObject)null);
				}
				_root.SetActive(false);
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
			_rows = null;
			_search = null;
			_status = (_pageText = null);
			_font = null;
			Catalog.Clear();
			GameCamera instance = GameCamera.instance;
			if (instance != null)
			{
				instance.UpdateMouseCapture();
			}
		}

		private static void AskQuantity(Entry entry)
		{
			//IL_002c: 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_0054: 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_006a: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00e7: 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_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: 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_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Expected O, but got Unknown
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			CancelQuantity();
			_search.DeactivateInputField(false);
			RectTransform obj = Box(_root.transform, "QuantityShade", Vector2.zero, new Vector2(1280f, 720f), new Color(0f, 0f, 0f, 0.7f));
			obj.anchorMin = Vector2.zero;
			obj.anchorMax = Vector2.one;
			obj.sizeDelta = Vector2.zero;
			_quantityRoot = ((Component)obj).gameObject;
			RectTransform parent = Box((Transform)(object)obj, "Quantity", Vector2.zero, new Vector2(470f, 260f), new Color(0.1f, 0.075f, 0.045f, 1f));
			TMP_Text obj2 = Label((Transform)(object)parent, entry.Name, new Vector2(0f, 92f), new Vector2(440f, 35f), 23f);
			obj2.richText = false;
			obj2.overflowMode = (TextOverflowModes)1;
			TMP_Text obj3 = Label((Transform)(object)parent, entry.Prefab, new Vector2(0f, 59f), new Vector2(440f, 30f), 16f);
			obj3.richText = false;
			obj3.overflowMode = (TextOverflowModes)1;
			TMP_Text error = Label((Transform)(object)parent, "Quantity (positive whole number)", new Vector2(0f, 27f), new Vector2(440f, 30f), 16f);
			RectTransform val = Box((Transform)(object)parent, "Amount", new Vector2(0f, -10f), new Vector2(220f, 40f), new Color(0.18f, 0.16f, 0.12f));
			_amount = ((Component)val).gameObject.AddComponent<TMP_InputField>();
			RectTransform component = new GameObject("Viewport", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			}).GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)val, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = new Vector2(10f, 4f);
			component.offsetMax = new Vector2(-10f, -4f);
			TMP_Text val2 = Label((Transform)(object)component, "", Vector2.zero, new Vector2(190f, 32f), 20f);
			val2.richText = false;
			_amount.textViewport = component;
			_amount.textComponent = (TMP_Text)(TextMeshProUGUI)val2;
			_amount.lineType = (LineType)0;
			_amount.contentType = (ContentType)2;
			_amount.characterLimit = 10;
			_amount.text = "1";
			bool submitted = false;
			Action spawn = delegate
			{
				if (!submitted && !((Object)(object)_amount == (Object)null))
				{
					if (!AdminSpawnMenuInput.TryAmount(_amount.text, out var amount))
					{
						error.text = "Enter a positive whole number.";
						_amount.ActivateInputField();
					}
					else
					{
						submitted = true;
						if (!AdminSpawnMenuController.RequestSpawn(entry.Prefab, amount))
						{
							submitted = false;
							if ((Object)(object)error != (Object)null)
							{
								error.text = "Could not send the request. Try again.";
							}
						}
						else
						{
							CancelQuantity();
							if ((Object)(object)_status != (Object)null)
							{
								_status.text = $"Requested {entry.Prefab} x{amount}. Check the game's spawn confirmation.";
							}
						}
					}
				}
			};
			Button((Transform)(object)parent, "Cancel", new Vector2(-105f, -83f), new Vector2(170f, 38f), CancelQuantity);
			Button((Transform)(object)parent, "Spawn", new Vector2(105f, -83f), new Vector2(170f, 38f), spawn);
			((UnityEvent<string>)(object)_amount.onSubmit).AddListener((UnityAction<string>)delegate
			{
				spawn();
			});
			_amount.ActivateInputField();
		}

		internal static void CancelQuantity()
		{
			if (!((Object)(object)_quantityRoot == (Object)null))
			{
				if ((Object)(object)_amount != (Object)null)
				{
					_amount.DeactivateInputField(false);
				}
				if ((Object)(object)EventSystem.current != (Object)null)
				{
					EventSystem.current.SetSelectedGameObject((GameObject)null);
				}
				_quantityRoot.SetActive(false);
				Object.Destroy((Object)(object)_quantityRoot);
				_quantityRoot = null;
				_amount = null;
			}
		}

		private static RectTransform Box(Transform parent, string name, Vector2 position, Vector2 size, Color color)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0049: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			component.pivot = val2;
			Vector2 anchorMin = (component.anchorMax = val2);
			component.anchorMin = anchorMin;
			component.anchoredPosition = position;
			component.sizeDelta = size;
			((Graphic)val.GetComponent<Image>()).color = color;
			return component;
		}

		private static TMP_Text Label(Transform parent, string text, Vector2 position, Vector2 size, float fontSize)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI component = new GameObject("Text", new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			}).GetComponent<TextMeshProUGUI>();
			((Transform)((TMP_Text)component).rectTransform).SetParent(parent, false);
			RectTransform rectTransform = ((TMP_Text)component).rectTransform;
			RectTransform rectTransform2 = ((TMP_Text)component).rectTransform;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			rectTransform2.anchorMax = val;
			rectTransform.anchorMin = val;
			((TMP_Text)component).rectTransform.anchoredPosition = position;
			((TMP_Text)component).rectTransform.sizeDelta = size;
			((TMP_Text)component).font = _font;
			((TMP_Text)component).fontSize = fontSize;
			((TMP_Text)component).text = text;
			((Graphic)component).color = Color.white;
			((TMP_Text)component).alignment = (TextAlignmentOptions)514;
			((TMP_Text)component).textWrappingMode = (TextWrappingModes)0;
			((Graphic)component).raycastTarget = false;
			return (TMP_Text)(object)component;
		}

		private static RectTransform Button(Transform parent, string title, Vector2 position, Vector2 size, Action action)
		{
			//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_0025: 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_005d: Expected O, but got Unknown
			//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)
			RectTransform val = Box(parent, "Button", position, size, new Color(0.3f, 0.24f, 0.13f));
			Button obj = ((Component)val).gameObject.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)((Component)val).GetComponent<Image>();
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				action();
			});
			if (!string.IsNullOrEmpty(title))
			{
				Label((Transform)(object)val, title, Vector2.zero, size, 17f);
			}
			return val;
		}
	}
	internal static class AdminSpawnMenuController
	{
		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class ConnectionPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNetPeer peer)
			{
				peer.m_rpc.Register<int>("ccorp_AdminSpawnMenuAccess", (Action<ZRpc, int>)ReceiveRequest);
				peer.m_rpc.Register<int, bool>("ccorp_AdminSpawnMenuAccessResult", (Action<ZRpc, int, bool>)ReceiveResponse);
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnDestroy")]
		private static class DisconnectPatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				Reset();
			}
		}

		[HarmonyPatch(typeof(TextInput), "IsVisible")]
		private static class ModalPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ref bool __result)
			{
				__result |= AdminSpawnMenu.IsOpen;
			}
		}

		[HarmonyPatch(typeof(Player), "TakeInput")]
		private static class InputPatch
		{
			[HarmonyPostfix]
			private static void Postfix(Player __instance, ref bool __result)
			{
				if (AdminSpawnMenu.IsOpen && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		private static class CursorPatch
		{
			[HarmonyPrefix]
			private static bool Prefix()
			{
				if (!AdminSpawnMenu.IsOpen)
				{
					return true;
				}
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
				return false;
			}
		}

		[HarmonyPatch(typeof(Menu), "Update")]
		private static class EscapePatch
		{
			[HarmonyPrefix]
			private static bool Prefix()
			{
				if (!AdminSpawnMenu.IsOpen)
				{
					return true;
				}
				if (Input.GetKeyDown((KeyCode)27))
				{
					if (AdminSpawnMenu.HasQuantityPrompt)
					{
						AdminSpawnMenu.CancelQuantity();
					}
					else
					{
						Reset();
					}
				}
				return false;
			}
		}

		private const string AccessRequestRpc = "ccorp_AdminSpawnMenuAccess";

		private const string AccessResponseRpc = "ccorp_AdminSpawnMenuAccessResult";

		private static int _sequence;

		private static int _pending;

		private static float _deadline;

		private static Player _requestPlayer;

		private static Player _menuPlayer;

		private static void Message(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		internal static void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || (AdminSpawnMenu.IsOpen && (Object)(object)_menuPlayer != (Object)(object)localPlayer) || (_pending != 0 && (Object)(object)_requestPlayer != (Object)(object)localPlayer))
			{
				Reset();
				return;
			}
			if (_pending != 0 && Time.unscaledTime > _deadline)
			{
				_pending = 0;
				Message("Could not verify admin access. Try again.");
			}
			if (!Input.GetKeyDown((KeyCode)288))
			{
				return;
			}
			if (AdminSpawnMenu.IsOpen || _pending != 0)
			{
				Reset();
			}
			else
			{
				if (!CanOpen())
				{
					return;
				}
				if (ZNet.instance.IsServer())
				{
					if (LocalHostIsAdmin())
					{
						Open();
					}
					else
					{
						Message("You're not admin");
					}
					return;
				}
				ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
				if (serverPeer?.m_rpc != null)
				{
					_pending = ++_sequence;
					_requestPlayer = localPlayer;
					_deadline = Time.unscaledTime + 6f;
					serverPeer.m_rpc.Invoke("ccorp_AdminSpawnMenuAccess", new object[1] { _pending });
				}
			}
		}

		private static bool CanOpen()
		{
			if ((Object)(object)Hud.instance != (Object)null && !Console.IsVisible() && !Menu.IsVisible() && !TextInput.IsVisible() && !InventoryGui.IsVisible() && !StoreGui.IsVisible() && !Minimap.IsOpen() && !Hud.IsPieceSelectionVisible() && !UnifiedPopup.IsVisible())
			{
				if (!((Object)(object)Chat.instance == (Object)null))
				{
					return !Chat.instance.HasFocus();
				}
				return true;
			}
			return false;
		}

		private static bool LocalHostIsAdmin()
		{
			return ZNet.instance.IsAdmin(((object)Unsafe.As<PlatformUserID, PlatformUserID>(ref UserInfo.GetLocalUser().UserId)/*cast due to .constrained prefix*/).ToString());
		}

		private static void Open()
		{
			_menuPlayer = Player.m_localPlayer;
			try
			{
				AdminSpawnMenu.Show();
			}
			catch (Exception ex)
			{
				AdminSpawnMenu.Close();
				Plugin.Log.LogError((object)("Failed to open admin spawn menu: " + ex));
				Message("Could not open the spawn menu. Check the log.");
			}
		}

		private static void ReceiveRequest(ZRpc rpc, int request)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ((rpc != null) ? rpc.GetSocket() : null) != null)
			{
				string hostName = rpc.GetSocket().GetHostName();
				bool flag = ZNet.instance.IsAdmin(hostName);
				if (!flag)
				{
					Plugin.Log.LogWarning((object)("Admin spawn menu denied for connection '" + hostName + "'."));
				}
				rpc.Invoke("ccorp_AdminSpawnMenuAccessResult", new object[2] { request, flag });
			}
		}

		private static void ReceiveResponse(ZRpc rpc, int request, bool allowed)
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || _pending == 0 || request != _pending || Time.unscaledTime > _deadline || (Object)(object)_requestPlayer != (Object)(object)Player.m_localPlayer || (Object)(object)Player.m_localPlayer == (Object)null || ((rpc != null) ? rpc.GetSocket() : null) == null)
			{
				return;
			}
			ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
			object obj;
			if (serverPeer == null)
			{
				obj = null;
			}
			else
			{
				ZRpc rpc2 = serverPeer.m_rpc;
				obj = ((rpc2 != null) ? rpc2.GetSocket() : null);
			}
			ISocket val = (ISocket)obj;
			if (val != null && !(rpc.GetSocket().GetHostName() != val.GetHostName()))
			{
				_pending = 0;
				if (!allowed)
				{
					Message("You're not admin");
				}
				else if (!((Character)Player.m_localPlayer).IsDead() && !((Character)Player.m_localPlayer).IsTeleporting() && CanOpen())
				{
					Open();
				}
			}
		}

		internal static bool RequestSpawn(string prefab, int amount)
		{
			if (!AdminSpawnMenu.IsOpen || (Object)(object)_menuPlayer != (Object)(object)Player.m_localPlayer || (Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsDead() || ((Character)Player.m_localPlayer).IsTeleporting() || (Object)(object)ZNetScene.instance == (Object)null || !AdminSpawnMenuInput.IsValid(prefab, amount))
			{
				return false;
			}
			if (ZNet.instance.IsServer())
			{
				if (!LocalHostIsAdmin())
				{
					Reset();
					Message("You're not admin");
					return false;
				}
				Plugin.Log.LogWarning((object)$"Admin menu spawn authorized for local host: {prefab} x{amount}.");
				Plugin.MaterializeAdminSpawn(prefab, amount);
				return true;
			}
			if (ZNet.instance.GetServerPeer()?.m_rpc == null)
			{
				return false;
			}
			ZNet.instance.RemoteCommand($"ccorp_spawn {prefab} {amount}");
			return true;
		}

		internal static void Reset()
		{
			_pending = 0;
			_requestPlayer = (_menuPlayer = null);
			if (AdminSpawnMenu.IsOpen)
			{
				AdminSpawnMenu.Close();
			}
		}
	}
	internal static class AdminSpawnMenuInput
	{
		internal static bool TryAmount(string text, out int amount)
		{
			if (int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out amount))
			{
				return amount > 0;
			}
			return false;
		}

		internal static bool IsValid(string prefab, int amount)
		{
			if (string.IsNullOrEmpty(prefab) || amount <= 0)
			{
				return false;
			}
			foreach (char c in prefab)
			{
				if (char.IsWhiteSpace(c) || char.IsControl(c) || c == ';')
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class AreaRepair
	{
		[HarmonyPatch(typeof(Player), "Repair")]
		private static class PlayerRepairPatch
		{
			private static void Postfix(Player __instance)
			{
				//IL_0045: 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_00f2: 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_012c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0139: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || RepairRadius == null || RepairRadius.Value <= 0f)
				{
					return;
				}
				Piece hoveringPiece = __instance.GetHoveringPiece();
				if ((Object)(object)hoveringPiece == (Object)null || !PrivateArea.CheckAccess(((Component)hoveringPiece).transform.position, 0f, true, false))
				{
					return;
				}
				int num = 0;
				HashSet<WearNTear> hashSet = new HashSet<WearNTear>();
				Collider[] array = Physics.OverlapSphere(((Component)hoveringPiece).transform.position, RepairRadius.Value, LayerMask.GetMask(new string[2] { "piece", "piece_nonsolid" }));
				for (int i = 0; i < array.Length; i++)
				{
					WearNTear componentInParent = ((Component)array[i]).GetComponentInParent<WearNTear>();
					if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent))
					{
						Piece component = ((Component)componentInParent).GetComponent<Piece>();
						if (!((Object)(object)component == (Object)null) && !((Object)(object)component == (Object)(object)hoveringPiece) && CanRepair(__instance, component) && PrivateArea.CheckAccess(((Component)component).transform.position, 0f, true, false) && componentInParent.Repair())
						{
							num++;
							component.m_placeEffect.Create(((Component)component).transform.position, ((Component)component).transform.rotation, (Transform)null, 1f, -1, ((Character)__instance).GetZDOID());
						}
					}
				}
				if (num > 0)
				{
					((Character)__instance).Message((MessageType)1, $"Estruturas próximas reparadas: {num}", 0, (Sprite)null, false);
				}
			}
		}

		private static readonly MethodInfo CheckCanRemovePiece = AccessTools.Method(typeof(Player), "CheckCanRemovePiece", new Type[1] { typeof(Piece) }, (Type[])null);

		private static ConfigEntry<float> RepairRadius;

		internal static void Initialize(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			RepairRadius = config.Bind<float>("Building", "RepairRadius", 3f, new ConfigDescription("Raio em metros que repara estruturas próximas ao usar o martelo. Use 0 para reparar somente a peça clicada.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
		}

		private static bool CanRepair(Player player, Piece piece)
		{
			if (!(CheckCanRemovePiece == null))
			{
				return (bool)CheckCanRemovePiece.Invoke(player, new object[1] { piece });
			}
			return true;
		}
	}
	internal static class ChestAccess
	{
		[HarmonyPatch(typeof(Container), "Awake")]
		private static class RegisterPatch
		{
			[HarmonyPostfix]
			private static void Postfix(Container __instance)
			{
				ZNetView val = View.Invoke(__instance);
				if (!((Object)(object)val == (Object)null) && val.IsValid() && QuickStack.IsChest(__instance))
				{
					val.Register<ZPackage>("ccorp_RequestChestAccess", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
					{
						ReceiveRequest(__instance, sender, package);
					});
					val.Register<ZPackage>("ccorp_ChestAccessResponse", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
					{
						ReceiveResponse(__instance, sender, package);
					});
				}
			}
		}

		[HarmonyPatch]
		private static class OpenReservationPatch
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				yield return AccessTools.Method(typeof(Container), "RPC_RequestOpen", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(Container), "RPC_RequestStack", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(Container), "RPC_RequestTakeAll", (Type[])null, (Type[])null);
			}

			[HarmonyPrefix]
			private static bool Prefix(Container __instance, long uid, MethodBase __originalMethod)
			{
				ZNetView val = View.Invoke(__instance);
				if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner() || !ReservedForAnother(val.GetZDO(), uid))
				{
					return true;
				}
				string text = ((__originalMethod.Name == "RPC_RequestStack") ? "RPC_StackResponse" : ((__originalMethod.Name == "RPC_RequestTakeAll") ? "RPC_TakeAllResponse" : "RPC_OpenResponse"));
				val.InvokeRPC(uid, text, new object[1] { false });
				return false;
			}
		}

		private sealed class Request
		{
			internal Container Chest;

			internal int Token;

			internal long Owner;

			internal uint Revision;

			internal float NextRetry;

			internal ChestAccessStatus Status;
		}

		private sealed class Operation
		{
			internal Player Player;

			internal float Radius;

			internal float Deadline;

			internal Action<List<Container>, HashSet<Container>> Complete;

			internal readonly List<Request> Requests = new List<Request>();
		}

		private const string RequestRpc = "ccorp_RequestChestAccess";

		private const string ResponseRpc = "ccorp_ChestAccessResponse";

		private const string LeaseOwner = "ccorp.chest.leaseOwner";

		private const string LeaseToken = "ccorp.chest.leaseToken";

		private const string LeaseExpiry = "ccorp.chest.leaseExpiry";

		private const float Timeout = 4f;

		private const double LeaseSeconds = 8.0;

		private static readonly FieldRef<Container, ZNetView> View = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

		private static readonly Func<Container, bool> Load = AccessTools.MethodDelegate<Func<Container, bool>>(AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<List<PrivateArea>> Wards = AccessTools.StaticFieldRefAccess<List<PrivateArea>>(AccessTools.Field(typeof(PrivateArea), "m_allAreas"));

		private static readonly Func<PrivateArea, bool> WardEnabled = AccessTools.MethodDelegate<Func<PrivateArea, bool>>(AccessTools.Method(typeof(PrivateArea), "IsEnabled", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<PrivateArea, Vector3, float, bool> WardInside = AccessTools.MethodDelegate<Func<PrivateArea, Vector3, float, bool>>(AccessTools.Method(typeof(PrivateArea), "IsInside", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<PrivateArea, long, bool> WardPermitted = AccessTools.MethodDelegate<Func<PrivateArea, long, bool>>(AccessTools.Method(typeof(PrivateArea), "IsPermitted", (Type[])null, (Type[])null), (object)null, true);

		private static Operation _operation;

		private static int _nextToken;

		internal static List<Container> PreparedChests { get; private set; }

		internal static bool Busy
		{
			get
			{
				if (_operation == null)
				{
					return PreparedChests != null;
				}
				return true;
			}
		}

		internal static bool IsInUse(Container chest)
		{
			if ((Object)(object)chest == (Object)null)
			{
				return false;
			}
			ZNetView val = View.Invoke(chest);
			bool localInUse = chest.IsInUse();
			bool remoteOwner = (Object)(object)val != (Object)null && val.IsValid() && !val.IsOwner();
			int replicatedInUse;
			if (val == null)
			{
				replicatedInUse = 0;
			}
			else
			{
				ZDO zDO = val.GetZDO();
				replicatedInUse = ((((zDO != null) ? new int?(zDO.GetInt(ZDOVars.s_inUse, 0)) : ((int?)null)) == 1) ? 1 : 0);
			}
			return ChestTransferRules.InUse(localInUse, remoteOwner, (byte)replicatedInUse != 0);
		}

		internal static bool CanMutate(Container chest)
		{
			if ((Object)(object)chest == (Object)null || IsInUse(chest))
			{
				return false;
			}
			ZNetView val = View.Invoke(chest);
			if ((Object)(object)val != (Object)null && val.IsValid() && val.IsOwner())
			{
				return !ReservedForAnother(val.GetZDO(), ZNet.GetUID());
			}
			return false;
		}

		private static long NowTicks()
		{
			return ZNet.instance.GetTime().Ticks;
		}

		private static bool ReservedForAnother(ZDO zdo, long requester)
		{
			return ChestTransferRules.ReservedForAnother(zdo.GetLong("ccorp.chest.leaseOwner", 0L), zdo.GetLong("ccorp.chest.leaseExpiry", 0L), requester, NowTicks());
		}

		private static void Reserve(ZDO zdo, long requester, int token)
		{
			zdo.Set("ccorp.chest.leaseOwner", requester);
			zdo.Set("ccorp.chest.leaseToken", token);
			zdo.Set("ccorp.chest.leaseExpiry", NowTicks() + 80000000);
		}

		internal static bool Begin(Player player, IEnumerable<Container> chests, float radius, Action<List<Container>, HashSet<Container>> complete)
		{
			if (Busy || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			Operation operation = (_operation = new Operation
			{
				Player = player,
				Radius = radius,
				Complete = complete,
				Deadline = Time.realtimeSinceStartup + 4f
			});
			foreach (Container item in chests.Distinct().ToList())
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				Request request = new Request
				{
					Chest = item,
					Token = ++_nextToken
				};
				operation.Requests.Add(request);
				ZNetView val = View.Invoke(item);
				if ((Object)(object)val == (Object)null || !val.IsValid() || !QuickStack.CanAccessChest(item, player, radius))
				{
					request.Status = ChestAccessStatus.Unavailable;
				}
				else if (IsInUse(item))
				{
					request.Status = ChestAccessStatus.InUse;
				}
				else if (val.IsOwner())
				{
					if (ReservedForAnother(val.GetZDO(), ZNet.GetUID()))
					{
						request.Status = ChestAccessStatus.InUse;
						continue;
					}
					Reserve(val.GetZDO(), ZNet.GetUID(), request.Token);
					Load(item);
					request.Status = ChestAccessStatus.Granted;
				}
				else
				{
					SendRequest(operation, request);
				}
			}
			Update();
			return true;
		}

		private static void SendRequest(Operation operation, Request request)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			ZNetView val = View.Invoke(request.Chest);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				request.Status = ChestAccessStatus.Unavailable;
				return;
			}
			request.Owner = val.GetZDO().GetOwner();
			if (request.Owner == 0L)
			{
				request.Status = ChestAccessStatus.Unavailable;
				return;
			}
			request.NextRetry = Time.realtimeSinceStartup + 0.75f;
			ZPackage val2 = new ZPackage();
			val2.Write(request.Token);
			val2.Write(((Character)operation.Player).GetZDOID());
			val2.Write(operation.Player.GetPlayerID());
			val2.Write(operation.Radius);
			val.InvokeRPC(request.Owner, "ccorp_RequestChestAccess", new object[1] { val2 });
		}

		private static void ReceiveRequest(Container chest, long sender, ZPackage package)
		{
			//IL_002f: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Expected O, but got Unknown
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			ZNetView val = View.Invoke(chest);
			if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner())
			{
				int num = package.ReadInt();
				ZDOID val2 = package.ReadZDOID();
				long num2 = package.ReadLong();
				float num3 = package.ReadSingle();
				ZDO zDO = val.GetZDO();
				ChestAccessStatus chestAccessStatus = ChestAccessStatus.Unavailable;
				ZNetPeer val3 = (ZNet.instance.IsServer() ? ZNet.instance.GetPeer(sender) : null);
				ZDOID val4 = val3?.m_characterID ?? val2;
				ZDO zDO2 = ZDOMan.instance.GetZDO(val4);
				long num4 = val3?.m_playerID ?? num2;
				bool flag = ((!ZNet.instance.IsServer()) ? (zDO2 != null && zDO2.GetOwner() == sender && zDO2.GetLong(ZDOVars.s_playerID, 0L) == num4) : (val3 != null && zDO2 != null && num4 != 0));
				if (zDO2 != null && flag && !float.IsNaN(num3) && num3 >= 1f && num3 <= 100f && QuickStack.IsChest(chest) && Vector3.Distance(zDO2.GetPosition(), ((Component)chest).transform.position) <= num3 && QuickStack.HasContainerAccess(chest, num4) && HasWardAccess(((Component)chest).transform.position, num4))
				{
					chestAccessStatus = ((chest.IsInUse() || ReservedForAnother(zDO, sender)) ? ChestAccessStatus.InUse : ChestAccessStatus.Granted);
				}
				if (chestAccessStatus == ChestAccessStatus.Unavailable)
				{
					Plugin.Log.LogWarning((object)$"Chest access rejected for {((Object)chest).name}: sender={sender}, peerFound={val3 != null}, characterFound={zDO2 != null}, authenticated={flag}, claimedCharacterMatches={((ZDOID)(ref val2)).Equals(val4)}, claimedPlayerMatches={num2 == num4}, radius={num3:0.#}, distance={((zDO2 == null) ? (-1f) : Vector3.Distance(zDO2.GetPosition(), ((Component)chest).transform.position)):0.#}, containerAccess={QuickStack.HasContainerAccess(chest, num4)}, wardAccess={HasWardAccess(((Component)chest).transform.position, num4)}.");
				}
				if (chestAccessStatus == ChestAccessStatus.Granted)
				{
					Reserve(zDO, sender, num);
					ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid);
					zDO.SetOwner(sender);
				}
				ZPackage val5 = new ZPackage();
				val5.Write(num);
				val5.Write((int)chestAccessStatus);
				val5.Write(zDO.DataRevision);
				val.InvokeRPC(sender, "ccorp_ChestAccessResponse", new object[1] { val5 });
			}
		}

		private static bool HasWardAccess(Vector3 position, long playerId)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			foreach (PrivateArea item in Wards.Invoke())
			{
				if ((Object)(object)item == (Object)null || !WardEnabled(item) || !WardInside(item, position, 0f))
				{
					continue;
				}
				flag = true;
				if (!WardPermitted(item, playerId))
				{
					Piece component = ((Component)item).GetComponent<Piece>();
					if (component == null || component.GetCreator() != playerId)
					{
						continue;
					}
				}
				return true;
			}
			return !flag;
		}

		private static void ReceiveResponse(Container chest, long sender, ZPackage package)
		{
			Operation operation = _operation;
			if (operation == null)
			{
				return;
			}
			int token = package.ReadInt();
			Request request = operation.Requests.Find((Request r) => (Object)(object)r.Chest == (Object)(object)chest && r.Token == token && r.Owner == sender);
			if (request != null && request.Status == ChestAccessStatus.Waiting)
			{
				ChestAccessStatus chestAccessStatus = (ChestAccessStatus)package.ReadInt();
				request.Revision = package.ReadUInt();
				request.Status = chestAccessStatus switch
				{
					ChestAccessStatus.InUse => chestAccessStatus, 
					ChestAccessStatus.Granted => ChestAccessStatus.Synchronizing, 
					_ => ChestAccessStatus.Unavailable, 
				};
				if (request.Status == ChestAccessStatus.Unavailable)
				{
					Plugin.Log.LogWarning((object)$"Chest access denied by owner for {((Object)chest).name} (owner={sender}).");
				}
			}
		}

		internal static void Update()
		{
			Operation operation = _operation;
			if (operation == null)
			{
				return;
			}
			if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)operation.Player == (Object)null || (Object)(object)operation.Player != (Object)(object)Player.m_localPlayer || ((Character)operation.Player).IsDead() || ((Character)operation.Player).IsTeleporting())
			{
				Reset();
				return;
			}
			foreach (Request request in operation.Requests)
			{
				if (request.Status != ChestAccessStatus.Waiting && request.Status != ChestAccessStatus.Synchronizing)
				{
					continue;
				}
				if ((Object)(object)request.Chest == (Object)null)
				{
					request.Status = ChestAccessStatus.Unavailable;
					continue;
				}
				ZNetView val = View.Invoke(request.Chest);
				if ((Object)(object)val == (Object)null || !val.IsValid())
				{
					request.Status = ChestAccessStatus.Unavailable;
					continue;
				}
				ZDO zDO = val.GetZDO();
				if (request.Status == ChestAccessStatus.Synchronizing && val.IsOwner() && zDO.DataRevision >= request.Revision && zDO.GetInt("ccorp.chest.leaseToken", 0) == request.Token && zDO.GetLong("ccorp.chest.leaseOwner", 0L) == ZNet.GetUID())
				{
					Load(request.Chest);
					request.Status = (CanMutate(request.Chest) ? ChestAccessStatus.Granted : ChestAccessStatus.InUse);
				}
				else if (Time.realtimeSinceStartup >= operation.Deadline)
				{
					request.Status = ChestAccessStatus.Unavailable;
					Plugin.Log.LogWarning((object)string.Format("Chest access timed out for {0} (owner={1}, phase={2}).", ((Object)request.Chest).name, request.Owner, (request.Revision == 0) ? "request" : "synchronization"));
				}
				else if (request.Status == ChestAccessStatus.Waiting && Time.realtimeSinceStartup >= request.NextRetry)
				{
					SendRequest(operation, request);
				}
			}
			if (operation.Requests.Any((Request r) => r.Status == ChestAccessStatus.Waiting || r.Status == ChestAccessStatus.Synchronizing))
			{
				return;
			}
			List<Container> list = (from r in operation.Requests
				where r.Status == ChestAccessStatus.Granted && CanMutate(r.Chest) && QuickStack.CanAccessChest(r.Chest, operation.Player, operation.Radius)
				select r.Chest).ToList();
			HashSet<Container> arg = new HashSet<Container>(from r in operation.Requests
				where r.Status == ChestAccessStatus.InUse
				select r.Chest);
			PreparedChests = list;
			try
			{
				operation.Complete(list, arg);
			}
			catch (Exception ex)
			{
				Logger.CreateLogSource("ccorp").LogError((object)("Chest transfer failed: " + ex));
			}
			finally
			{
				PreparedChests = null;
				Release(operation);
				_operation = null;
			}
		}

		private static void Release(Operation operation)
		{
			foreach (Request request in operation.Requests)
			{
				if ((Object)(object)request.Chest == (Object)null)
				{
					continue;
				}
				ZNetView val = View.Invoke(request.Chest);
				if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner())
				{
					ZDO zDO = val.GetZDO();
					if (zDO.GetLong("ccorp.chest.leaseOwner", 0L) == ZNet.GetUID() && zDO.GetInt("ccorp.chest.leaseToken", 0) == request.Token)
					{
						zDO.Set("ccorp.chest.leaseOwner", 0L);
						zDO.Set("ccorp.chest.leaseExpiry", 0L);
					}
				}
			}
		}

		internal static void Reset()
		{
			if (_operation != null && (Object)(object)ZNet.instance != (Object)null)
			{
				Release(_operation);
			}
			_operation = null;
			PreparedChests = null;
		}
	}
	internal enum ChestAccessStatus
	{
		Waiting,
		Synchronizing,
		Granted,
		InUse,
		Unavailable
	}
	internal static class ChestTransferRules
	{
		internal static bool InUse(bool localInUse, bool remoteOwner, bool replicatedInUse)
		{
			if (!localInUse)
			{
				return remoteOwner && replicatedInUse;
			}
			return true;
		}

		internal static bool ReservedForAnother(long holder, long expiry, long requester, long now)
		{
			if (holder != 0L && holder != requester)
			{
				return expiry > now;
			}
			return false;
		}

		internal static string PullMessage(string itemName, int moved, int requested, bool blocked)
		{
			if (blocked && moved < requested)
			{
				if (moved <= 0)
				{
					return "Chest in use.";
				}
				return $"Collected {moved}/{requested} {itemName}. Chest in use.";
			}
			if (moved <= 0)
			{
				return "No available ingredients or inventory space.";
			}
			return $"Collected {moved}/{requested} {itemName} from nearby chests.";
		}
	}
	internal sealed class ConnectedPlotSearch
	{
		internal readonly struct Cell : IEquatable<Cell>
		{
			internal readonly int X;

			internal readonly int Z;

			internal Cell(int x, int z)
			{
				X = x;
				Z = z;
			}

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

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

			public override int GetHashCode()
			{
				return (X * 397) ^ Z;
			}
		}

		private const int MaxVisitedCells = 100000;

		private readonly Queue<Cell> _pending = new Queue<Cell>();

		private readonly HashSet<Cell> _visited = new HashSet<Cell>();

		private readonly float _radiusSquared;

		private readonly int _stride;

		internal readonly float Step;

		internal bool Truncated { get; private set; }

		internal bool Complete => _pending.Count == 0;

		internal ConnectedPlotSearch(float radius, float spacing)
		{
			if (radius <= 0f || spacing <= 0f || float.IsNaN(radius) || float.IsNaN(spacing) || float.IsInfinity(radius) || float.IsInfinity(spacing))
			{
				throw new ArgumentOutOfRangeException("radius");
			}
			spacing = Math.Max(0.75f, spacing);
			_stride = (int)Math.Ceiling(spacing / 0.5f);
			Step = spacing / (float)_stride;
			_radiusSquared = radius * radius;
			Enqueue(new Cell(0, 0));
		}

		private void Enqueue(Cell cell)
		{
			float num = (float)cell.X * Step;
			float num2 = (float)cell.Z * Step;
			if (!(num * num + num2 * num2 > _radiusSquared) && !_visited.Contains(cell))
			{
				if (_visited.Count >= 100000)
				{
					Truncated = true;
					return;
				}
				_visited.Add(cell);
				_pending.Enqueue(cell);
			}
		}

		internal void Advance(int checks, Func<Cell, bool> isCultivated, Queue<Cell> candidates)
		{
			for (int i = 0; i < checks; i++)
			{
				if (_pending.Count <= 0)
				{
					break;
				}
				Cell cell = _pending.Dequeue();
				if (isCultivated(cell))
				{
					if ((cell.X != 0 || cell.Z != 0) && cell.X % _stride == 0 && cell.Z % _stride == 0)
					{
						candidates.Enqueue(cell);
					}
					Enqueue(new Cell(cell.X + 1, cell.Z));
					Enqueue(new Cell(cell.X - 1, cell.Z));
					Enqueue(new Cell(cell.X, cell.Z + 1));
					Enqueue(new Cell(cell.X, cell.Z - 1));
				}
			}
		}
	}
	internal static class CraftFromContainers
	{
		private sealed class PendingBuild
		{
			internal Player Player;

			internal Piece Piece;

			internal GameObject Ghost;

			internal Vector3 Position;

			internal Quaternion Rotation;

			internal Dictionary<string, int> Costs;

			internal float Deadline;
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static class AuthorizeBuildPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(Player __instance, bool takeInput)
			{
				//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
				//IL_0106: Unknown result type (might be due to invalid IL or missing references)
				//IL_010b: Unknown result type (might be due to invalid IL or missing references)
				if (_replayingBuild || !Enabled.Value || ShiftAutoPlant.InventoryOnly || !takeInput || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (!ZInput.GetButtonDown("Attack") && !ZInput.GetButtonDown("JoyPlace")))
				{
					return true;
				}
				Piece val = SelectedPiece(__instance);
				GameObject val2 = PlacementGhost.Invoke(__instance);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || __instance.NoCostCheat() || NoPlacementCost.Invoke(__instance))
				{
					return true;
				}
				Dictionary<string, int> dictionary = Costs(val.m_resources, 0, 1);
				if (dictionary.Count == 0 || CoversCosts(__instance, dictionary, Array.Empty<Container>()))
				{
					return true;
				}
				if (!ResourceChests(__instance, dictionary.Keys).Any())
				{
					return true;
				}
				if (_pendingBuild != null)
				{
					return false;
				}
				_pendingBuild = new PendingBuild
				{
					Player = __instance,
					Piece = val,
					Ghost = val2,
					Position = val2.transform.position,
					Rotation = val2.transform.rotation,
					Costs = dictionary,
					Deadline = Time.realtimeSinceStartup + 10f
				};
				if (!ChestAccess.Busy)
				{
					BeginPendingBuild();
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(ZInput), "GetButtonDown", new Type[] { typeof(string) })]
		private static class ReplayBuildInputPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(string name, ref bool __result)
			{
				if (!_forcePlaceButton || name != "Attack")
				{
					return true;
				}
				_forcePlaceButton = false;
				__result = true;
				return false;
			}
		}

		[HarmonyPatch(typeof(BuildUi), "OnSelectPiece")]
		private static class BuildingResourcePullPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(Piece piece)
			{
				if (!CtrlClickPull.Value || !IsResourcePullModifierHeld() || (Object)(object)piece == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
				{
					return true;
				}
				Dictionary<string, int> dictionary = new Dictionary<string, int>();
				Requirement[] resources = piece.m_resources;
				foreach (Requirement val in resources)
				{
					string text = val?.m_resItem?.m_itemData?.m_shared?.m_name;
					if (!string.IsNullOrEmpty(text))
					{
						int amount = val.GetAmount(0);
						if (amount > 0)
						{
							dictionary.TryGetValue(text, out var value);
							dictionary[text] = value + amount;
						}
					}
				}
				PullResources(Player.m_localPlayer, dictionary);
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
		private static class RequirementDisplayPatch
		{
			private static readonly HashSet<int> AdjustedTextInstances = new HashSet<int>();

			[HarmonyPostfix]
			private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier, bool __result)
			{
				//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f3: 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_0215: Unknown result type (might be due to invalid IL or missing references)
				//IL_021a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0227: Unknown result type (might be due to invalid IL or missing references)
				//IL_0236: Unknown result type (might be due to invalid IL or missing references)
				//IL_023b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0270: Unknown result type (might be due to invalid IL or missing references)
				//IL_0284: Unknown result type (might be due to invalid IL or missing references)
				//IL_02af: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)elementRoot != (Object)null)
				{
					RequirementResourcePull requirementResourcePull = ((Component)elementRoot).GetComponent<RequirementResourcePull>();
					if ((Object)(object)requirementResourcePull == (Object)null)
					{
						requirementResourcePull = ((Component)elementRoot).gameObject.AddComponent<RequirementResourcePull>();
					}
					requirementResourcePull.Player = player;
					requirementResourcePull.ItemName = ((!__result) ? null : req?.m_resItem?.m_itemData?.m_shared?.m_name);
					requirementResourcePull.RequiredAmount = ((req != null) ? (req.GetAmount(quality) * craftMultiplier) : 0);
					Transform obj = elementRoot.Find("res_icon");
					Graphic val = ((obj != null) ? ((Component)obj).GetComponent<Graphic>() : null);
					if ((Object)(object)val != (Object)null)
					{
						val.raycastTarget = true;
					}
				}
				if (!__result || (Object)(object)elementRoot == (Object)null || (Object)(object)req?.m_resItem == (Object)null)
				{
					return;
				}
				string itemName = req.m_resItem.m_itemData?.m_shared?.m_name;
				if (!TryGetDisplayedResourceCounts(player, itemName, out var inventoryCount, out var nearbyChestCount))
				{
					return;
				}
				Transform val2 = elementRoot.Find("res_amount");
				TMP_Text val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<TMP_Text>() : null);
				if (!((Object)(object)val3 == (Object)null))
				{
					int num = req.GetAmount(quality) * craftMultiplier;
					val3.text = $"{inventoryCount} / {num}\n<size=85%>({nearbyChestCount})</size>";
					if (AdjustedTextInstances.Add(((Object)val3).GetInstanceID()))
					{
						float num2 = (val3.fontSize *= 0.85f);
						val3.enableAutoSizing = true;
						val3.fontSizeMax = num2;
						val3.fontSizeMin = Mathf.Max(8f, num2 * 0.65f);
						RectTransform rectTransform = val3.rectTransform;
						Rect rect = rectTransform.rect;
						float height = ((Rect)(ref rect)).height;
						float num4 = Mathf.Max(height, num2 * 2.8f);
						rectTransform.SetSizeWithCurrentAnchors((Axis)1, num4);
						rectTransform.anchoredPosition -= new Vector2(0f, (num4 - height) * (1f - rectTransform.pivot.y));
						rectTransform.anchoredPosition += new Vector2(0f, 2f);
					}
					val3.richText = true;
					val3.textWrappingMode = (TextWrappingModes)0;
					val3.overflowMode = (TextOverflowModes)0;
					val3.alignment = (TextAlignmentOptions)258;
					if (inventoryCount >= num)
					{
						((Graphic)val3).color = Color.white;
					}
					else if (inventoryCount + nearbyChestCount >= num)
					{
						((Graphic)val3).color = Color.yellow;
					}
					else
					{
						((Graphic)val3).color = ((Mathf.Sin(Time.time * 10f) > 0f) ? Color.red : Color.white);
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
		private static class AuthorizeCraftPatch
		{
			private static readonly FieldRef<InventoryGui, Recipe> Recipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe");

			private static readonly FieldRef<InventoryGui, ItemData> Upgrade = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem");

			private static readonly FieldRef<InventoryGui, int> Variant = AccessTools.FieldRefAccess<InventoryGui, int>("m_craftVariant");

			private static readonly FieldRef<InventoryGui, int> Amount = AccessTools.FieldRefAccess<InventoryGui, int>("m_multiCraftAmount");

			private static readonly FieldRef<InventoryGui, bool> Multiple = AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting");

			private static readonly Action<InventoryGui, Player> Craft = AccessTools.MethodDelegate<Action<InventoryGui, Player>>(AccessTools.Method(typeof(InventoryGui), "DoCrafting", (Type[])null, (Type[])null), (object)null, true);

			[HarmonyPrefix]
			private static bool Prefix(InventoryGui __instance, Player player)
			{
				if (!Enabled.Value || ShiftAutoPlant.InventoryOnly || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)player == (Object)null || player.NoCostCheat() || ChestAccess.PreparedChests != null)
				{
					return true;
				}
				Recipe recipe = Recipe.Invoke(__instance);
				if ((Object)(object)recipe == (Object)null)
				{
					return true;
				}
				ItemData upgrade = Upgrade.Invoke(__instance);
				int upgradeQuality = upgrade?.m_quality ?? 0;
				int quality = upgradeQuality + 1;
				int variant = Variant.Invoke(__instance);
				int amount = Amount.Invoke(__instance);
				bool multiple = Multiple.Invoke(__instance);
				Dictionary<string, int> dictionary = Costs(recipe.m_resources, quality, (!multiple) ? 1 : amount);
				if (CoversCosts(player, dictionary, Array.Empty<Container>()))
				{
					return true;
				}
				if (ChestAccess.Busy)
				{
					((Character)player).Message((MessageType)2, "Chest transfer in progress.", 0, (Sprite)null, false);
					return false;
				}
				int generation = _craftGeneration;
				CraftingStation station = player.GetCurrentCraftingStation();
				ChestAccess.Begin(player, ResourceChests(player, dictionary.Keys), Radius.Value, delegate(List<Container> available, HashSet<Container> blocked)
				{
					if (!((Object)(object)__instance == (Object)null) && InventoryGui.IsVisible() && generation == _craftGeneration && !((Object)(object)Recipe.Invoke(__instance) != (Object)(object)recipe) && Upgrade.Invoke(__instance) == upgrade && (upgrade?.m_quality ?? 0) == upgradeQuality && Variant.Invoke(__instance) == variant && Amount.Invoke(__instance) == amount && Multiple.Invoke(__instance) == multiple && !((Object)(object)player.GetCurrentCraftingStation() != (Object)(object)station))
					{
						_cacheExpiresAt = 0f;
						if (blocked.Count > 0 && !player.HaveRequirements(recipe, false, quality, (!multiple) ? 1 : amount))
						{
							((Character)player).Message((MessageType)2, "Chest in use.", 0, (Sprite)null, false);
						}
						Craft(__instance, player);
					}
				});
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnCraftCancelPressed")]
		private static class CraftCancelPatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				_craftGeneration++;
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
		private static class RecipeRequirementPatch
		{
			[HarmonyPrefix]
			private static void Prefix(Player __instance, bool discover, out ResourceContext __state)
			{
				__state = _requirementContext;
				if (!discover)
				{
					_requirementContext = CreateContext(__instance);
				}
			}

			[HarmonyPostfix]
			private static void Postfix(ResourceContext __state)
			{
				_requirementContext = __state;
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Piece),
			typeof(RequirementMode)
		})]
		private static class BuildingRequirementPatch
		{
			[HarmonyPrefix]
			private static void Prefix(Player __instance, Piece piece, RequirementMode mode, out ResourceContext __state)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Invalid comparison between Unknown and I4
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				__state = _requirementContext;
				if ((int)mode != 1)
				{
					_requirementContext = CreateContext(__instance);
				}
				if ((int)mode != 0 || _requirementContext == null)
				{
					return;
				}
				List<Container> list = _requirementContext.Containers.Where(ChestAccess.CanMutate).ToList();
				Dictionary<string, int> dictionary = Costs(piece.m_resources, 0, 1);
				if (_pendingBuild == null && !ChestAccess.Busy && Time.realtimeSinceStartup >= _nextBuildAccess && (Object)(object)SelectedPiece(__instance) == (Object)(object)piece && !CoversCosts(__instance, dictionary, list))
				{
					_nextBuildAccess = Time.realtimeSinceStartup + 1f;
					ChestAccess.Begin(__instance, ResourceChests(__instance, dictionary.Keys), Radius.Value, delegate
					{
						_cacheExpiresAt = 0f;
					});
				}
				_requirementContext = new ResourceContext(__instance, list);
			}

			[HarmonyPostfix]
			private static void Postfix(ResourceContext __state)
			{
				_requirementContext = __state;
			}
		}

		[HarmonyPatch(typeof(Inventory), "CountItems")]
		private static class CountNearbyResourcesPatch
		{
			[HarmonyPostfix]
			private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
			{
				if (!ShiftAutoPlant.InventoryOnly && _requirementContext != null && __instance == ((Humanoid)_requirementContext.Player).GetInventory())
				{
					__result += CountInNearbyChests(name, quality, matchWorldLevel);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "HaveItem", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		private static class HaveNearbyResourcePatch
		{
			[HarmonyPostfix]
			private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result)
			{
				if (!ShiftAutoPlant.InventoryOnly && !__result && _requirementContext != null && __instance == ((Humanoid)_requirementContext.Player).GetInventory())
				{
					__result = CountInNearbyChests(name, -1, matchWorldLevel) > 0;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeResources")]
		private static class ConsumeNearbyResourcesPatch
		{
			[HarmonyPrefix]
			private static void Prefix(Player __instance, out ResourceContext __state)
			{
				__state = _consumptionContext;
				ResourceContext resourceContext = CreateContext(__instance);
				_consumptionContext = ((resourceContext == null) ? null : new ResourceContext(__instance, resourceContext.Containers.Where(ChestAccess.CanMutate).ToList()));
			}

			[HarmonyPostfix]
			private static void Postfix(ResourceContext __state)
			{
				_consumptionContext = __state;
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		private static class ConsumeFromNearbyChestsPatch
		{
			[HarmonyPrefix]
			private static void Prefix(Inventory __instance, string name, int amount, int itemQuality, bool worldLevelBased, out int __state)
			{
				__state = 0;
				if (!ShiftAutoPlant.InventoryOnly && _consumptionContext != null && __instance == ((Humanoid)_consumptionContext.Player).GetInventory())
				{
					int num = __instance.CountItems(name, itemQuality, worldLevelBased);
					__state = Mathf.Max(0, amount - num);
				}
			}

			[HarmonyPostfix]
			private static void Postfix(string name, int itemQuality, bool worldLevelBased, int __state)
			{
				if (_consumptionContext == null || __state <= 0)
				{
					return;
				}
				int num = __state;
				foreach (Container container in _consumptionContext.Containers)
				{
					Inventory inventory = container.GetInventory();
					if (inventory == null)
					{
						continue;
					}
					int num2 = Mathf.Min(inventory.CountItems(name, itemQuality, worldLevelBased), num);
					if (num2 > 0 && ChestAccess.CanMutate(container) && QuickStack.CanAccessChest(container, _consumptionContext.Player, Radius.Value))
					{
						inventory.RemoveItem(name, num2, itemQuality, worldLevelBased);
						num -= num2;
						if (num <= 0)
						{
							break;
						}
					}
				}
			}
		}

		private sealed class ResourceContext
		{
			internal readonly Player Player;

			internal readonly List<Container> Containers;

			internal ResourceContext(Player player, List<Container> containers)
			{
				Player = player;
				Containers = containers;
			}
		}

		private static ConfigEntry<bool> Enabled;

		private static ConfigEntry<float> Radius;

		private static ConfigEntry<bool> CtrlClickPull;

		private static ResourceContext _requirementContext;

		private static ResourceContext _consumptionContext;

		private static Player _cachedPlayer;

		private static Vector3 _cachedPosition;

		private static float _cachedRadius;

		private static float _cacheExpiresAt;

		private static List<Container> _cachedContainers = new List<Container>();

		private static float _nextBuildAccess;

		private static int _craftGeneration;

		private static PendingBuild _pendingBuild;

		private static bool _replayingBuild;

		private static bool _forcePlaceButton;

		private static readonly Func<Player, Piece> SelectedPiece = AccessTools.MethodDelegate<Func<Player, Piece>>(AccessTools.Method(typeof(Player), "GetSelectedPiece", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<Player, bool, float> UpdatePlacement = AccessTools.MethodDelegate<Action<Player, bool, float>>(AccessTools.Method(typeof(Player), "UpdatePlacement", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<Player, GameObject> PlacementGhost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static readonly FieldRef<Player, bool> NoPlacementCost = AccessTools.FieldRefAccess<Player, bool>("m_noPlacementCost");

		internal static void Reset()
		{
			_requirementContext = null;
			_consumptionContext = null;
			_cachedPlayer = null;
			_cachedContainers.Clear();
			_cacheExpiresAt = (_nextBuildAccess = 0f);
			_craftGeneration++;
			_pendingBuild = null;
			_replayingBuild = (_forcePlaceButton = false);
		}

		internal static void Update()
		{
			if (_pendingBuild != null && !ChestAccess.Busy)
			{
				BeginPendingBuild();
			}
		}

		private static bool BuildTargetUnchanged(PendingBuild pending)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if (pending == null || (Object)(object)pending.Player == (Object)null || (Object)(object)pending.Player != (Object)(object)Player.m_localPlayer || ((Character)pending.Player).IsDead() || ((Character)pending.Player).IsTeleporting() || (Object)(object)SelectedPiece(pending.Player) != (Object)(object)pending.Piece || Time.realtimeSinceStartup > pending.Deadline)
			{
				return false;
			}
			GameObject val = PlacementGhost.Invoke(pending.Player);
			if ((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)pending.Ghost && Vector3.Distance(val.transform.position, pending.Position) < 0.2f)
			{
				return Quaternion.Angle(val.transform.rotation, pending.Rotation) < 2f;
			}
			return false;
		}

		private static void BeginPendingBuild()
		{
			PendingBuild pending = _pendingBuild;
			if (!BuildTargetUnchanged(pending))
			{
				_pendingBuild = null;
			}
			else if (!ChestAccess.Begin(pending.Player, ResourceChests(pending.Player, pending.Costs.Keys), Radius.Value, delegate(List<Container> available, HashSet<Container> blocked)
			{
				if (_pendingBuild == pending)
				{
					_pendingBuild = null;
					_cacheExpiresAt = 0f;
					if (BuildTargetUnchanged(pending))
					{
						if (CoversCosts(pending.Player, pending.Costs, available))
						{
							_replayingBuild = (_forcePlaceButton = true);
							try
							{
								UpdatePlacement(pending.Player, arg2: true, Time.deltaTime);
								return;
							}
							finally
							{
								_replayingBuild = (_forcePlaceButton = false);
							}
						}
						Plugin.Log.LogWarning((object)string.Format("Build chest stock unavailable: piece={0}, authorized={1}, inUse={2}, requirements={3}.", ((Object)pending.Piece).name, available.Count, blocked.Count, string.Join(", ", pending.Costs.Select((KeyValuePair<string, int> cost) => $"{cost.Key}:{cost.Value}"))));
						((Character)pending.Player).Message((MessageType)2, (blocked.Count > 0) ? "Chest in use." : "Nearby chest resources are unavailable.", 0, (Sprite)null, false);
					}
				}
			}))
			{
				_pendingBuild = null;
			}
		}

		private static Dictionary<string, int> Costs(Requirement[] requirements, int quality, int multiplier)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (Requirement val in requirements)
			{
				string text = val?.m_resItem?.m_itemData?.m_shared?.m_name;
				if (!string.IsNullOrEmpty(text))
				{
					int num = val.GetAmount(quality) * multiplier;
					if (num > 0)
					{
						dictionary.TryGetValue(text, out var value);
						dictionary[text] = value + num;
					}
				}
			}
			return dictionary;
		}

		private static bool CoversCosts(Player player, Dictionary<string, int> costs, IEnumerable<Container> chests)
		{
			ResourceContext requirementContext = _requirementContext;
			_requirementContext = null;
			try
			{
				return costs.All((KeyValuePair<string, int> cost) => ((Humanoid)player).GetInventory().CountItems(cost.Key, -1, true) + chests.Where((Container chest) => ChestAccess.CanMutate(chest) && QuickStack.CanAccessChest(chest, player, Radius.Value)).Sum((Container chest) => chest.GetInventory().CountItems(cost.Key, -1, true)) >= cost.Value);
			}
			finally
			{
				_requirementContext = requirementContext;
			}
		}

		internal static void Initialize(ConfigFile config)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			ConfigEntry<bool> val = config.Bind<bool>("Crafting", "ShiftClickPullResources", true, (ConfigDescription)null);
			CtrlClickPull = config.Bind<bool>("Crafting", "CtrlClickPullResources", val.Value, "Ctrl + clique esquerdo no ingrediente da bancada traz a quantidade completa do custo exibido, independente do estoque no inventário. No menu de construção, Ctrl + clique na peça traz todos os ingredientes para construir uma unidade, independente do estoque no inventário. Se houver menos, traz o disponível. Respeita NearbyChestRadius, acesso, baús em uso e espaço. Não produz/constrói automaticamente. Sincronizado e bloqueado pelo servidor.");
			ConfigRemoveLegacyPull(config, val);
			Enabled = config.Bind<bool>("Crafting", "UseNearbyChestResources", true, "Permite construir, fabricar e melhorar itens usando recursos de baús próximos depois dos recursos do inventário.");
			Radius = config.Bind<float>("Crafting", "NearbyChestRadius", 25f, new ConfigDescription("Raio em metros usado para localizar baús cujos recursos podem ser usados na construção e em todas as estações.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
		}

		private static void ConfigRemoveLegacyPull(ConfigFile config, ConfigEntry<bool> oldPull)
		{
			config.Remove(((ConfigEntryBase)oldPull).Definition);
			config.Save();
		}

		internal static bool IsResourcePullModifierHeld()
		{
			if (!Input.GetKey((KeyCode)306))
			{
				return Input.GetKey((KeyCode)305);
			}
			return true;
		}

		private static ResourceContext CreateContext(Player player)
		{
			if (!Enabled.Value || ShiftAutoPlant.InventoryOnly || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return null;
			}
			return new ResourceContext(player, GetNearbyContainers(player));
		}

		internal static void PullResources(Player player, string itemName, int requiredAmount)
		{
			PullResources(player, new Dictionary<string, int> { [itemName] = requiredAmount });
		}

		private static bool CanPull(Player player)
		{
			if (CtrlClickPull.Value && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !Console.IsVisible() && !Menu.IsVisible() && !TextInput.IsVisible())
			{
				if (!((Object)(object)Chat.instance == (Object)null))
				{
					return !Chat.instance.HasFocus();
				}
				return true;
			}
			return false;
		}

		private static IEnumerable<Container> ResourceChests(Player player, IEnumerable<string> names)
		{
			HashSet<string> requestedNames = new HashSet<string>(names);
			return from chest in QuickStack.FindEligibleChests(player, Radius.Value, includeInUse: true)
				where chest.GetInventory() != null && chest.GetInventory().GetAllItems().Any((ItemData item) => item != null && item.m_worldLevel >= Game.m_worldLevel && requestedNames.Contains(item.m_shared.m_name))
				orderby Vector3.Distance(((Component)player).transform.position, ((Component)chest).transform.position)
				select chest;
		}

		private static void PullResources(Player player, Dictionary<string, int> costs)
		{
			if (!CanPull(player) || ChestAccess.Busy)
			{
				return;
			}
			Dictionary<string, int> requested = costs.Where((KeyValuePair<string, int> cost) => !string.IsNullOrEmpty(cost.Key) && cost.Value > 0).ToDictionary((KeyValuePair<string, int> cost) => cost.Key, (KeyValuePair<string, int> cost) => ResourcePullTransfer.Requested(cost.Value));
			if (requested.Count == 0)
			{
				return;
			}
			ChestAccess.Begin(player, ResourceChests(player, requested.Keys), Radius.Value, delegate(List<Container> chests, HashSet<Container> blocked)
			{
				if (CanPull(player))
				{
					List<string> list = new List<string>();
					foreach (KeyValuePair<string, int> cost in requested)
					{
						int num = chests.Where((Container chest) => ChestAccess.CanMutate(chest) && QuickStack.CanAccessChest(chest, player, Radius.Value)).Sum((Container chest) => (from item in chest.GetInventory().GetAllItems()
							where item != null && item.m_shared.m_name == cost.Key && item.m_worldLevel >= Game.m_worldLevel
							select item).Sum((ItemData item) => item.m_stack));
						int num2 = TransferResources(player, cost.Key, cost.Value, chests);
						bool blocked2 = num2 < cost.Value && num < cost.Value && blocked.Any(delegate(Container chest)
						{
							if ((Object)(object)chest != (Object)null)
							{
								Inventory inventory = chest.GetInventory();
								if (inventory == null)
								{
									return false;
								}
								return inventory.GetAllItems().Any((ItemData item) => item != null && item.m_shared.m_name == cost.Key && item.m_worldLevel >= Game.m_worldLevel);
							}
							return false;
						});
						list.Add(ChestTransferRules.PullMessage(Localization.instance.Localize(cost.Key), num2, cost.Value, blocked2));
					}
					_cacheExpiresAt = 0f;
					((Character)player).Message((MessageType)2, string.Join("\n", list), 0, (Sprite)null, false);
				}
			});
		}

		private static int TransferResources(Player player, string itemName, int requiredAmount, IEnumerable<Container> chests)
		{
			Inventory destination = ((Humanoid)player).GetInventory();
			if (destination == null)
			{
				return 0;
			}
			ResourceContext requirementContext = _requirementContext;
			ResourceContext consumptionContext = _consumptionContext;
			_requirementContext = null;
			_consumptionContext = null;
			int num = 0;
			try
			{
				int num2 = requiredAmount;
				foreach (Container chest in chests)
				{
					if (!ChestAccess.CanMutate(chest) || !QuickStack.CanAccessChest(chest, player, Radius.Value))
					{
						continue;
					}
					Inventory source = chest.GetInventory();
					if (source == null || source == destination)
					{
						continue;
					}
					foreach (ItemData item in new List<ItemData>(source.GetAllItems()))
					{
						if (num2 <= 0)
						{
							break;
						}
						if (item != null && !(item.m_shared.m_name != itemName) && item.m_worldLevel >= Game.m_worldLevel && source.ContainsItem(item))
						{
							int num3 = ResourcePullTransfer.Move(item, Mathf.Min(num2, item.m_stack), delegate(ItemData original, int amount)
							{
								ItemData obj = original.Clone();
								obj.m_stack = amount;
								return obj;
							}, (ItemData original) => destination.CountItems(itemName, original.m_quality, true), delegate(ItemData copy)
							{
								destination.AddItem(copy);
							}, delegate(ItemData original, int amount)
							{
								source.RemoveItem(original, amount);
							});
							num2 -= num3;
							num += num3;
						}
					}
					if (num2 <= 0)
					{
						break;
					}
				}
				return num;
			}
			finally
			{
				_requirementContext = requirementContext;
				_consumptionContext = consumptionContext;
			}
		}

		private static List<Container> GetNearbyContainers(Player player)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (ChestAccess.PreparedChests != null)
			{
				return ChestAccess.PreparedChests;
			}
			float value = Radius.Value;
			Vector3 position = ((Component)player).transform.position;
			if ((Object)(object)_cachedPlayer == (Object)(object)player && Time.unscaledTime < _cacheExpiresAt && Mathf.Approximately(_cachedRadius, value) && Vector3.Distance(_cachedPosition, position) < 0.25f)
			{
				return _cachedContainers;
			}
			_cachedPlayer = player;
			_cachedPosition = position;
			_cachedRadius = value;
			_cacheExpiresAt = Time.unscaledTime + 0.25f;
			_cachedContainers = (from container in QuickStack.FindEligibleChests(player, value)
				orderby Vector3.Distance(position, ((Component)container).transform.position)
				select container).ToList();
			return _cachedContainers;
		}

		private static int CountInNearbyChests(string itemName, int quality, bool matchWorldLevel)
		{
			if (_requirementContext == null || string.IsNullOrEmpty(itemName))
			{
				return 0;
			}
			int num = 0;
			foreach (Container container in _requirementContext.Containers)
			{
				if (!((Object)(object)container == (Object)null) && !ChestAccess.IsInUse(container) && QuickStack.CanAccessChest(container, _requirementContext.Player, Radius.Value))
				{
					Inventory inventory = container.GetInventory();
					if (inventory != null)
					{
						num += inventory.CountItems(itemName, quality, matchWorldLevel);
					}
				}
			}
			return num;
		}

		private static bool TryGetDisplayedResourceCounts(Player player, string itemName, out int inventoryCount, out int nearbyChestCount)
		{
			inventoryCount = 0;
			nearbyChestCount = 0;
			if (!Enabled.Value || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || string.IsNullOrEmpty(itemName))
			{
				return false;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return false;
			}
			inventoryCount = inventory.CountItems(itemName, -1, true);
			foreach (Container nearbyContainer in GetNearbyContainers(player))
			{
				Inventory inventory2 = nearbyContainer.GetInventory();
				if (inventory2 != null)
				{
					nearbyChestCount += inventory2.CountItems(itemName, -1, true);
				}
			}
			return true;
		}
	}
	internal static class DynamicFlattenRadius
	{
		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static class PlacementScopePatch
		{
			[HarmonyPrefix]
			private static void Prefix(Player __instance, Piece piece, out PlacementState __state)
			{
				__state = null;
				if (Enabled != null && Enabled.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)piece == (Object)null) && !((Object)(object)piece != (Object)(object)_selectedPiece) && !(_currentRadius <= 0f))
				{
					__state = new PlacementState(piece);
					__state.Apply(_currentRadius);
				}
			}

			[HarmonyPostfix]
			private static void Postfix(PlacementState __state)
			{
				__state?.Restore();
			}

			[HarmonyFinalizer]
			private static void Finalizer(PlacementState __state)
			{
				__state?.Restore();
			}
		}

		private sealed class PlacementState
		{
			private readonly TerrainOp _terrainOp;

			private readonly TerrainModifier _modifier;

			private readonly float _levelRadius;

			private readonly float _raiseRadius;

			private readonly float _smoothRadius;

			private readonly float _paintRadius;

			private bool _restored;

			internal PlacementState(Piece piece)
			{
				_terrainOp = ((Component)piece).GetComponent<TerrainOp>();
				_modifier = ((Component)piece).GetComponent<TerrainModifier>();
				if ((Object)(object)_terrainOp != (Object)null && _terrainOp.m_settings != null)
				{
					_levelRadius = _terrainOp.m_settings.m_levelRadius;
					_raiseRadius = _terrainOp.m_settings.m_raiseRadius;
					_smoothRadius = _terrainOp.m_settings.m_smoothRadius;
					_paintRadius = _terrainOp.m_settings.m_paintRadius;
				}
				else if ((Object)(object)_modifier != (Object)null)
				{
					_levelRadius = _modifier.m_levelRadius;
					_smoothRadius = _modifier.m_smoothRadius;
					_paintRadius = _modifier.m_paintRadius;
				}
			}

			internal void Apply(float radius)
			{
				if ((Object)(object)_terrainOp != (Object)null)
				{
					DynamicFlattenRadius.Apply(_terrainOp.m_settings, radius);
				}
				if ((Object)(object)_modifier != (Object)null)
				{
					DynamicFlattenRadius.Apply(_modifier, radius);
				}
			}

			internal void Restore()
			{
				if (!_restored)
				{
					_restored = true;
					if ((Object)(object)_terrainOp != (Object)null && _terrainOp.m_settings != null)
					{
						_terrainOp.m_settings.m_levelRadius = _levelRadius;
						_terrainOp.m_settings.m_raiseRadius = _raiseRadius;
						_terrainOp.m_settings.m_smoothRadius = _smoothRadius;
						_terrainOp.m_settings.m_paintRadius = _paintRadius;
					}
					if ((Object)(object)_modifier != (Object)null)
					{
						_modifier.m_levelRadius = _levelRadius;
						_modifier.m_smoothRadius = _smoothRadius;
						_modifier.m_paintRadius = _paintRadius;
					}
				}
			}
		}

		private static readonly FieldRef<Player, GameObject> PlacementGhost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static ConfigEntry<bool> Enabled;

		private static ConfigEntry<float> MaximumRadius;

		private static Piece _selectedPiece;

		private static float _originalRadius;

		private static float _currentRadius;

		private static float _scroll;

		internal static void Initialize(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			Enabled = config.Bind<bool>("Terrain", "DynamicFlattenRadius", true, "Permite ajustar com Ctrl + roda do mouse o raio de Terraplanar, Cultivar, colocar grama e pavimentar com pedra. Trocar de função, ferramenta ou desconectar restaura o raio original. Sincronizado e bloqueado pelo servidor.");
			MaximumRadius = config.Bind<float>("Terrain", "MaximumFlattenRadius", 10f, new ConfigDescription("Raio máximo, em metros, permitido para as ações de terreno compatíveis com Ctrl + roda do mouse. Cada passo altera 0,5 m. Sincronizado e bloqueado pelo servidor.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 25f), Array.Empty<object>()));
		}

		internal static void Reset()
		{
			_selectedPiece = null;
			_originalRadius = 0f;
			_currentRadius = 0f;
			_scroll = 0f;
		}

		internal static void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			Piece val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetSelectedPiece() : null);
			if (Enabled == null || !Enabled.Value || (Object)(object)val == (Object)null || (Object)(object)PlacementGhost.Invoke(localPlayer) == (Object)null || !FlattenRadiusRules.IsSupportedTerrainAction(Utils.GetPrefabName(((Component)val).gameObject)))
			{
				ResetSelection();
				return;
			}
			if ((Object)(object)_selectedPiece != (Object)(object)val)
			{
				_selectedPiece = val;
				_originalRadius = GetOriginalRadius(val);
				_currentRadius = _originalRadius;
				_scroll = 0f;
			}
			ApplyPreview(localPlayer);
			if (!ControlHeld() || IsUiBlocking())
			{
				_scroll = 0f;
				return;
			}
			_scroll += ZInput.GetMouseScrollWheel();
			if (!(Mathf.Abs(_scroll) < 0.1f))
			{
				int direction = ((_scroll > 0f) ? 1 : (-1));
				_scroll = 0f;
				float num = FlattenRadiusRules.Adjust(_currentRadius, _originalRadius, MaximumRadius.Value, direction);
				if (!Mathf.Approximately(num, _currentRadius))
				{
					_currentRadius = num;
					ApplyPreview(localPlayer);
					((Character)localPlayer).Message((MessageType)2, $"Raio de {FlattenRadiusRules.ActionName(Utils.GetPrefabName(((Component)val).gameObject))}: {_currentRadius:0.0} m", 0, (Sprite)null, false);
				}
			}
		}

		private static void ResetSelection()
		{
			_selectedPiece = null;
			_originalRadius = 0f;
			_currentRadius = 0f;
			_scroll = 0f;
		}

		private static float GetOriginalRadius(Piece piece)
		{
			TerrainOp component = ((Component)piece).GetComponent<TerrainOp>();
			if ((Object)(object)component != (Object)null)
			{
				return component.GetRadius();
			}
			TerrainModifier component2 = ((Component)piece).GetComponent<TerrainModifier>();
			if (!((Object)(object)component2 != (Object)null))
			{
				return 3f;
			}
			return component2.GetRadius();
		}

		private static void ApplyPreview(Player player)
		{
			GameObject val = PlacementGhost.Invoke(player);
			if (!((Object)(object)val == (Object)null) && FlattenRadiusRules.IsSupportedTerrainAction(Utils.GetPrefabName(val)))
			{
				TerrainOp component = val.GetComponent<TerrainOp>();
				if ((Object)(object)component != (Object)null)
				{
					Apply(component.m_settings, _currentRadius);
				}
				CircleProjector[] componentsInChildren = val.GetComponentsInChildren<CircleProjector>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].m_radius = _currentRadius;
				}
			}
		}

		private static void Apply(Settings settings, float radius)
		{
			if (settings != null)
			{
				if (settings.m_level)
				{
					settings.m_levelRadius = radius;
				}
				if (settings.m_raise)
				{
					settings.m_raiseRadius = radius;
				}
				if (settings.m_smooth)
				{
					settings.m_smoothRadius = radius;
				}
				if (settings.m_paintCleared)
				{
					settings.m_paintRadius = radius;
				}
			}
		}

		private static void Apply(TerrainModifier modifier, float radius)
		{
			if (modifier.m_level)
			{
				modifier.m_levelRadius = radius;
			}
			if (modifier.m_smooth)
			{
				modifier.m_smoothRadius = radius;
			}
			if (modifier.m_paintCleared)
			{
				modifier.m_paintRadius = radius;
			}
		}

		private static bool ControlHeld()
		{
			if (!Input.GetKey((KeyCode)306))
			{
				return Input.GetKey((KeyCode)305);
			}
			return true;
		}

		private static bool IsUiBlocking()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			if (!Hud.IsPieceSelectionVisible() && !InventoryGui.IsVisible() && !Menu.IsActive() && !Console.IsVisible() && !TextInput.IsVisible() && (!((Object)(object)Minimap.instance != (Object)null) || (int)Minimap.instance.m_mode != 2))
			{
				if ((Object)(object)Chat.instance != (Object)null)
				{
					return Chat.instance.HasFocus();
				}
				return false;
			}
			return true;
		}
	}
	internal static class EquipmentUpgrades
	{
		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class CopyDatabasePatch
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(ObjectDB __instance)
			{
				Apply(__instance);
			}
		}

		[HarmonyPatch(typeof(Recipe), "GetRequiredStationLevel")]
		private static class RequiredLevelPatch
		{
			[HarmonyPostfix]
			private static void Postfix(Recipe __instance, int quality, ref int __result)
			{
				SharedData val = __instance.m_item?.m_itemData?.m_shared;
				if (ExtraLevels != null && ExtraLevels.Value != 0 && val != null && OriginalLimits.TryGetValue(val, out var value) && quality > value && quality <= val.m_maxQuality)
				{
					CraftingStation requiredStation = __instance.GetRequiredStation(quality);
					if ((Object)(object)requiredStation != (Object)null && !requiredStation.m_upgrader && StationMaxima.TryGetValue(requiredStation.m_name, out var value2))
					{
						__result = value2;
					}
				}
			}
		}

		private static ConfigEntry<int> ExtraLevels;

		private static readonly Dictionary<SharedData, int> OriginalLimits = new Dictionary<SharedData, int>();

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

		internal static void Initialize(ConfigFile config)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			ExtraLevels = config.Bind<int>("Equipment", "ExtraUpgradeLevels", 2, new ConfigDescription("Níveis extras para armas, escudos e armaduras melhoráveis. 2 aumenta um limite original de 4 para 6; 0 preserva original. Os níveis extras exigem a estação com todas as melhorias disponíveis no catálogo de construção. Custos e atributos seguem as fórmulas nativas. Não reduz a qualidade de itens existentes. Sincronizado e bloqueado pelo servidor.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>()));
			ExtraLevels.SettingChanged += OnChanged;
		}

		private static void OnChanged(object sender, EventArgs args)
		{
			Apply(ObjectDB.instance);
		}

		private static bool IsEquipment(ItemType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected I4, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			switch (type - 3)
			{
			default:
				if ((int)type != 22)
				{
					break;
				}
				goto case 0;
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 8:
			case 9:
			case 11:
			case 14:
				return true;
			case 5:
			case 6:
			case 7:
			case 10:
			case 12:
			case 13:
				break;
			}
			return false;
		}

		internal static void Apply(ObjectDB db)
		{
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			if (db?.m_items == null || ExtraLevels == null)
			{
				return;
			}
			Dictionary<string, HashSet<string>> dictionary = new Dictionary<string, HashSet<string>>();
			HashSet<string> hashSet = new HashSet<string>();
			HashSet<PieceTable> hashSet2 = new HashSet<PieceTable>();
			foreach (GameObject item in db.m_items)
			{
				PieceTable val = ((!((Object)(object)item != (Object)null)) ? null : item.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces);
				if ((Object)(object)val == (Object)null || !hashSet2.Add(val))
				{
					continue;
				}
				foreach (GameObject piece in val.m_pieces)
				{
					if ((Object)(object)piece == (Object)null)
					{
						continue;
					}
					StationExtension component = piece.GetComponent<StationExtension>();
					Piece component2 = piece.GetComponent<Piece>();
					if (!((Object)(object)component?.m_craftingStation == (Object)null) && !((Object)(object)component2 == (Object)null) && component2.m_enabled)
					{
						string name = component.m_craftingStation.m_name;
						if (component.m_stack)
						{
							hashSet.Add(name);
						}
						if (!dictionary.TryGetValue(name, out var value))
						{
							value = (dictionary[name] = new HashSet<string>());
						}
						value.Add(component2.m_name);
					}
				}
			}
			StationMaxima.Clear();
			foreach (KeyValuePair<string, HashSet<string>> item2 in dictionary)
			{
				if (!hashSet.Contains(item2.Key))
				{
					StationMaxima[item2.Key] = 1 + item2.Value.Count;
				}
			}
			HashSet<SharedData> hashSet4 = new HashSet<SharedData>();
			foreach (Recipe recipe in db.m_recipes)
			{
				SharedData val2 = recipe?.m_item?.m_itemData?.m_shared;
				if (val2 != null && IsEquipment(val2.m_itemType))
				{
					if (!OriginalLimits.TryGetValue(val2, out var value2))
					{
						value2 = (OriginalLimits[val2] = val2.m_maxQuality);
					}
					CraftingStation requiredStation = recipe.GetRequiredStation(value2 + 1);
					if (value2 > 1 && (Object)(object)requiredStation != (Object)null && !requiredStation.m_upgrader && StationMaxima.ContainsKey(requiredStation.m_name))
					{
						hashSet4.Add(va