Decompiled source of StorageNetwork v1.0.0

StorageNetwork.dll

Decompiled 16 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("StorageNetwork")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("StorageNetwork")]
[assembly: AssemblyTitle("StorageNetwork")]
[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 StorageNetwork
{
	internal enum ChestRole
	{
		None,
		Input,
		Storage
	}
	internal static class ChestConfig
	{
		internal const float MinRange = 2f;

		internal const float MaxRange = 100f;

		private static readonly int RoleKey = StringExtensionMethods.GetStableHashCode("SN_Role");

		private static readonly int TagsKey = StringExtensionMethods.GetStableHashCode("SN_Tags");

		private static readonly int RangeKey = StringExtensionMethods.GetStableHashCode("SN_Range");

		private static readonly int LockedKey = StringExtensionMethods.GetStableHashCode("SN_TypeLocked");

		private static readonly int LegacyItemTagsKey = StringExtensionMethods.GetStableHashCode("SN_ItemTags");

		internal static readonly int InUseKey = StringExtensionMethods.GetStableHashCode("InUse");

		internal static float DefaultRange => Mathf.Clamp(Plugin.NetworkRange.Value, 2f, 100f);

		internal static ZDO GetZDO(Container c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return null;
			}
			ZNetView component = ((Component)c).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return null;
			}
			return component.GetZDO();
		}

		internal static bool TryGetId(Container c, out ZDOID id)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = GetZDO(c);
			id = zDO?.m_uid ?? ZDOID.None;
			return zDO != null;
		}

		internal static bool IsEligible(Container c)
		{
			if (GetZDO(c) == null)
			{
				return false;
			}
			if ((Object)(object)((Component)c).GetComponent<TombStone>() != (Object)null)
			{
				return false;
			}
			if (!Plugin.AllowMovingContainers.Value)
			{
				if ((Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null)
				{
					return false;
				}
				if ((Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null)
				{
					return false;
				}
			}
			return true;
		}

		internal static bool EnsureOwner(Container c)
		{
			ZNetView val = (((Object)(object)c != (Object)null) ? ((Component)c).GetComponent<ZNetView>() : null);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return false;
			}
			if (!val.IsOwner())
			{
				val.ClaimOwnership();
			}
			return val.IsOwner();
		}

		internal static bool IsInUseByOthers(Container c)
		{
			ZDO zDO = GetZDO(c);
			if (zDO != null)
			{
				return zDO.GetInt(InUseKey, 0) == 1;
			}
			return false;
		}

		internal static ChestRole GetRole(Container c)
		{
			ZDO zDO = GetZDO(c);
			if (zDO == null)
			{
				return ChestRole.None;
			}
			return zDO.GetInt(RoleKey, 0) switch
			{
				2 => ChestRole.Storage, 
				1 => ChestRole.Input, 
				_ => ChestRole.None, 
			};
		}

		internal static bool SetRole(Container c, ChestRole role)
		{
			if (IsLocked(c) || !EnsureOwner(c))
			{
				return false;
			}
			GetZDO(c).Set(RoleKey, (int)role, false);
			return true;
		}

		internal static bool IsLocked(Container c)
		{
			ZDO zDO = GetZDO(c);
			if (zDO != null)
			{
				return zDO.GetInt(LockedKey, 0) == 1;
			}
			return false;
		}

		internal static void SetLocked(Container c, bool locked)
		{
			if (EnsureOwner(c))
			{
				GetZDO(c).Set(LockedKey, locked ? 1 : 0, false);
			}
		}

		internal static bool HasCustomRange(Container c)
		{
			ZDO zDO = GetZDO(c);
			if (zDO != null)
			{
				return zDO.GetFloat(RangeKey, 0f) > 0f;
			}
			return false;
		}

		internal static float GetRange(Container c)
		{
			ZDO zDO = GetZDO(c);
			float num = ((zDO != null) ? zDO.GetFloat(RangeKey, 0f) : 0f);
			if (!(num > 0f))
			{
				return DefaultRange;
			}
			return Mathf.Clamp(num, 2f, 100f);
		}

		internal static void SetRange(Container c, float range)
		{
			if (EnsureOwner(c))
			{
				GetZDO(c).Set(RangeKey, (range > 0f) ? Mathf.Clamp(range, 2f, 100f) : 0f);
			}
		}

		internal static List<string> GetTags(Container c)
		{
			ZDO zDO = GetZDO(c);
			if (zDO != null)
			{
				return TagDatabase.ParseList(zDO.GetString(TagsKey, ""));
			}
			return new List<string>();
		}

		internal static void SetTags(Container c, IEnumerable<string> tags)
		{
			if (EnsureOwner(c))
			{
				GetZDO(c).Set(TagsKey, TagDatabase.JoinList(tags));
			}
		}

		internal static Dictionary<string, List<string>> GetLegacyItemTags(Container c)
		{
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
			ZDO zDO = GetZDO(c);
			if (zDO == null)
			{
				return dictionary;
			}
			string text = zDO.GetString(LegacyItemTagsKey, "");
			if (string.IsNullOrEmpty(text))
			{
				return dictionary;
			}
			string[] array = text.Split(new char[1] { ';' });
			foreach (string text2 in array)
			{
				int num = text2.IndexOf('=');
				if (num > 0)
				{
					string text3 = text2.Substring(0, num).Trim();
					if (text3.Length != 0)
					{
						dictionary[text3] = TagDatabase.ParseList(text2.Substring(num + 1));
					}
				}
			}
			return dictionary;
		}

		internal static void ClearLegacyItemTags(Container c)
		{
			if (EnsureOwner(c))
			{
				GetZDO(c).Set(LegacyItemTagsKey, "");
			}
		}

		internal static string Describe(Container c)
		{
			string text = DescribeRole(c);
			if (text == null || !IsLocked(c))
			{
				return text;
			}
			return text + " (type locked)";
		}

		private static string DescribeRole(Container c)
		{
			switch (GetRole(c))
			{
			case ChestRole.Input:
				return $"Input chest ({GetRange(c):0}m)";
			case ChestRole.Storage:
			{
				List<string> tags = GetTags(c);
				if (tags.Count != 0)
				{
					return "Storage: " + string.Join(", ", tags.ToArray());
				}
				return "Storage (no tags)";
			}
			default:
				return null;
			}
		}
	}
	internal class ContainerTracker : MonoBehaviour
	{
		private static readonly HashSet<Container> Tracked = new HashSet<Container>();

		private Container _container;

		private void Awake()
		{
			_container = ((Component)this).GetComponent<Container>();
			if ((Object)(object)_container != (Object)null)
			{
				Tracked.Add(_container);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_container != (Object)null)
			{
				Tracked.Remove(_container);
			}
		}

		internal static List<Container> All()
		{
			List<Container> list = new List<Container>(Tracked.Count);
			foreach (Container item in Tracked)
			{
				if ((Object)(object)item != (Object)null)
				{
					list.Add(item);
				}
			}
			return list;
		}

		internal static List<Container> InRange(Vector3 origin, float range)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			List<Container> list = new List<Container>();
			float num = range * range;
			foreach (Container item in Tracked)
			{
				if (!((Object)(object)item == (Object)null))
				{
					Vector3 val = ((Component)item).transform.position - origin;
					if (!(((Vector3)(ref val)).sqrMagnitude > num) && ChestConfig.IsEligible(item))
					{
						list.Add(item);
					}
				}
			}
			return list;
		}
	}
	internal class FlashManager : MonoBehaviour
	{
		private static readonly HashSet<ZDOID> Flashing = new HashSet<ZDOID>();

		private static readonly HashSet<string> Selected = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static float _startTime;

		private float _nextAttach;

		internal static int FlashingCount => Flashing.Count;

		internal static IEnumerable<string> SelectedPrefabs => Selected;

		internal static bool IsSelected(string prefab)
		{
			return Selected.Contains(prefab);
		}

		internal static bool IsFlashing(ZDOID id)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return Flashing.Contains(id);
		}

		internal static bool IsFlashing(Container c)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (ChestConfig.TryGetId(c, out var id))
			{
				return Flashing.Contains(id);
			}
			return false;
		}

		internal static void Set(IEnumerable<string> prefabs, IEnumerable<ZDOID> chests)
		{
			Selected.Clear();
			Flashing.Clear();
			if (prefabs != null)
			{
				Selected.UnionWith(prefabs);
			}
			if (chests != null)
			{
				Flashing.UnionWith(chests);
			}
			if (Flashing.Count == 0)
			{
				Selected.Clear();
			}
			_startTime = Time.time;
		}

		internal static void Clear()
		{
			Selected.Clear();
			Flashing.Clear();
		}

		private void Update()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				if (Flashing.Count > 0)
				{
					Clear();
				}
			}
			else
			{
				if (Flashing.Count == 0)
				{
					return;
				}
				if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible())
				{
					Container val = Patches.CurrentContainer(InventoryGui.instance);
					if ((Object)(object)val != (Object)null && ChestConfig.TryGetId(val, out var id) && Flashing.Remove(id) && Flashing.Count == 0)
					{
						Selected.Clear();
					}
				}
				float value = Plugin.FlashTimeout.Value;
				if (value > 0f && Time.time - _startTime > value)
				{
					Clear();
				}
				else
				{
					if (Time.time < _nextAttach)
					{
						return;
					}
					_nextAttach = Time.time + 0.5f;
					foreach (Container item in ContainerTracker.All())
					{
						if (ChestConfig.TryGetId(item, out var id2) && Flashing.Contains(id2) && (Object)(object)((Component)item).GetComponent<FlashEffect>() == (Object)null)
						{
							((Component)item).gameObject.AddComponent<FlashEffect>().Init(id2);
						}
					}
				}
			}
		}
	}
	internal class FlashEffect : MonoBehaviour
	{
		private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor");

		private static Material _beamMaterial;

		private static bool _beamMaterialSearched;

		private ZDOID _id;

		private GameObject _fx;

		private Light _light;

		private LineRenderer _beam;

		private Renderer[] _renderers = (Renderer[])(object)new Renderer[0];

		private MaterialPropertyBlock[] _originalBlocks = (MaterialPropertyBlock[])(object)new MaterialPropertyBlock[0];

		private MaterialPropertyBlock _block;

		internal void Init(ZDOID id)
		{
			//IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Expected O, but got Unknown
			_id = id;
			Color value = Plugin.FlashColor.Value;
			_renderers = Array.FindAll(((Component)this).GetComponentsInChildren<Renderer>(), (Renderer r) => r is MeshRenderer || r is SkinnedMeshRenderer);
			Vector3 val = ((Component)this).transform.position + Vector3.up;
			if (_renderers.Length != 0)
			{
				Bounds bounds = _renderers[0].bounds;
				Renderer[] renderers = _renderers;
				foreach (Renderer val2 in renderers)
				{
					((Bounds)(ref bounds)).Encapsulate(val2.bounds);
				}
				((Vector3)(ref val))..ctor(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).max.y, ((Bounds)(ref bounds)).center.z);
			}
			_fx = new GameObject("StorageNetwork_Flash");
			_fx.transform.position = val + Vector3.up * 0.3f;
			_fx.transform.SetParent(((Component)this).transform, true);
			_light = _fx.AddComponent<Light>();
			_light.type = (LightType)2;
			_light.color = value;
			_light.range = 4f;
			_light.shadows = (LightShadows)0;
			if (Plugin.FlashBeam.Value && (Object)(object)BeamMaterial() != (Object)null)
			{
				_beam = _fx.AddComponent<LineRenderer>();
				((Renderer)_beam).sharedMaterial = _beamMaterial;
				_beam.useWorldSpace = true;
				_beam.positionCount = 2;
				_beam.SetPosition(0, val);
				_beam.SetPosition(1, val + Vector3.up * 12f);
				_beam.startWidth = 0.15f;
				_beam.endWidth = 0.02f;
				((Renderer)_beam).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)_beam).receiveShadows = false;
			}
			if (Plugin.FlashGlow.Value)
			{
				_block = new MaterialPropertyBlock();
				_originalBlocks = (MaterialPropertyBlock[])(object)new MaterialPropertyBlock[_renderers.Length];
				for (int num2 = 0; num2 < _renderers.Length; num2++)
				{
					_originalBlocks[num2] = new MaterialPropertyBlock();
					_renderers[num2].GetPropertyBlock(_originalBlocks[num2]);
				}
			}
			else
			{
				_renderers = (Renderer[])(object)new Renderer[0];
			}
		}

		private static Material BeamMaterial()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			if (_beamMaterialSearched)
			{
				return _beamMaterial;
			}
			_beamMaterialSearched = true;
			string[] array = new string[4] { "Sprites/Default", "UI/Default", "Legacy Shaders/Particles/Additive", "Unlit/Color" };
			for (int i = 0; i < array.Length; i++)
			{
				Shader val = Shader.Find(array[i]);
				if (!((Object)(object)val == (Object)null))
				{
					_beamMaterial = new Material(val);
					break;
				}
			}
			if ((Object)(object)_beamMaterial == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No shader found for the flash beam; only the light will be shown.");
			}
			return _beamMaterial;
		}

		private void Update()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			if (!FlashManager.IsFlashing(_id))
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			float num = 0.5f + 0.5f * Mathf.Sin(Time.time * 6f);
			Color value = Plugin.FlashColor.Value;
			if ((Object)(object)_light != (Object)null)
			{
				_light.intensity = 0.6f + 2.4f * num;
			}
			if ((Object)(object)_beam != (Object)null)
			{
				Color startColor = default(Color);
				((Color)(ref startColor))..ctor(value.r, value.g, value.b, 0.2f + 0.7f * num);
				_beam.startColor = startColor;
				_beam.endColor = new Color(value.r, value.g, value.b, 0f);
			}
			for (int i = 0; i < _renderers.Length; i++)
			{
				Renderer val = _renderers[i];
				if (!((Object)(object)val == (Object)null))
				{
					val.GetPropertyBlock(_block);
					_block.SetColor(EmissionColor, value * (0.15f + 0.6f * num));
					val.SetPropertyBlock(_block);
				}
			}
		}

		private void OnDestroy()
		{
			for (int i = 0; i < _renderers.Length; i++)
			{
				if ((Object)(object)_renderers[i] != (Object)null)
				{
					_renderers[i].SetPropertyBlock(_originalBlocks[i]);
				}
			}
			if ((Object)(object)_fx != (Object)null)
			{
				Object.Destroy((Object)(object)_fx);
			}
		}
	}
	internal static class GlobalItemTags
	{
		internal enum SyncMode
		{
			NotReady,
			Host,
			Client,
			ClientLocalOnly
		}

		private const string RpcRequest = "StorageNetwork_ItemTags_Request";

		private const string RpcFull = "StorageNetwork_ItemTags_Full";

		private const string RpcSet = "StorageNetwork_ItemTags_Set";

		private const string RpcChanged = "StorageNetwork_ItemTags_Changed";

		private const float ServerReplyTimeout = 10f;

		private static readonly Dictionary<string, List<string>> Rules = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);

		private static ZRoutedRpc _registeredOn;

		private static string _savePath;

		private static bool _requested;

		private static float _requestTime;

		internal static SyncMode Mode { get; private set; } = SyncMode.NotReady;

		internal static bool Ready => Mode != SyncMode.NotReady;

		internal static int Revision { get; private set; }

		internal static string StatusText => Mode switch
		{
			SyncMode.NotReady => "Waiting for the world's item tags...", 
			SyncMode.ClientLocalOnly => "The server doesn't run Storage Network: item tags are saved on this PC only.", 
			_ => null, 
		};

		internal static void Tick()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null)
			{
				if (Mode != SyncMode.NotReady || _registeredOn != null)
				{
					Reset();
				}
				return;
			}
			if (_registeredOn != ZRoutedRpc.instance)
			{
				Register();
			}
			if (ZNet.instance.IsServer())
			{
				if (Mode != SyncMode.Host)
				{
					InitHost();
				}
			}
			else
			{
				if (Mode == SyncMode.Client || (Object)(object)Player.m_localPlayer == (Object)null)
				{
					return;
				}
				if (!_requested)
				{
					long num = ServerPeerId();
					if (num != 0L)
					{
						_requested = true;
						_requestTime = Time.unscaledTime;
						ZRoutedRpc.instance.InvokeRoutedRPC(num, "StorageNetwork_ItemTags_Request", new object[1] { (object)new ZPackage() });
					}
				}
				else if (Mode == SyncMode.NotReady && Time.unscaledTime - _requestTime > 10f)
				{
					Plugin.Log.LogWarning((object)"No reply from the server for item tags; it probably doesn't run Storage Network. Using a local table.");
					_savePath = Path.Combine(FolderPath(), "_server-without-mod.itemtags.txt");
					Load();
					Mode = SyncMode.ClientLocalOnly;
					Revision++;
				}
			}
		}

		private static void Reset()
		{
			Rules.Clear();
			Mode = SyncMode.NotReady;
			_registeredOn = null;
			_savePath = null;
			_requested = false;
			Revision++;
		}

		private static void Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			instance.Register<ZPackage>("StorageNetwork_ItemTags_Request", (Action<long, ZPackage>)OnRequest);
			instance.Register<ZPackage>("StorageNetwork_ItemTags_Full", (Action<long, ZPackage>)OnFull);
			instance.Register<ZPackage>("StorageNetwork_ItemTags_Set", (Action<long, ZPackage>)OnSet);
			instance.Register<ZPackage>("StorageNetwork_ItemTags_Changed", (Action<long, ZPackage>)OnChanged);
			_registeredOn = instance;
		}

		private static void InitHost()
		{
			string worldName = ZNet.instance.GetWorldName();
			if (!string.IsNullOrEmpty(worldName))
			{
				_savePath = Path.Combine(FolderPath(), SafeFileName(worldName) + ".itemtags.txt");
				Load();
				Mode = SyncMode.Host;
				Revision++;
				Plugin.Log.LogInfo((object)$"World item tags: {Rules.Count} rules from {_savePath}");
			}
		}

		internal static bool TryGet(string prefab, out List<string> tags)
		{
			return Rules.TryGetValue(prefab, out tags);
		}

		internal static IEnumerable<string> AllUsedTags()
		{
			return Rules.Values.SelectMany((List<string> v) => v);
		}

		internal static void Set(string prefab, List<string> tags)
		{
			if (string.IsNullOrEmpty(prefab) || !Ready)
			{
				return;
			}
			Apply(prefab, tags);
			switch (Mode)
			{
			case SyncMode.Host:
				Save();
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "StorageNetwork_ItemTags_Changed", new object[1] { Pack(prefab, tags) });
				break;
			case SyncMode.Client:
			{
				long num = ServerPeerId();
				if (num != 0L)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(num, "StorageNetwork_ItemTags_Set", new object[1] { Pack(prefab, tags) });
				}
				else
				{
					Plugin.Log.LogWarning((object)"Not connected to the server; item tag change was not sent.");
				}
				break;
			}
			case SyncMode.ClientLocalOnly:
				Save();
				break;
			}
		}

		internal static void MigrateLegacy(Container c)
		{
			if (!Ready || (Object)(object)c == (Object)null)
			{
				return;
			}
			Dictionary<string, List<string>> legacyItemTags = ChestConfig.GetLegacyItemTags(c);
			if (legacyItemTags.Count == 0)
			{
				return;
			}
			int num = 0;
			foreach (KeyValuePair<string, List<string>> item in legacyItemTags)
			{
				if (!Rules.ContainsKey(item.Key))
				{
					Set(item.Key, item.Value);
					num++;
				}
			}
			ChestConfig.ClearLegacyItemTags(c);
			Plugin.Log.LogInfo((object)$"Moved {num} item tag rule(s) from a chest into the world-wide table");
		}

		private static void OnRequest(long sender, ZPackage _)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			if (!ZNet.instance.IsServer())
			{
				return;
			}
			if (Mode != SyncMode.Host)
			{
				InitHost();
			}
			ZPackage val = new ZPackage();
			val.Write(Rules.Count);
			foreach (KeyValuePair<string, List<string>> rule in Rules)
			{
				val.Write(rule.Key);
				val.Write(TagDatabase.JoinList(rule.Value));
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "StorageNetwork_ItemTags_Full", new object[1] { val });
		}

		private static void OnFull(long sender, ZPackage pkg)
		{
			if (!ZNet.instance.IsServer())
			{
				Rules.Clear();
				int num = pkg.ReadInt();
				for (int i = 0; i < num; i++)
				{
					string key = pkg.ReadString();
					Rules[key] = TagDatabase.ParseList(pkg.ReadString());
				}
				if (Mode == SyncMode.ClientLocalOnly)
				{
					Plugin.Log.LogInfo((object)"Server replied late; switching from local to world-wide item tags.");
				}
				Mode = SyncMode.Client;
				_savePath = null;
				Revision++;
			}
		}

		private static void OnSet(long sender, ZPackage pkg)
		{
			if (ZNet.instance.IsServer())
			{
				if (Mode != SyncMode.Host)
				{
					InitHost();
				}
				Unpack(pkg, out var prefab, out var tags);
				Apply(prefab, tags);
				Save();
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "StorageNetwork_ItemTags_Changed", new object[1] { Pack(prefab, tags) });
			}
		}

		private static void OnChanged(long sender, ZPackage pkg)
		{
			if (!ZNet.instance.IsServer())
			{
				Unpack(pkg, out var prefab, out var tags);
				Apply(prefab, tags);
			}
		}

		private static long ServerPeerId()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return 0L;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer != null && peer.m_uid != 0L)
				{
					return peer.m_uid;
				}
			}
			return 0L;
		}

		private static void Apply(string prefab, List<string> tags)
		{
			if (tags == null)
			{
				Rules.Remove(prefab);
			}
			else
			{
				Rules[prefab] = new List<string>(tags);
			}
			Revision++;
		}

		private static ZPackage Pack(string prefab, List<string> tags)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(prefab);
			val.Write(tags == null);
			val.Write((tags == null) ? "" : TagDatabase.JoinList(tags));
			return val;
		}

		private static void Unpack(ZPackage pkg, out string prefab, out List<string> tags)
		{
			prefab = pkg.ReadString();
			bool flag = pkg.ReadBool();
			string csv = pkg.ReadString();
			tags = (flag ? null : TagDatabase.ParseList(csv));
		}

		private static string FolderPath()
		{
			string text = Path.Combine(Path.Combine(Paths.ConfigPath, "StorageNetwork"), "worlds");
			Directory.CreateDirectory(text);
			return text;
		}

		private static string SafeFileName(string name)
		{
			StringBuilder stringBuilder = new StringBuilder(name.Length);
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char c in name)
			{
				stringBuilder.Append((Array.IndexOf(invalidFileNameChars, c) >= 0) ? '_' : c);
			}
			return stringBuilder.ToString();
		}

		private static void Load()
		{
			Rules.Clear();
			if (_savePath == null || !File.Exists(_savePath))
			{
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(_savePath);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.Length != 0 && !text.StartsWith("#"))
					{
						int num = text.IndexOf('=');
						if (num > 0)
						{
							Rules[text.Substring(0, num).Trim()] = TagDatabase.ParseList(text.Substring(num + 1));
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not read item tags from " + _savePath + ": " + ex.Message));
			}
		}

		private static void Save()
		{
			if (_savePath == null)
			{
				return;
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("# Storage Network world-wide item tags. Format: PrefabName=tagA,tagB");
				stringBuilder.AppendLine("# An empty list after '=' means the item is deliberately untagged.");
				foreach (KeyValuePair<string, List<string>> item in Rules.OrderBy<KeyValuePair<string, List<string>>, string>((KeyValuePair<string, List<string>> k) => k.Key, StringComparer.OrdinalIgnoreCase))
				{
					stringBuilder.Append(item.Key).Append('=').AppendLine(TagDatabase.JoinList(item.Value));
				}
				string text = _savePath + ".tmp";
				File.WriteAllText(text, stringBuilder.ToString());
				if (File.Exists(_savePath))
				{
					File.Delete(_savePath);
				}
				File.Move(text, _savePath);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not save item tags to " + _savePath + ": " + ex.Message));
			}
		}
	}
	internal static class NetworkCrafting
	{
		private enum Source
		{
			Station,
			PlayerPosition
		}

		private static int _depth;

		private static Source _source;

		private static int _cacheFrame = -1;

		private static Source _cacheSource;

		private static CraftingStation _cacheStation;

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

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

		internal static bool Active => _depth > 0;

		internal static void Patch(Harmony harmony)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected O, but got Unknown
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Expected O, but got Unknown
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Expected O, but got Unknown
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Expected O, but got Unknown
			HarmonyMethod finalizer = new HarmonyMethod(typeof(NetworkCrafting), "ExitFinalizer", (Type[])null);
			int num = 0;
			HarmonyMethod prefix = new HarmonyMethod(typeof(NetworkCrafting), "EnterRecipePrefix", (Type[])null);
			foreach (MethodInfo item in Methods(typeof(Player), "HaveRequirementItems", "HaveRequirements").Where(FirstParamIsRecipe))
			{
				num += TryPatch(harmony, item, prefix, null, finalizer);
			}
			HarmonyMethod prefix2 = new HarmonyMethod(typeof(NetworkCrafting), "EnterPiecePrefix", (Type[])null);
			foreach (MethodInfo item2 in Methods(typeof(Player), "HaveRequirements").Where(FirstParamIsPiece))
			{
				num += TryPatch(harmony, item2, prefix2, null, finalizer);
			}
			HarmonyMethod prefix3 = new HarmonyMethod(typeof(NetworkCrafting), "EnterAutoPrefix", (Type[])null);
			foreach (MethodInfo item3 in Methods(typeof(Player), "ConsumeResources").Concat(Methods(typeof(InventoryGui), "SetupRequirement")))
			{
				num += TryPatch(harmony, item3, prefix3, null, finalizer);
			}
			HarmonyMethod postfix = new HarmonyMethod(typeof(NetworkCrafting), "SetupRequirementPostfix", (Type[])null);
			foreach (MethodInfo item4 in Methods(typeof(InventoryGui), "SetupRequirement"))
			{
				TryPatch(harmony, item4, null, postfix);
			}
			int num2 = 0;
			HarmonyMethod postfix2 = new HarmonyMethod(typeof(NetworkCrafting), "CountItemsPostfix", (Type[])null);
			foreach (MethodInfo item5 in Methods(typeof(Inventory), "CountItems").Where(FirstParamIsString))
			{
				num2 += TryPatch(harmony, item5, null, postfix2);
			}
			int num3 = 0;
			HarmonyMethod prefix4 = new HarmonyMethod(typeof(NetworkCrafting), "RemoveItemPrefix", (Type[])null);
			foreach (MethodInfo item6 in from m in Methods(typeof(Inventory), "RemoveItem")
				where FirstParamIsString(m) && SecondParamIsInt(m)
				select m)
			{
				num3 += TryPatch(harmony, item6, prefix4);
			}
			if (num == 0 || num2 == 0 || num3 == 0)
			{
				Plugin.Log.LogWarning((object)$"Crafting from the network may not work: patched {num} crafting, {num2} counting and {num3} removing methods.");
			}
			else
			{
				Plugin.Log.LogInfo((object)$"Crafting from the network enabled ({num}/{num2}/{num3} methods patched)");
			}
		}

		private static IEnumerable<MethodInfo> Methods(Type type, params string[] names)
		{
			return from m in AccessTools.GetDeclaredMethods(type)
				where names.Contains(m.Name) && !m.IsAbstract
				select m;
		}

		private static bool FirstParamIsRecipe(MethodInfo m)
		{
			ParameterInfo[] parameters = m.GetParameters();
			if (parameters.Length >= 1)
			{
				return parameters[0].ParameterType == typeof(Recipe);
			}
			return false;
		}

		private static bool FirstParamIsPiece(MethodInfo m)
		{
			ParameterInfo[] parameters = m.GetParameters();
			if (parameters.Length >= 1)
			{
				return parameters[0].ParameterType == typeof(Piece);
			}
			return false;
		}

		private static bool FirstParamIsString(MethodInfo m)
		{
			ParameterInfo[] parameters = m.GetParameters();
			if (parameters.Length >= 1)
			{
				return parameters[0].ParameterType == typeof(string);
			}
			return false;
		}

		private static bool SecondParamIsInt(MethodInfo m)
		{
			ParameterInfo[] parameters = m.GetParameters();
			if (parameters.Length >= 2)
			{
				return parameters[1].ParameterType == typeof(int);
			}
			return false;
		}

		private static int TryPatch(Harmony harmony, MethodInfo m, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod finalizer = null)
		{
			try
			{
				harmony.Patch((MethodBase)m, prefix, postfix, (HarmonyMethod)null, finalizer, (HarmonyMethod)null);
				return 1;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not patch " + m.DeclaringType?.Name + "." + m.Name + ": " + ex.Message));
				return 0;
			}
		}

		private static void EnterRecipePrefix(out bool __state)
		{
			__state = Enter(Source.Station);
		}

		private static void EnterPiecePrefix(out bool __state)
		{
			__state = Enter(Source.PlayerPosition);
		}

		private static void EnterAutoPrefix(out bool __state)
		{
			bool flag = (Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible();
			__state = Enter((!flag) ? Source.PlayerPosition : Source.Station);
		}

		private static bool Enter(Source source)
		{
			if (_depth > 0)
			{
				_depth++;
				return true;
			}
			if (!((source == Source.Station) ? Plugin.CraftFromNetwork.Value : Plugin.BuildFromNetwork.Value) || ChestsFor(source).Count == 0)
			{
				return false;
			}
			_source = source;
			_depth = 1;
			return true;
		}

		private static Exception ExitFinalizer(bool __state, Exception __exception)
		{
			if (__state && _depth > 0)
			{
				_depth--;
			}
			return __exception;
		}

		internal static List<Container> NetworkChests()
		{
			return ChestsFor(_source);
		}

		private static List<Container> ChestsFor(Source source)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return new List<Container>();
			}
			CraftingStation val = ((source == Source.Station) ? localPlayer.GetCurrentCraftingStation() : null);
			if (Time.frameCount == _cacheFrame && source == _cacheSource && (Object)(object)val == (Object)(object)_cacheStation)
			{
				return _cacheChests;
			}
			_cacheFrame = Time.frameCount;
			_cacheSource = source;
			_cacheStation = val;
			CountCache.Clear();
			if (source == Source.Station)
			{
				_cacheChests = (((Object)(object)val == (Object)null) ? new List<Container>() : ChestsFor(((Component)val).transform.position));
			}
			else
			{
				_cacheChests = ChestsFor(((Component)localPlayer).transform.position);
			}
			return _cacheChests;
		}

		internal static List<Container> ChestsFor(Vector3 pos)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			List<Container> list = new List<Container>();
			HashSet<Container> hashSet = new HashSet<Container>();
			foreach (Container item in ContainerTracker.InRange(pos, 100f))
			{
				if (ChestConfig.GetRole(item) != ChestRole.Input || Vector3.Distance(pos, ((Component)item).transform.position) > ChestConfig.GetRange(item))
				{
					continue;
				}
				if (hashSet.Add(item))
				{
					list.Add(item);
				}
				foreach (SortService.Target item2 in SortService.FindTargets(item))
				{
					if (hashSet.Add(item2.Container))
					{
						list.Add(item2.Container);
					}
				}
			}
			list.Sort(delegate(Container a, Container b)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = ((Component)a).transform.position - pos;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				val = ((Component)b).transform.position - pos;
				return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude);
			});
			return list;
		}

		internal static bool InNetwork(CraftingStation station)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)station != (Object)null)
			{
				return ChestsFor(((Component)station).transform.position).Count > 0;
			}
			return false;
		}

		private static bool IsPlayerInventory(Inventory inv)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return inv == ((Humanoid)localPlayer).GetInventory();
			}
			return false;
		}

		private static bool Matches(ItemData item, string name, int quality)
		{
			if (item.m_shared.m_name == name)
			{
				if (quality >= 0)
				{
					return item.m_quality == quality;
				}
				return true;
			}
			return false;
		}

		private static int CountIn(Inventory inv, string name, int quality)
		{
			if (inv == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (Matches(allItem, name, quality))
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		internal static int NetworkCount(string name, int quality)
		{
			List<Container> list = NetworkChests();
			string key = name + "#" + quality;
			if (CountCache.TryGetValue(key, out var value))
			{
				return value;
			}
			int num = 0;
			foreach (Container item in list)
			{
				num += CountIn(item.GetInventory(), name, quality);
			}
			CountCache[key] = num;
			return num;
		}

		private static void SetupRequirementPostfix(object[] __args)
		{
			if (!Active || !Plugin.ShowNetworkAmounts.Value)
			{
				return;
			}
			Transform val = null;
			Requirement val2 = null;
			foreach (object obj in __args)
			{
				Transform val3 = (Transform)((obj is Transform) ? obj : null);
				if (val3 != null && (Object)(object)val == (Object)null)
				{
					val = val3;
					continue;
				}
				Requirement val4 = (Requirement)((obj is Requirement) ? obj : null);
				if (val4 != null && val2 == null)
				{
					val2 = val4;
				}
			}
			if (!((Object)(object)val == (Object)null) && val2 != null && !((Object)(object)val2.m_resItem == (Object)null))
			{
				TMP_Text val5 = FindAmountText(val);
				if (!((Object)(object)val5 == (Object)null) && int.TryParse(StripTags(val5.text).Trim(), out var result))
				{
					string name = val2.m_resItem.m_itemData.m_shared.m_name;
					Player localPlayer = Player.m_localPlayer;
					int num = (((Object)(object)localPlayer != (Object)null) ? CountIn(((Humanoid)localPlayer).GetInventory(), name, -1) : 0) + NetworkCount(name, -1);
					val5.textWrappingMode = (TextWrappingModes)0;
					val5.overflowMode = (TextOverflowModes)0;
					val5.text = $"{result}<size=80%> / {num}</size>";
				}
			}
		}

		private static TMP_Text FindAmountText(Transform root)
		{
			Transform val = root.Find("res_amount");
			if ((Object)(object)val != (Object)null)
			{
				TMP_Text component = ((Component)val).GetComponent<TMP_Text>();
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
			}
			TMP_Text[] componentsInChildren = ((Component)root).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val2 in componentsInChildren)
			{
				if (int.TryParse(StripTags(val2.text).Trim(), out var _))
				{
					return val2;
				}
			}
			return null;
		}

		private static string StripTags(string text)
		{
			if (string.IsNullOrEmpty(text) || text.IndexOf('<') < 0)
			{
				return text ?? "";
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			bool flag = false;
			foreach (char c in text)
			{
				switch (c)
				{
				case '<':
					flag = true;
					continue;
				case '>':
					flag = false;
					continue;
				}
				if (!flag)
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		private static void CountItemsPostfix(Inventory __instance, object[] __args, ref int __result)
		{
			if (Active && IsPlayerInventory(__instance))
			{
				string text = __args[0] as string;
				if (!string.IsNullOrEmpty(text))
				{
					int quality = ((__args.Length > 1 && __args[1] is int num) ? num : (-1));
					__result += NetworkCount(text, quality);
				}
			}
		}

		private static void RemoveItemPrefix(Inventory __instance, object[] __args)
		{
			if (!Active || !IsPlayerInventory(__instance))
			{
				return;
			}
			string text = __args[0] as string;
			if (string.IsNullOrEmpty(text) || !(__args[1] is int num) || num <= 0)
			{
				return;
			}
			int quality = ((__args.Length > 2 && __args[2] is int num2) ? num2 : (-1));
			int num3 = CountIn(__instance, text, quality);
			if (num3 < num)
			{
				__args[1] = num3;
				int num4 = TakeFromNetwork(text, quality, num - num3);
				if (num4 > 0)
				{
					Plugin.Log.LogWarning((object)$"Crafting took {num - num3 - num4} of {num - num3} missing '{text}' from the network; {num4} could not be found.");
				}
			}
		}

		private static int TakeFromNetwork(string name, int quality, int amount)
		{
			foreach (Container item in NetworkChests())
			{
				if (amount <= 0)
				{
					break;
				}
				Inventory inventory = item.GetInventory();
				if (inventory == null || CountIn(inventory, name, quality) == 0 || ChestConfig.IsInUseByOthers(item) || !ChestConfig.EnsureOwner(item))
				{
					continue;
				}
				foreach (ItemData item2 in (from i in inventory.GetAllItems()
					where Matches(i, name, quality)
					select i).ToList())
				{
					if (amount <= 0)
					{
						break;
					}
					int num = Math.Min(amount, item2.m_stack);
					inventory.RemoveItem(item2, num);
					amount -= num;
				}
			}
			CountCache.Clear();
			return amount;
		}
	}
	internal class NetworkPanel : MonoBehaviour
	{
		private enum Tab
		{
			Overview,
			ItemTags,
			Range
		}

		private const int Columns = 6;

		private const float Gap = 4f;

		private InventoryGui _builtFor;

		private RectTransform _root;

		private float _width;

		private bool _offsetDirty = true;

		private readonly List<TMP_InputField> _inputs = new List<TMP_InputField>();

		private Container _current;

		private float _nextRefresh;

		private int _seenRevision = -1;

		private Tab _tab;

		private Button[] _roleButtons;

		private Button _lockButton;

		private Image _lockIcon;

		private GameObject _noneSection;

		private GameObject _storageSection;

		private GameObject _inputSection;

		private TMP_Text _info;

		private Button[] _tabButtons;

		private GameObject[] _tabPages;

		private List<string> _nearbyTags = new List<string>();

		private List<string> _contentTags = new List<string>();

		private List<KeyValuePair<string, string>> _chestItems = new List<KeyValuePair<string, string>>();

		private TMP_InputField _ovSearch;

		private Button _ovSort;

		private bool _ovByCount;

		private RectTransform _ovContent;

		private readonly List<UiKit.Slot> _slots = new List<UiKit.Slot>();

		private readonly Dictionary<string, SortService.OverviewEntry> _ovByPrefab = new Dictionary<string, SortService.OverviewEntry>(StringComparer.OrdinalIgnoreCase);

		private List<SortService.OverviewEntry> _overview = new List<SortService.OverviewEntry>();

		private TMP_Text _ovEmpty;

		private TMP_Text _ovHover;

		private TMP_Text _ovFooter;

		private Button _ovStop;

		private TMP_Text _tagStatus;

		private TMP_InputField _tagSearch;

		private RectTransform _tagList;

		private string _tagListKey;

		private GameObject _editor;

		private TMP_Text _editorTitle;

		private TMP_Text _editorPreview;

		private TMP_InputField _editorTags;

		private RectTransform _editorChips;

		private string _editorChipsKey;

		private string _selectedPrefab;

		private TMP_Text _rangeCurrent;

		private TMP_Text _rangeValue;

		private TMP_Text _rangeChange;

		private TMP_Text _confirmText;

		private Slider _rangeSlider;

		private Button _rangeSave;

		private Button _rangeDefault;

		private GameObject _rangeButtons;

		private GameObject _rangeConfirm;

		private float _pendingRange;

		private List<SortService.Target> _dropped = new List<SortService.Target>();

		private int _gained;

		private bool _confirmIsDefault;

		private TMP_Text _storageInfo;

		private TMP_InputField _storageTags;

		private RectTransform _storageChips;

		private string _storageChipsKey;

		internal static bool IsTyping { get; private set; }

		internal static bool Failed { get; private set; }

		private void Update()
		{
			Container val = ((Plugin.ClassicPanel.Value || Failed) ? null : VisibleContainer());
			if ((Object)(object)val == (Object)null)
			{
				Hide();
			}
			else if (EnsureBuilt())
			{
				if ((Object)(object)val != (Object)(object)_current)
				{
					ResetFor(val);
				}
				if (!((Component)_root).gameObject.activeSelf)
				{
					((Component)_root).gameObject.SetActive(true);
				}
				UpdatePlacement();
				if (_seenRevision != GlobalItemTags.Revision || Time.unscaledTime >= _nextRefresh)
				{
					Refresh();
				}
				UpdateFooter();
				IsTyping = _inputs.Any((TMP_InputField i) => (Object)(object)i != (Object)null && i.isFocused);
				if (IsTyping && Input.GetKeyDown((KeyCode)27))
				{
					Unfocus();
				}
			}
		}

		private void Hide()
		{
			IsTyping = false;
			_current = null;
			if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf)
			{
				Unfocus();
				((Component)_root).gameObject.SetActive(false);
			}
		}

		private void Unfocus()
		{
			foreach (TMP_InputField input in _inputs)
			{
				if ((Object)(object)input != (Object)null && input.isFocused)
				{
					input.DeactivateInputField(false);
				}
			}
			if ((Object)(object)EventSystem.current != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			}
			IsTyping = false;
		}

		private static Container VisibleContainer()
		{
			if (!Plugin.ShowWindow.Value || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return null;
			}
			if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible())
			{
				return null;
			}
			Container val = Patches.CurrentContainer(InventoryGui.instance);
			if (!((Object)(object)val != (Object)null) || !ChestConfig.IsEligible(val))
			{
				return null;
			}
			return val;
		}

		private bool EnsureBuilt()
		{
			if ((Object)(object)_root != (Object)null && (Object)(object)_builtFor == (Object)(object)InventoryGui.instance)
			{
				return true;
			}
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_root).gameObject);
			}
			_root = null;
			_inputs.Clear();
			_slots.Clear();
			_current = null;
			try
			{
				Build(InventoryGui.instance);
				_builtFor = InventoryGui.instance;
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not build the in-game Storage Network panel; using the classic panel instead.\n" + ex));
				Failed = true;
				if ((Object)(object)_root != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)_root).gameObject);
				}
				_root = null;
				return false;
			}
		}

		private void UpdatePlacement()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if (_offsetDirty)
			{
				_offsetDirty = false;
				_root.anchoredPosition = new Vector2(ComputeOffsetX(instance), 0f);
			}
			float num = 620f;
			if ((Object)(object)instance.m_container != (Object)null && ((Component)instance.m_container).gameObject.activeInHierarchy)
			{
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				Vector3[] array2 = (Vector3[])(object)new Vector3[4];
				instance.m_player.GetWorldCorners(array);
				instance.m_container.GetWorldCorners(array2);
				float y = ((Transform)instance.m_player).InverseTransformPoint(array[1]).y;
				float y2 = ((Transform)instance.m_player).InverseTransformPoint(array2[0]).y;
				if (y - y2 > 100f)
				{
					num = y - y2;
				}
			}
			num = Mathf.Max(num, 560f);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(_width, num);
			if (_root.sizeDelta != val)
			{
				_root.sizeDelta = val;
			}
		}

		private float ComputeOffsetX(InventoryGui gui)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = gui.m_player.rect;
			float xMax = ((Rect)(ref rect)).xMax;
			float right = xMax;
			Vector3[] corners = (Vector3[])(object)new Vector3[4];
			Scan(gui.m_player);
			Scan(gui.m_container);
			return right - xMax + 10f;
			void Scan(RectTransform parent)
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)parent == (Object)null) && ((Component)parent).gameObject.activeInHierarchy)
				{
					RectTransform[] componentsInChildren = ((Component)parent).GetComponentsInChildren<RectTransform>(false);
					foreach (RectTransform val in componentsInChildren)
					{
						if (!((Object)(object)val == (Object)(object)_root) && !((Transform)val).IsChildOf((Transform)(object)_root))
						{
							val.GetWorldCorners(corners);
							float x = ((Transform)gui.m_player).InverseTransformPoint(corners[2]).x;
							if (x > right && x < xMax + 220f)
							{
								right = x;
							}
						}
					}
				}
			}
		}

		private void ResetFor(Container c)
		{
			_offsetDirty = true;
			_current = c;
			Unfocus();
			_selectedPrefab = null;
			_editor.SetActive(false);
			_storageTags.text = string.Join(", ", ChestConfig.GetTags(c).ToArray());
			_ovSearch.text = "";
			_tagSearch.text = "";
			_tagListKey = null;
			_storageChipsKey = null;
			_editorChipsKey = null;
			_pendingRange = ChestConfig.GetRange(c);
			_rangeConfirm.SetActive(false);
			_nextRefresh = 0f;
			Refresh();
		}

		private void Build(InventoryGui gui)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			UiKit.Init(gui);
			_width = 6f * UiKit.SlotSize.x + 20f + 12f + 40f;
			GameObject val = UiKit.NewUi("StorageNetworkPanel", (Transform)(object)gui.m_player);
			val.AddComponent<NetworkPanelMarker>();
			_root = (RectTransform)val.transform;
			RectTransform root = _root;
			RectTransform root2 = _root;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(1f, 1f);
			root2.anchorMax = val2;
			root.anchorMin = val2;
			_root.pivot = new Vector2(0f, 1f);
			_root.anchoredPosition = new Vector2(14f, 0f);
			_root.sizeDelta = new Vector2(_width, 620f);
			((Graphic)UiKit.Panel(val, new Color(0.29f, 0.2f, 0.14f, 0.97f))).raycastTarget = true;
			VerticalLayoutGroup obj = val.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj).padding = new RectOffset(20, 20, 16, 20);
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 8f;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			Transform transform = UiKit.Row((Transform)(object)_root, 34f).transform;
			UiKit.Layout(UiKit.NewUi("Spacer", transform), -1f, 34f);
			UiKit.Layout((Component)(object)UiKit.Label(transform, "STORAGE NETWORK", 26f, UiKit.Orange, norse: true, (TextAlignmentOptions)514), -1f, -1f, 1f);
			_lockButton = UiKit.IconButton(transform, UiKit.LockSprite(closed: false), 34f, ToggleLock, out _lockIcon);
			Transform transform2 = UiKit.Row((Transform)(object)_root, 30f, 4f).transform;
			_roleButtons = (Button[])(object)new Button[3]
			{
				UiKit.MakeButton(transform2, "None", delegate
				{
					SetRole(ChestRole.None);
				}, -1f, 30f, 16f),
				UiKit.MakeButton(transform2, "Input", delegate
				{
					SetRole(ChestRole.Input);
				}, -1f, 30f, 16f),
				UiKit.MakeButton(transform2, "Storage", delegate
				{
					SetRole(ChestRole.Storage);
				}, -1f, 30f, 16f)
			};
			UiKit.Divider((Transform)(object)_root);
			BuildNoneSection();
			BuildStorageSection();
			BuildInputSection();
			val.SetActive(false);
		}

		private void BuildNoneSection()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			_noneSection = UiKit.Column((Transform)(object)_root, 8f, "None");
			UiKit.Layout(_noneSection, -1f, -1f, -1f, 1f);
			UiKit.Label(_noneSection.transform, "<color=#FFB04A>Input</color>: dump items here. They're sent to matching storage chests when you close it.\n\n<color=#FFB04A>Storage</color>: receives items whose tags match this chest's tags.", 17f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513);
		}

		private void BuildStorageSection()
		{
			//IL_0058: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			_storageSection = UiKit.Column((Transform)(object)_root, 8f, "Storage");
			UiKit.Layout(_storageSection, -1f, -1f, -1f, 1f);
			Transform transform = _storageSection.transform;
			_storageInfo = (TMP_Text)(object)UiKit.Label(transform, "", 15f, UiKit.Muted, norse: false, (TextAlignmentOptions)513);
			UiKit.Label(transform, "Chest tags (comma separated)", 18f, UiKit.Orange, norse: false, (TextAlignmentOptions)513);
			_storageTags = UiKit.MakeInput(transform, "e.g. PlainsFood, PlainsMobDrops");
			_inputs.Add(_storageTags);
			Transform transform2 = UiKit.Row(transform, 34f).transform;
			UiKit.MakeButton(transform2, "Apply", delegate
			{
				ChestConfig.SetTags(_current, TagDatabase.ParseList(_storageTags.text));
				_storageTags.text = string.Join(", ", ChestConfig.GetTags(_current).ToArray());
				Unfocus();
				RefreshSoon();
			});
			UiKit.MakeButton(transform2, "Revert", delegate
			{
				_storageTags.text = string.Join(", ", ChestConfig.GetTags(_current).ToArray());
				Unfocus();
			});
			UiKit.Label(transform, "Tip: '" + Plugin.OverflowTag.Value + "' makes this an overflow chest. An item's prefab name (e.g. BlackMetalScrap) as a tag targets that exact item. Click a tag below to add it.", 14f, UiKit.Muted, norse: false, (TextAlignmentOptions)513);
			_storageChips = UiKit.MakeScroll(transform, 120f, out var _, 64f);
			AddChipGrid(_storageChips);
		}

		private void BuildInputSection()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			_inputSection = UiKit.Column((Transform)(object)_root, 8f, "Input");
			UiKit.Layout(_inputSection, -1f, -1f, -1f, 1f);
			Transform transform = _inputSection.transform;
			Transform transform2 = UiKit.Row(transform, 30f).transform;
			_info = (TMP_Text)(object)UiKit.Label(transform2, "", 16f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513);
			_info.alignment = (TextAlignmentOptions)4097;
			UiKit.Layout((Component)(object)_info, -1f, -1f, 1f);
			UiKit.StyleAction(UiKit.MakeButton(transform2, "Sort now", delegate
			{
				SortService.SortInput(_current, quiet: false);
				RefreshSoon();
			}, 120f, 30f, 16f));
			Transform transform3 = UiKit.Row(transform, 30f, 4f).transform;
			_tabButtons = (Button[])(object)new Button[3]
			{
				UiKit.MakeButton(transform3, "Overview", delegate
				{
					SetTab(Tab.Overview);
				}, -1f, 30f, 16f),
				UiKit.MakeButton(transform3, "Item tags", delegate
				{
					SetTab(Tab.ItemTags);
				}, -1f, 30f, 16f),
				UiKit.MakeButton(transform3, "Range", delegate
				{
					SetTab(Tab.Range);
				}, -1f, 30f, 16f)
			};
			_tabPages = (GameObject[])(object)new GameObject[3]
			{
				BuildOverviewPage(transform),
				BuildItemTagsPage(transform),
				BuildRangePage(transform)
			};
			SetTab(_tab);
		}

		private GameObject BuildOverviewPage(Transform parent)
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = UiKit.Column(parent, 6f, "Overview");
			UiKit.Layout(obj, -1f, -1f, -1f, 1f);
			Transform transform = obj.transform;
			Transform transform2 = UiKit.Row(transform, 34f).transform;
			_ovSearch = UiKit.MakeInput(transform2, "Search items");
			((UnityEvent<string>)(object)_ovSearch.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				RefreshOverviewSlots();
			});
			_inputs.Add(_ovSearch);
			_ovSort = UiKit.MakeButton(transform2, "By name", delegate
			{
				_ovByCount = !_ovByCount;
				UiKit.SetButtonText(_ovSort, _ovByCount ? "By count" : "By name");
				RefreshOverviewSlots();
			}, 110f, 34f, 15f);
			_ovContent = UiKit.MakeScroll(transform, 140f, out var _, UiKit.SlotSize.y + 4f);
			GridLayoutGroup obj2 = ((Component)_ovContent).gameObject.AddComponent<GridLayoutGroup>();
			obj2.cellSize = UiKit.SlotSize;
			obj2.spacing = new Vector2(4f, 4f);
			((LayoutGroup)obj2).padding = new RectOffset(2, 2, 2, 2);
			obj2.constraint = (Constraint)1;
			obj2.constraintCount = 6;
			_ovEmpty = (TMP_Text)(object)UiKit.Label(transform, "", 15f, UiKit.Muted, norse: false, (TextAlignmentOptions)513);
			_ovHover = (TMP_Text)(object)UiKit.Label(transform, " ", 15f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513);
			UiKit.Layout((Component)(object)_ovHover, 20f);
			Transform transform3 = UiKit.Row(transform, 34f).transform;
			_ovFooter = (TMP_Text)(object)UiKit.Label(transform3, "", 14f, UiKit.Muted, norse: false, (TextAlignmentOptions)513);
			_ovFooter.alignment = (TextAlignmentOptions)4097;
			UiKit.Layout((Component)(object)_ovFooter, -1f, -1f, 1f);
			_ovStop = UiKit.MakeButton(transform3, "Stop", delegate
			{
				FlashManager.Clear();
				UpdateSlotSelection();
			}, 80f, 34f, 15f);
			return obj;
		}

		private GameObject BuildItemTagsPage(Transform parent)
		{
			//IL_0043: 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_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Expected O, but got Unknown
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = UiKit.Column(parent, 6f, "ItemTags");
			UiKit.Layout(obj, -1f, -1f, -1f, 1f);
			Transform transform = obj.transform;
			_tagStatus = (TMP_Text)(object)UiKit.Label(transform, "", 14f, UiKit.Warn, norse: false, (TextAlignmentOptions)513);
			_tagSearch = UiKit.MakeInput(transform, "Search all items (2+ letters)");
			((UnityEvent<string>)(object)_tagSearch.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				RebuildTagList();
			});
			_inputs.Add(_tagSearch);
			_tagList = UiKit.MakeScroll(transform, 110f, out var _, 90f);
			VerticalLayoutGroup obj2 = ((Component)_tagList).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 2f;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			_editor = UiKit.Column(transform, 6f, "Editor");
			Transform transform2 = _editor.transform;
			_editorTitle = (TMP_Text)(object)UiKit.Label(transform2, "", 20f, UiKit.Orange, norse: true, (TextAlignmentOptions)513);
			_editorTags = UiKit.MakeInput(transform2, "Tags, comma separated");
			_inputs.Add(_editorTags);
			Transform transform3 = UiKit.Row(transform2, 34f).transform;
			UiKit.MakeButton(transform3, "Save", delegate
			{
				if (GlobalItemTags.Ready && _selectedPrefab != null)
				{
					GlobalItemTags.Set(_selectedPrefab, TagDatabase.ParseList(_editorTags.text));
					Unfocus();
					UpdateEditorState();
				}
			});
			UiKit.MakeButton(transform3, "Reset to defaults", delegate
			{
				if (GlobalItemTags.Ready && _selectedPrefab != null)
				{
					GlobalItemTags.Set(_selectedPrefab, null);
					SelectItem(_selectedPrefab);
				}
			});
			UiKit.Label(transform2, "Item tags apply to every input chest in this world and replace the item's default tags.", 13f, UiKit.Muted, norse: false, (TextAlignmentOptions)513);
			GameObject val = UiKit.NewUi("Chips", transform2);
			_editorChips = (RectTransform)val.transform;
			AddChipGrid(_editorChips);
			_editorPreview = (TMP_Text)(object)UiKit.Label(transform2, "", 15f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513);
			_editor.SetActive(false);
			return obj;
		}

		private GameObject BuildRangePage(Transform parent)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Expected O, but got Unknown
			//IL_0251: 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_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = UiKit.Column(parent, 8f, "Range");
			UiKit.Layout(obj, -1f, -1f, -1f, 1f);
			Transform transform = obj.transform;
			_rangeCurrent = (TMP_Text)(object)UiKit.Label(transform, "", 19f, UiKit.Orange, norse: false, (TextAlignmentOptions)513);
			Transform transform2 = UiKit.Row(transform, 34f).transform;
			UiKit.MakeButton(transform2, "-", delegate
			{
				SetPendingRange(_pendingRange - 1f);
			}, 38f, 34f, 20f);
			_rangeSlider = UiKit.MakeSlider(transform2, 2f, 100f, delegate(float v)
			{
				SetPendingRange(v);
			});
			if ((Object)(object)_rangeSlider == (Object)null)
			{
				UiKit.Layout(UiKit.NewUi("Spacer", transform2), -1f, -1f, 1f);
			}
			UiKit.MakeButton(transform2, "+", delegate
			{
				SetPendingRange(_pendingRange + 1f);
			}, 38f, 34f, 20f);
			_rangeValue = (TMP_Text)(object)UiKit.Label(transform2, "", 19f, UiKit.Orange, norse: false, (TextAlignmentOptions)4100);
			UiKit.Layout((Component)(object)_rangeValue, -1f, 64f);
			_rangeChange = (TMP_Text)(object)UiKit.Label(transform, " ", 15f, UiKit.Muted, norse: false, (TextAlignmentOptions)513);
			_rangeButtons = UiKit.Row(transform, 36f);
			_rangeSave = UiKit.MakeButton(_rangeButtons.transform, "Save range", delegate
			{
				TryApplyRange(_pendingRange, isDefault: false);
			});
			_rangeDefault = UiKit.MakeButton(_rangeButtons.transform, "Use default", delegate
			{
				TryApplyRange(ChestConfig.DefaultRange, isDefault: true);
			});
			_rangeConfirm = UiKit.Column(transform, 8f, "Confirm");
			((LayoutGroup)_rangeConfirm.GetComponent<VerticalLayoutGroup>()).padding = new RectOffset(12, 12, 10, 12);
			((Graphic)_rangeConfirm.AddComponent<Image>()).color = new Color(0.08f, 0.05f, 0.03f, 0.85f);
			UiKit.Layout((Component)(object)UiKit.Label(_rangeConfirm.transform, "Lower the range?", 22f, UiKit.Orange, norse: true, (TextAlignmentOptions)514), 28f);
			_confirmText = (TMP_Text)(object)UiKit.Label(_rangeConfirm.transform, "", 15f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513);
			Transform transform3 = UiKit.Row(_rangeConfirm.transform, 34f).transform;
			UiKit.MakeButton(transform3, "Lower range", delegate
			{
				CommitRange(_pendingRange, _confirmIsDefault);
			}, -1f, 34f, 16f);
			UiKit.MakeButton(transform3, "Cancel", delegate
			{
				_rangeConfirm.SetActive(false);
				SetPendingRange(ChestConfig.GetRange(_current));
			}, -1f, 34f, 16f);
			UiKit.MakeButton(_rangeConfirm.transform, "Make these chests flash", delegate
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				List<ZDOID> list = new List<ZDOID>();
				foreach (SortService.Target item in _dropped)
				{
					if (ChestConfig.TryGetId(item.Container, out var id))
					{
						list.Add(id);
					}
				}
				FlashManager.Set(null, list);
			}, -1f, 32f, 15f);
			_rangeConfirm.SetActive(false);
			UiKit.Label(transform, $"Storage chests within this distance of the input chest belong to its network ({2f:0}–{100f:0} m).", 14f, UiKit.Muted, norse: false, (TextAlignmentOptions)513);
			return obj;
		}

		private static void AddChipGrid(RectTransform content)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			GridLayoutGroup obj = ((Component)content).gameObject.AddComponent<GridLayoutGroup>();
			obj.constraint = (Constraint)1;
			obj.constraintCount = 3;
			obj.spacing = new Vector2(4f, 4f);
			((LayoutGroup)obj).padding = new RectOffset(2, 2, 2, 2);
			obj.cellSize = new Vector2(128f, 28f);
		}

		private void FitChipCells(RectTransform content)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			GridLayoutGroup component = ((Component)content).GetComponent<GridLayoutGroup>();
			Rect rect = content.rect;
			float num = ((Rect)(ref rect)).width;
			if (num < 60f)
			{
				num = _width - 60f;
			}
			component.cellSize = new Vector2(Mathf.Floor((num - 4f - 8f) / 3f), 28f);
		}

		private void ToggleLock()
		{
			if (!((Object)(object)_current == (Object)null))
			{
				ChestConfig.SetLocked(_current, !ChestConfig.IsLocked(_current));
				RefreshSoon();
			}
		}

		private void SetRole(ChestRole role)
		{
			if (!((Object)(object)_current == (Object)null) && ChestConfig.SetRole(_current, role))
			{
				_pendingRange = ChestConfig.GetRange(_current);
				RefreshSoon();
			}
		}

		private void SetTab(Tab tab)
		{
			_tab = tab;
			for (int i = 0; i < _tabPages.Length; i++)
			{
				_tabPages[i].SetActive(i == (int)tab);
			}
			for (int j = 0; j < _tabButtons.Length; j++)
			{
				UiKit.SetActiveStyle(_tabButtons[j], j == (int)tab);
			}
			Unfocus();
			if ((Object)(object)_current != (Object)null && tab == Tab.Range)
			{
				_rangeConfirm.SetActive(false);
				SetPendingRange(ChestConfig.GetRange(_current));
			}
		}

		private void RefreshSoon()
		{
			_nextRefresh = 0f;
		}

		private void Refresh()
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			_nextRefresh = Time.unscaledTime + 1f;
			_seenRevision = GlobalItemTags.Revision;
			if ((Object)(object)_current == (Object)null)
			{
				return;
			}
			GlobalItemTags.MigrateLegacy(_current);
			ChestRole role = ChestConfig.GetRole(_current);
			bool flag = ChestConfig.IsLocked(_current);
			for (int i = 0; i < _roleButtons.Length; i++)
			{
				UiKit.SetActiveStyle(_roleButtons[i], i == (int)role);
				((Selectable)_roleButtons[i]).interactable = !flag || i == (int)role;
			}
			_lockIcon.sprite = UiKit.LockSprite(flag);
			((Graphic)_lockIcon).color = (Color)(flag ? UiKit.Orange : new Color(UiKit.Muted.r, UiKit.Muted.g, UiKit.Muted.b, 0.75f));
			_noneSection.SetActive(role == ChestRole.None);
			_storageSection.SetActive(role == ChestRole.Storage);
			_inputSection.SetActive(role == ChestRole.Input);
			float num = ((role == ChestRole.Input) ? ChestConfig.GetRange(_current) : ChestConfig.DefaultRange);
			HashSet<string> hashSet = TagDatabase.NewSet();
			hashSet.UnionWith(GlobalItemTags.AllUsedTags());
			int num2 = 0;
			foreach (Container item in ContainerTracker.InRange(((Component)_current).transform.position, num))
			{
				if (!((Object)(object)item == (Object)(object)_current) && ChestConfig.GetRole(item) == ChestRole.Storage)
				{
					num2++;
					hashSet.UnionWith(ChestConfig.GetTags(item));
				}
			}
			_nearbyTags = hashSet.OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase).ToList();
			HashSet<string> hashSet2 = TagDatabase.NewSet();
			HashSet<string> hashSet3 = TagDatabase.NewSet();
			_chestItems = new List<KeyValuePair<string, string>>();
			Inventory inventory = _current.GetInventory();
			if (inventory != null)
			{
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					string text = TagDatabase.PrefabName(allItem);
					if (hashSet2.Add(text))
					{
						_chestItems.Add(new KeyValuePair<string, string>(text, TagDatabase.DisplayName(allItem)));
						hashSet3.UnionWith(TagDatabase.GetDefaultTags(text));
					}
				}
			}
			_chestItems.Sort((KeyValuePair<string, string> a, KeyValuePair<string, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase));
			_contentTags = hashSet3.OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase).ToList();
			switch (role)
			{
			case ChestRole.Storage:
				RefreshStorage();
				break;
			case ChestRole.Input:
				_info.text = string.Format("{0} storage chest{1} within <color=#FFB04A>{2:0} m</color>", num2, (num2 == 1) ? "" : "s", num);
				_overview = SortService.BuildOverview(_current);
				RefreshOverviewSlots();
				RefreshItemTags();
				RefreshRange();
				break;
			}
		}

		private void RefreshStorage()
		{
			int num = SortService.InputsCovering(_current);
			_storageInfo.text = ((num == 0) ? "Not in range of any input chest." : string.Format("Part of {0} input chest network{1}.", num, (num == 1) ? "" : "s"));
			List<string> tags = _nearbyTags.Take(30).Concat(_contentTags.Take(60)).Distinct<string>(StringComparer.OrdinalIgnoreCase)
				.ToList();
			RebuildChips(_storageChips, tags, ref _storageChipsKey, delegate(string tag)
			{
				_storageTags.text = AddTag(_storageTags.text, tag);
			});
		}

		private void RebuildChips(RectTransform content, List<string> tags, ref string key, Action<string> onPick)
		{
			string text = string.Join("|", tags.ToArray());
			if (text == key)
			{
				return;
			}
			key = text;
			FitChipCells(content);
			UiKit.Clear((Transform)(object)content);
			foreach (string tag in tags)
			{
				string captured = tag;
				UiKit.FlatButton((Transform)(object)content, tag, delegate
				{
					onPick(captured);
				}, 28f, 14f, (TextAlignmentOptions)514);
			}
		}

		private static string AddTag(string buffer, string tag)
		{
			List<string> list = TagDatabase.ParseList(buffer);
			if (!list.Contains<string>(tag, StringComparer.OrdinalIgnoreCase))
			{
				list.Add(tag);
			}
			return string.Join(", ", list.ToArray());
		}

		private void RefreshOverviewSlots()
		{
			if ((Object)(object)_ovContent == (Object)null)
			{
				return;
			}
			_ovByPrefab.Clear();
			foreach (SortService.OverviewEntry item in _overview)
			{
				_ovByPrefab[item.Prefab] = item;
			}
			string q = _ovSearch.text.Trim();
			IEnumerable<SortService.OverviewEntry> source = _overview;
			if (q.Length > 0)
			{
				source = source.Where((SortService.OverviewEntry e) => e.Display.IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0 || e.Prefab.IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0);
			}
			source = (_ovByCount ? source.OrderByDescending((SortService.OverviewEntry e) => e.Count).ThenBy<SortService.OverviewEntry, string>((SortService.OverviewEntry e) => e.Display, StringComparer.OrdinalIgnoreCase) : source.OrderBy<SortService.OverviewEntry, string>((SortService.OverviewEntry e) => e.Display, StringComparer.OrdinalIgnoreCase));
			List<SortService.OverviewEntry> list = source.ToList();
			while (_slots.Count < list.Count)
			{
				UiKit.Slot slot = UiKit.MakeSlot((Transform)(object)_ovContent);
				slot.Clicked = OnSlotClicked;
				slot.Hovered = OnSlotHovered;
				_slots.Add(slot);
			}
			for (int num = 0; num < _slots.Count; num++)
			{
				UiKit.Slot slot2 = _slots[num];
				if (num >= list.Count)
				{
					((Component)slot2).gameObject.SetActive(false);
					continue;
				}
				SortService.OverviewEntry overviewEntry = list[num];
				((Component)slot2).gameObject.SetActive(true);
				slot2.Prefab = overviewEntry.Prefab;
				if ((Object)(object)slot2.Icon != (Object)null)
				{
					ItemData val = TagDatabase.FindItemData(overviewEntry.Prefab);
					Sprite val2 = ((val != null) ? val.GetIcon() : null);
					slot2.Icon.sprite = val2;
					((Behaviour)slot2.Icon).enabled = (Object)(object)val2 != (Object)null;
				}
				if ((Object)(object)slot2.Amount != (Object)null)
				{
					slot2.Amount.text = overviewEntry.Count.ToString();
				}
				if ((Object)(object)slot2.Corner != (Object)null)
				{
					slot2.Corner.text = "x" + overviewEntry.Chests.Count;
				}
				slot2.SetSelected(FlashManager.IsSelected(overviewEntry.Prefab));
			}
			_ovEmpty.text = ((_overview.Count == 0) ? "The storage chests in this network are empty." : ((list.Count == 0) ? "No items match your search." : ""));
			((Component)_ovEmpty).gameObject.SetActive(_ovEmpty.text.Length > 0);
		}

		private void UpdateSlotSelection()
		{
			foreach (UiKit.Slot slot in _slots)
			{
				if (((Component)slot).gameObject.activeSelf)
				{
					slot.SetSelected(FlashManager.IsSelected(slot.Prefab));
				}
			}
		}

		private void OnSlotHovered(UiKit.Slot slot, bool enter)
		{
			if (!enter || slot.Prefab == null || !_ovByPrefab.TryGetValue(slot.Prefab, out var value))
			{
				_ovHover.text = " ";
				return;
			}
			int count = value.Chests.Count;
			_ovHover.text = string.Format("<color=#FFB04A>{0}</color>: {1:N0} in {2} chest{3}", value.Display, value.Count, count, (count == 1) ? "" : "s");
		}

		private void OnSlotClicked(UiKit.Slot slot, bool additive)
		{
			string prefab = slot.Prefab;
			if (prefab == null)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(FlashManager.SelectedPrefabs, StringComparer.OrdinalIgnoreCase);
			if (additive)
			{
				if (!hashSet.Remove(prefab))
				{
					hashSet.Add(prefab);
				}
			}
			else if (hashSet.Count == 1 && hashSet.Contains(prefab))
			{
				hashSet.Clear();
			}
			else
			{
				hashSet.Clear();
				hashSet.Add(prefab);
			}
			HashSet<ZDOID> hashSet2 = new HashSet<ZDOID>();
			foreach (SortService.OverviewEntry item in _overview)
			{
				if (hashSet.Contains(item.Prefab))
				{
					hashSet2.UnionWith(item.Chests);
				}
			}
			if (hashSet.Count == 0)
			{
				FlashManager.Clear();
			}
			else
			{
				FlashManager.Set(hashSet, hashSet2);
			}
			UpdateSlotSelection();
		}

		private void UpdateFooter()
		{
			if (!((Object)(object)_ovFooter == (Object)null) && _inputSection.activeSelf)
			{
				int flashingCount = FlashManager.FlashingCount;
				string text = ((flashingCount > 0) ? string.Format("{0} chest{1} flashing until opened.", flashingCount, (flashingCount == 1) ? " is" : "s are") : "Click an item to make its chests flash. Ctrl+Click to select several.");
				if (_ovFooter.text != text)
				{
					_ovFooter.text = text;
					UpdateSlotSelection();
				}
				if (((Component)_ovStop).gameObject.activeSelf != flashingCount > 0)
				{
					((Component)_ovStop).gameObject.SetActive(flashingCount > 0);
				}
			}
		}

		private void RefreshItemTags()
		{
			string statusText = GlobalItemTags.StatusText;
			_tagStatus.text = statusText ?? "";
			((Component)_tagStatus).gameObject.SetActive(statusText != null);
			RebuildTagList();
			if (_selectedPrefab != null)
			{
				UpdateEditorState();
			}
		}

		private void RebuildTagList()
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			string text = _tagSearch.text.Trim();
			List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
			string text3;
			if (text.Length >= 2)
			{
				foreach (ItemDrop item in TagDatabase.AllItems())
				{
					string name = ((Object)((Component)item).gameObject).name;
					string text2 = TagDatabase.DisplayName(item.m_itemData);
					if (name.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						list.Add(new KeyValuePair<string, string>(name, text2));
						if (list.Count >= 60)
						{
							break;
						}
					}
				}
				list.Sort((KeyValuePair<string, string> a, KeyValuePair<string, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase));
				text3 = ((list.Count == 0) ? "No items found." : null);
			}
			else
			{
				list = _chestItems;
				text3 = ((list.Count == 0) ? "This chest is empty. Search to tag any item." : "In this chest:");
			}
			string text4 = text + "#" + _selectedPrefab + "#" + string.Join("|", list.Select((KeyValuePair<string, string> r) => r.Key).ToArray());
			if (text4 == _tagListKey)
			{
				return;
			}
			_tagListKey = text4;
			UiKit.Clear((Transform)(object)_tagList);
			if (text3 != null)
			{
				UiKit.Layout((Component)(object)UiKit.Label((Transform)(object)_tagList, text3, 14f, UiKit.Muted, norse: false, (TextAlignmentOptions)513), 22f);
			}
			foreach (KeyValuePair<string, string> item2 in list)
			{
				string prefab = item2.Key;
				bool flag = string.Equals(prefab, _selectedPrefab, StringComparison.OrdinalIgnoreCase);
				string text5 = (flag ? "<color=#FFB04A>" : "") + item2.Value + (flag ? "</color>" : "") + "  <color=#A8987E><size=80%>" + prefab + "</size></color>";
				UiKit.FlatButton((Transform)(object)_tagList, text5, delegate
				{
					SelectItem(prefab);
				}, 28f, 15f, (TextAlignmentOptions)4097);
			}
		}

		private void SelectItem(string prefab)
		{
			_selectedPrefab = prefab;
			SortService.ItemTags itemTags = SortService.ResolveTags(prefab);
			List<string> tags;
			HashSet<string> source = (GlobalItemTags.TryGet(prefab, out tags) ? itemTags.User : itemTags.Defaults);
			_editorTags.text = string.Join(", ", source.OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase).ToArray());
			_editor.SetActive(true);
			Unfocus();
			UpdateEditorState();
			RebuildTagList();
		}

		private void UpdateEditorState()
		{
			if (_selectedPrefab != null)
			{
				ItemData val = TagDatabase.FindItemData(_selectedPrefab);
				string text = ((val != null) ? TagDatabase.DisplayName(val) : _selectedPrefab);
				List<string> tags;
				bool flag = GlobalItemTags.TryGet(_selectedPrefab, out tags);
				_editorTitle.text = text + (flag ? "  <size=65%><color=#CDB898>custom tags</color></size>" : "  <size=65%><color=#CDB898>default tags</color></size>");
				_editorPreview.text = SortService.Preview(_current, _selectedPrefab);
				RebuildChips(_editorChips, _nearbyTags.Take(12).ToList(), ref _editorChipsKey, delegate(string tag)
				{
					_editorTags.text = AddTag(_editorTags.text, tag);
				});
			}
		}

		private void RefreshRange()
		{
			float range = ChestConfig.GetRange(_current);
			bool flag = ChestConfig.HasCustomRange(_current);
			_rangeCurrent.text = $"Current range: {range:0} m" + (flag ? "" : "  <size=75%><color=#CDB898>(default)</color></size>");
			UiKit.SetButtonText(_rangeDefault, $"Use default ({ChestConfig.DefaultRange:0} m)");
			((Selectable)_rangeDefault).interactable = flag;
			UpdateRangePreview();
		}

		private void SetPendingRange(float value)
		{
			_pendingRange = Mathf.Clamp(Mathf.Round(value), 2f, 100f);
			if (_rangeConfirm.activeSelf)
			{
				_rangeConfirm.SetActive(false);
			}
			UpdateRangePreview();
		}

		private void UpdateRangePreview()
		{
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_current == (Object)null))
			{
				float range = ChestConfig.GetRange(_current);
				if ((Object)(object)_rangeSlider != (Object)null)
				{
					_rangeSlider.SetValueWithoutNotify(_pendingRange);
				}
				_rangeValue.text = $"{_pendingRange:0} m";
				_dropped = ((_pendingRange < range) ? SortService.StorageBetween(_current, _pendingRange, range) : new List<SortService.Target>());
				_gained = ((_pendingRange > range) ? SortService.StorageBetween(_current, range, _pendingRange).Count : 0);
				if (_pendingRange < range)
				{
					((Graphic)_rangeChange).color = ((_dropped.Count > 0) ? UiKit.Warn : UiKit.Muted);
					_rangeChange.text = ((_dropped.Count == 0) ? "No storage chests would leave the network." : string.Format("{0} storage chest{1} would leave the network.", _dropped.Count, (_dropped.Count == 1) ? "" : "s"));
				}
				else if (_pendingRange > range)
				{
					((Graphic)_rangeChange).color = UiKit.Muted;
					_rangeChange.text = ((_gained == 0) ? "No extra storage chests in that range." : string.Format("{0} more storage chest{1} would join the network.", _gained, (_gained == 1) ? "" : "s"));
				}
				else
				{
					_rangeChange.text = " ";
				}
				((Selectable)_rangeSave).interactable = Mathf.Abs(_pendingRange - range) > 0.01f;
				_rangeButtons.SetActive(!_rangeConfirm.activeSelf);
			}
		}

		private void TryApplyRange(float target, bool isDefault)
		{
			float range = ChestConfig.GetRange(_current);
			_pendingRange = target;
			UpdateRangePreview();
			if (target < range - 0.01f && _dropped.Count > 0)
			{
				_confirmIsDefault = isDefault;
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append(string.Format("Going from {0:0} m to {1:0} m removes {2} storage chest{3} from this network:\n", range, target, _dropped.Count, (_dropped.Count == 1) ? "" : "s"));
				foreach (SortService.Target item in _dropped.Take(6))
				{
					stringBuilder.Append("  • ").Append(item.Label()).Append('\n');
				}
				if (_dropped.Count > 6)
				{
					stringBuilder.Append($"  …and {_dropped.Count - 6} more\n");
				}
				stringBuilder.Append("Their items stay where they are, but this input chest won't send anything there anymore.");
				_confirmText.text = stringBuilder.ToString();
				_rangeConfirm.SetActive(true);
				_rangeButtons.SetActive(false);
			}
			else
			{
				CommitRange(target, isDefault);
			}
		}

		private void CommitRange(float target, bool isDefault)
		{
			ChestConfig.SetRange(_current, isDefault ? 0f : target);
			_rangeConfirm.SetActive(false);
			_pendingRange = ChestConfig.GetRange(_current);
			RefreshSoon();
			RefreshRange();
		}
	}
	internal class NetworkWindow : MonoBehaviour
	{
		private enum InputTab
		{
			Overview,
			ItemTags,
			Range
		}

		internal static bool IsTyping;

		private const int WindowId = 23166;

		private const float Width = 400f;

		private Rect _rect = new Rect(-1f, 90f, 400f, 10f);

		private bool _collapsed;

		private InputTab _tab;

		private Container _current;

		private float _nextRefresh;

		private int _seenRevision = -1;

		private int _storageCount;

		private List<string> _nearbyTags = new List<string>();

		private List<string> _contentTags = new List<string>();

		private string _chestTagsBuf = "";

		private int _coveringInputs;

		private Vector2 _chipScroll;

		private string _search = "";

		private string _lastSearch;

		private string _selectedPrefab;

		private string _itemTagsBuf = "";

		private string _preview = "";

		private bool _isCustom;

		private Vector2 _itemScroll;

		private List<KeyValuePair<string, string>> _chestItems = new List<KeyValuePair<string, string>>();

		private readonly List<KeyValuePair<string, string>> _searchItems = new List<KeyValuePair<string, string>>();

		private List<SortService.OverviewEntry> _overview = new List<SortService.OverviewEntry>();

		private string _ovSearch = "";

		private string _ovSearchApplied = "";

		private bool _ovSortByCount;

		private Vector2 _ovScroll;

		private float _pendingRange;

		private float _previewedRange = -1f;

		private List<SortService.Target> _dropped = new List<SortService.Target>();

		private int _gained;

		private bool _confirmLower;

		private bool _confirmIsDefault;

		private GUIStyle _wrap;

		private GUIStyle _header;

		private GUIStyle _small;

		private GUIStyle _chip;

		private GUIStyle _warn;

		private GUIStyle _row;

		private GUIStyle _rowSel;

		private GUIStyle _rowText;

		private GUIStyle _rowRight;

		private static bool IsLayout
		{
			get
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Invalid comparison between Unknown and I4
				if (Event.current != null)
				{
					return (int)Event.current.type == 8;
				}
				return false;
			}
		}

		private void OnGUI()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			Container val = ((Plugin.ClassicPanel.Value || NetworkPanel.Failed) ? VisibleContainer() : null);
			if ((Object)(object)val == (Object)null)
			{
				IsTyping = false;
				_current = null;
				return;
			}
			if ((Object)(object)val != (Object)(object)_current)
			{
				ResetFor(val);
			}
			InitStyles();
			float num = (float)Screen.height / 1080f * Plugin.UiScale.Value;
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
			if (((Rect)(ref _rect)).x < 0f)
			{
				((Rect)(ref _rect)).x = (float)Screen.width / num - 400f - 30f;
			}
			((Rect)(ref _rect)).height = 10f;
			_rect = GUILayout.Window(23166, _rect, new WindowFunction(DrawWindow), "Storage Network 1.0.0", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(400f) });
			string nameOfFocusedControl = GUI.GetNameOfFocusedControl();
			IsTyping = GUIUtility.keyboardControl != 0 && nameOfFocusedControl != null && nameOfFocusedControl.StartsWith("SN_");
		}

		private static Container VisibleContainer()
		{
			if (!Plugin.ShowWindow.Value || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return null;
			}
			if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible())
			{
				return null;
			}
			Container val = Patches.CurrentContainer(InventoryGui.instance);
			if (!((Object)(object)val != (Object)null) || !ChestConfig.IsEligible(val))
			{
				return null;
			}
			return val;
		}

		private void ResetFor(Container c)
		{
			_current = c;
			_chestTagsBuf = string.Join(", ", ChestConfig.GetTags(c).ToArray());
			_selectedPrefab = null;
			_itemTagsBuf = "";
			_preview = "";
			_pendingRange = ChestConfig.GetRange(c);
			_previewedRange = -1f;
			_confirmLower = false;
			_nextRefresh = 0f;
			GUIUtility.keyboardControl = 0;
		}

		private void InitStyles()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_0063: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_00d9: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			//IL_010b: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			//IL_0153: Expected O, but got Unknown
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: 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_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Expected O, but got Unknown
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			if (_wrap == null)
			{
				_wrap = new GUIStyle(GUI.skin.label)
				{
					wordWrap = true
				};
				_small = new GUIStyle(GUI.skin.label)
				{
					wordWrap = true,
					fontSize = 11
				};
				_small.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
				_header = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1
				};
				_header.normal.textColor = new Color(1f, 0.85f, 0.55f);
				_chip = new GUIStyle(GUI.skin.button)
				{
					fontSize = 11,
					padding = new RectOffset(4, 4, 2, 2)
				};
				_warn = new GUIStyle(GUI.skin.box)
				{
					wordWrap = true,
					alignment = (TextAnchor)0,
					padding = new RectOffset(8, 8, 6, 6)
				};
				_warn.normal.textColor = new Color(1f, 0.6f, 0.45f);
				_row = new GUIStyle(GUI.skin.label)
				{
					margin = new RectOffset(0, 0, 1, 1)
				};
				_row.hover.background = MakeTex(new Color(1f, 1f, 1f, 0.08f));
				_row.active.background = MakeTex(new Color(1f, 1f, 1f, 0.15f));
				_rowSel = new GUIStyle(_row);
				_rowSel.normal.background = MakeTex(new Color(1f, 0.75f, 0.2f, 0.28f));
				_rowSel.hover.background = MakeTex(new Color(1f, 0.75f, 0.2f, 0.36f));
				_rowText = new GUIStyle(GUI.skin.label)
				{
					clipping = (TextClipping)1
				};
				_rowRight = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)2
				};
				_rowRight.normal.textColor = new Color(0.85f, 0.85f, 0.85f);
			}
		}

		private static void LayoutChanged()
		{
			GUIUtility.ExitGUI();
		}

		private static Texture2D MakeTex(Color c)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1)
			{
				hideFlags = (HideFlags)61
			};
			val.SetPixel(0, 0, c);
			val.Apply();
			return val;
		}

		private void RefreshIfNeeded()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if (_seenRevision == GlobalItemTags.Revision && Time.unscaledTime < _nextRefresh)
			{
				return;
			}
			_nextRefresh = Time.unscaledTime + 1f;
			_seenRevision = GlobalItemTags.Revision;
			GlobalItemTags.MigrateLegacy(_current);
			ChestRole role = ChestConfig.GetRole(_current);
			float range = ((role == ChestRole.Input) ? ChestConfig.GetRange(_current) : ChestConfig.DefaultRange);
			HashSet<string> hashSet = TagDatabase.NewSet();
			hashSet.UnionWith(GlobalItemTags.AllUsedTags());
			_storageCount = 0;
			foreach (Container item in ContainerTracker.InRange(((Component)_current).transform.position, range))
			{
				if (!((Object)(object)item == (Object)(object)_current) && ChestConfig.GetRole(item) == ChestRole.Storage)
				{
					_storageCount++;
					hashSet.UnionWith(ChestConfig.GetTags(item));
				}
			}
			_nearbyTags = hashSet.OrderBy<string, string>((string t) => t, StringComparer.OrdinalIgnoreCase).ToList();
			HashSet<string> hashSet2 = TagDatabase.NewSet();
			HashSet<string> hashSet3 = TagDatabase.NewSet();
			_chestItems = new List<KeyValuePair<string, string>>();
			Inventory inventory = _current.GetInventory();
			if (inventory != null)
			{
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					string text = TagDatabase.PrefabName(allItem);
					if (hashSet2.Add(text))
					{
						_chestItems.Add(new KeyValuePair<string, string>(text, TagDatabase.DisplayName(allItem)));
						hashSet3.UnionWith(TagDatabase.GetDefaultTags(text));
					}
				}
			}
			_chestItems.Sort((KeyValuePair<string, string> a, KeyValuePair<string, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase));
			_contentTags = hashSet3.OrderBy<string, string>((string t) => t, StringComparer.OrdinalIgnoreCase).ToList();
			switch (role)
			{
			case ChestRole.Input:
				_overview = SortService.BuildOverview(_current);
				if (_selectedPrefab != null)
				{
					UpdateItemState();
				}
				break;
			case ChestRole.Storage:
				_coveringInputs = SortService.InputsCovering(_current);
				break;
			}
		}

		private void DrawWindow(int id)
		{
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			if (IsLayout)
			{
				RefreshIfNeeded();
				UpdateSearch();
				_ovSearchApplied = _ovSearch.Trim();
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label((Localization.instance != null) ? Localization.instance.Localize(_current.m_name) : _current.m_name, _header, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			bool flag = ChestConfig.IsLocked(_current);
			bool flag2 = GUILayout.Toggle(flag, "Lock type", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
			if (flag2 != flag)
			{
				ChestConfig.SetLocked(_current, flag2);
				LayoutChanged();
			}
			if (GUILayout.Button(_collapsed ? "Show" : "Hide", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
			{
				_collapsed = !_collapsed;
				LayoutChanged();
			}
			GUILayout.EndHorizontal();
			if (!_collapsed)
			{
				ChestRole role = ChestConfig.GetRole(_current);
				GUI.enabled = !flag;
				int num = GUILayout.Toolbar((int)role, new string[3] { "Not networked", "Input", "Storage" }, Array.Empty<GUILayoutOption>());
				GUI.enabled = true;
				if (flag)
				{
					num = (int)role;
				}
				if (num != (int)role)
				{
					ChestConfig.SetRole(_current, (ChestRole)num);
					_pendingRange = ChestConfig.GetRange(_current);
					_nextRefresh = 0f;
					LayoutChanged();
				}
				GUILayout.Space(6f);
				switch ((ChestRole)num)
				{
				case ChestRole.Input:
					DrawInput();
					break;
				case ChestRole.Storage:
					DrawStorage();
					break;
				default:
					GUILayout.Label("Input: dump items here; they are sent to matching storage chests when you close it.\nStorage: receives items whose tags match this chest's tags.", _wrap, Array.Empty<GUILayoutOption>());
					break;
				}
			}
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 22f));
		}

		private void DrawStorage()
		{
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be d