Decompiled source of ChestFlow v0.5.9

ChestFlow.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ChestFlow.Core;
using ChestFlow.Runtime;
using HarmonyLib;
using JG224.ModCore.API;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ChestFlow")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.9.0")]
[assembly: AssemblyInformationalVersion("0.5.9")]
[assembly: AssemblyProduct("ChestFlow")]
[assembly: AssemblyTitle("ChestFlow")]
[assembly: AssemblyVersion("0.5.9.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 ChestFlow
{
	[BepInPlugin("com.jg224.chestflow", "ChestFlow", "0.5.9")]
	[BepInDependency("com.jg224.modcore", "0.5.0")]
	[BepInProcess("valheim.exe")]
	[BepInProcess("valheim_server.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("goldenrevolver.quick_stack_store")]
	[BepInIncompatibility("com.maxsch.valheim.MultiUserChest")]
	[BepInIncompatibility("Narolith.AutoFeed")]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string PluginGuid = "com.jg224.chestflow";

		internal const string PluginName = "ChestFlow";

		internal const string PluginVersion = "0.5.9";

		internal const string ModCoreGuid = "com.jg224.modcore";

		internal const int ProtocolVersion = 2;

		internal static readonly ModuleId ModuleId = new ModuleId("chestflow");

		private Harmony? _harmony;

		private IDisposable? _stackInput;

		private IDisposable? _alternateStackInput;

		private readonly List<IDisposable> _registrations = new List<IDisposable>();

		private bool _shutDown;

		internal static Plugin Instance { get; private set; } = null;

		internal static ManualLogSource LogInstance { get; private set; } = null;

		internal static ICoreServices Core { get; private set; } = null;

		internal QuickStackService QuickStackService { get; private set; }

		internal static bool IsActive { get; private set; }

		private void Awake()
		{
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Expected O, but got Unknown
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Expected O, but got Unknown
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			IsActive = false;
			_shutDown = false;
			Instance = this;
			LogInstance = ((BaseUnityPlugin)this).Logger;
			try
			{
				if (!ModCoreApi.IsAvailable)
				{
					throw new InvalidOperationException("ModCore did not initialize before ChestFlow.");
				}
				Core = ModCoreApi.Services;
				SemanticVersion val = default(SemanticVersion);
				if (!SemanticVersion.TryParse("0.5.9", ref val))
				{
					throw new InvalidOperationException("ChestFlow has invalid release version metadata.");
				}
				_registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "com.jg224.chestflow", "ChestFlow", val, 2, (ModuleSide)3, (ModuleRequirement)4, 0uL, 1, 1)));
				_registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)1, "com.jg224.chestflow.", 1, Array.Empty<string>()));
				_registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)6, "com.jg224.chestflow.", 1, Array.Empty<string>()));
				_registrations.Add(RoutedRpcIngress.Register(ModuleId, new string[8] { "ChestFlow_MultiUserHello", "ChestFlow_RequestContainerControl", "ChestFlow_ContainerControlResponse", "ChestFlow_AutoFeedTake", "ChestFlow_AutoFeedTakeResponse", "ChestFlow_AutoFeedFinalize", "ChestFlow_AutoFeedPrepare", "ChestFlow_AutoFeedPrepared" }));
				_registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)2, "com.jg224.chestflow.", 1, Array.Empty<string>()));
				_registrations.Add(Core.Ui.Reserve(new UiReservation(ModuleId, (UiSurface)4, "container-logistics-controls", 20, true)));
				ModConfig.Bind(ConfigFileMigration.Open((BaseUnityPlugin)(object)this, Paths.ConfigPath, ((BaseUnityPlugin)this).Logger));
				ConfigEntry<KeyboardShortcut>[] array = new ConfigEntry<KeyboardShortcut>[2]
				{
					ModConfig.QuickStackShortcut,
					ModConfig.QuickStackAlternateShortcut
				};
				foreach (ConfigEntry<KeyboardShortcut> shortcut in array)
				{
					_registrations.Add(Core.Configuration.Register(new ConfigSettingDescriptor(ModuleId, ((ConfigEntryBase)shortcut).Definition.Section, ((ConfigEntryBase)shortcut).Definition.Key, (ConfigScope)1, (Func<string>)(() => ((ConfigEntryBase)shortcut).GetSerializedValue()), 1)));
					shortcut.SettingChanged += RefreshStackInputRegistrations;
				}
				RefreshStackInputRegistrations();
				QuickStackService = new QuickStackService(this);
				StorageCommands.Register();
				_harmony = new Harmony("com.jg224.chestflow");
				PatchAllSafely();
				IsActive = true;
				Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Required server-authoritative chest logistics hooks ready.");
				((BaseUnityPlugin)this).Logger.LogInfo((object)"ChestFlow 0.5.9 loaded.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0} failed to initialize safely: {1}", "ChestFlow", ex));
				if (Core != null)
				{
					Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message);
				}
				Shutdown();
				throw;
			}
		}

		private void PatchAllSafely()
		{
			Type[] array = (from type2 in typeof(Plugin).Assembly.GetTypes()
				where type2.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0
				select type2).OrderBy<Type, string>((Type type2) => type2.FullName, StringComparer.Ordinal).ToArray();
			int num = 0;
			Type[] array2 = array;
			foreach (Type type in array2)
			{
				try
				{
					_harmony.PatchAll(type);
					num++;
				}
				catch (Exception arg)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to apply patch class {type.FullName}; other ChestFlow features will remain available: {arg}");
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Applied {num} of {array.Length} ChestFlow patch classes.");
		}

		private unsafe void RefreshStackInputRegistrations(object? sender = null, EventArgs? args = null)
		{
			//IL_0037: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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_00d9: Expected O, but got Unknown
			_stackInput?.Dispose();
			_alternateStackInput?.Dispose();
			_stackInput = (_alternateStackInput = null);
			KeyboardShortcut value = ModConfig.QuickStackShortcut.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
			{
				IInputRegistry input = Core.Input;
				ModuleId moduleId = ModuleId;
				value = ModConfig.QuickStackShortcut.Value;
				_stackInput = input.Register(new InputActionDescriptor(moduleId, "QuickStackNearby", ((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).ToString(), "gameplay", 0));
			}
			value = ModConfig.QuickStackAlternateShortcut.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
			{
				IInputRegistry input2 = Core.Input;
				ModuleId moduleId2 = ModuleId;
				value = ModConfig.QuickStackAlternateShortcut.Value;
				_alternateStackInput = input2.Register(new InputActionDescriptor(moduleId2, "QuickStackNearbyAlternate", ((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).ToString(), "gameplay", 0));
			}
		}

		private void Update()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsActive)
			{
				return;
			}
			MultiUserContainerService.Update();
			AutoFeedService.Update();
			NearbyResourceService.RepairInvalidPlayerInventoryPositions();
			if (ChestUpgradeService.UpdateLegacyMigration())
			{
				return;
			}
			ChestRuleEditor.Update();
			InventoryButtons.UpdateVisibility();
			if (ModConfig.Enabled.Value && CanAcceptShortcut())
			{
				if (IsShortcutDownAllowingOtherKeys(ModConfig.QuickStackShortcut.Value) || IsShortcutDownAllowingOtherKeys(ModConfig.QuickStackAlternateShortcut.Value))
				{
					QuickStackNearby();
				}
				KeyboardShortcut value = ModConfig.SortChestShortcut.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					SortOpenChest();
				}
			}
		}

		internal void QuickStackNearby()
		{
			if (!IsActive)
			{
				return;
			}
			try
			{
				QuickStackService.BeginNearbyQuickStack(RestockProfileService.RestockNearby);
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Nearby quick stack failed: {arg}");
			}
		}

		internal void SortOpenChest()
		{
			if (!IsActive)
			{
				return;
			}
			try
			{
				Container val = InventoryAccess.CurrentContainer(InventoryGui.instance);
				if ((Object)(object)val == (Object)null)
				{
					Player localPlayer = Player.m_localPlayer;
					if (localPlayer != null)
					{
						((Character)localPlayer).Message((MessageType)2, "Open a chest to sort it.", 0, (Sprite)null, false);
					}
				}
				else if (!MultiUserContainerService.TryDeferUntilOwned(val, SortOpenChest))
				{
					int num = InventorySorter.Sort(val.GetInventory(), ModConfig.ChestSortMode.Value, ModConfig.SortDescending.Value);
					Player localPlayer2 = Player.m_localPlayer;
					if (localPlayer2 != null)
					{
						((Character)localPlayer2).Message((MessageType)2, string.Format("Sorted {0} item stack{1} by {2}.", num, (num == 1) ? string.Empty : "s", ModConfig.ChestSortMode.Value), 0, (Sprite)null, false);
					}
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Chest sort failed: {arg}");
			}
		}

		internal void UpgradeOpenChest(int targetTier)
		{
			if (!IsActive)
			{
				return;
			}
			try
			{
				Container val = InventoryAccess.CurrentContainer(InventoryGui.instance);
				if (!((Object)(object)val != (Object)null) || !MultiUserContainerService.TryDeferUntilOwned(val, delegate
				{
					UpgradeOpenChest(targetTier);
				}))
				{
					ChestUpgradeService.UpgradeOpenChest(targetTier);
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Chest upgrade failed: {arg}");
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "Chest upgrade failed. See the log for details.", 0, (Sprite)null, false);
				}
			}
		}

		private static bool CanAcceptShortcut()
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			if (ChestRuleEditor.IsOpen)
			{
				return false;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return false;
			}
			if (Console.IsVisible() || Menu.IsVisible() || TextInput.IsVisible())
			{
				return false;
			}
			if ((Object)(object)Minimap.instance != (Object)null && Minimap.InTextInput())
			{
				return false;
			}
			return true;
		}

		private static bool IsShortcutDownAllowingOtherKeys(KeyboardShortcut shortcut)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			KeyCode mainKey = ((KeyboardShortcut)(ref shortcut)).MainKey;
			if ((int)mainKey == 0 || !UnityInput.Current.GetKeyDown(mainKey))
			{
				return false;
			}
			return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((KeyCode modifier) => modifier == mainKey || UnityInput.Current.GetKey(modifier));
		}

		private void OnDestroy()
		{
			Shutdown();
		}

		private void Shutdown()
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			if (_shutDown)
			{
				return;
			}
			_shutDown = true;
			IsActive = false;
			if (ModConfig.QuickStackShortcut != null)
			{
				ModConfig.QuickStackShortcut.SettingChanged -= RefreshStackInputRegistrations;
			}
			if (ModConfig.QuickStackAlternateShortcut != null)
			{
				ModConfig.QuickStackAlternateShortcut.SettingChanged -= RefreshStackInputRegistrations;
			}
			_stackInput?.Dispose();
			_alternateStackInput?.Dispose();
			_stackInput = (_alternateStackInput = null);
			QuickStackService?.Reset();
			MultiUserContainerService.Reset();
			AutoFeedService.Reset();
			InventoryButtons.Detach();
			TransferContext.End();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
			for (int num = _registrations.Count - 1; num >= 0; num--)
			{
				try
				{
					_registrations[num].Dispose();
				}
				catch (Exception ex)
				{
					ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
					if (logger != null)
					{
						logger.LogWarning((object)("Registration cleanup failed: " + ex.Message));
					}
				}
			}
			_registrations.Clear();
			if (Core != null)
			{
				Core.Metrics.RemoveOwner(ModuleId);
			}
			Core = null;
		}
	}
}
namespace ChestFlow.Runtime
{
	internal static class AutoFeedService
	{
		private sealed class ScanCooldown
		{
			internal float Next;
		}

		private sealed class ClientRequest
		{
			internal int Id;

			internal Container Container;

			internal ZDOID Animal;

			internal float Expires;

			internal float RetryAt;
		}

		private sealed class ServerRequest
		{
			internal string Key = "";

			internal int Id;

			internal long Sender;

			internal long Actor;

			internal Container Container;

			internal ZDOID Animal;

			internal long PreviousOwner;

			internal float Expires;

			internal bool Prepared;

			internal byte[]? Inventory;
		}

		internal const string TakeFoodRpc = "ChestFlow_AutoFeedTake";

		internal const string TakeFoodResponseRpc = "ChestFlow_AutoFeedTakeResponse";

		internal const string FinalizeFoodRpc = "ChestFlow_AutoFeedFinalize";

		internal const string PrepareFoodRpc = "ChestFlow_AutoFeedPrepare";

		internal const string PreparedFoodRpc = "ChestFlow_AutoFeedPrepared";

		private const string ReceiptKey = "ChestFlow.AutoFeedReceipt.v1";

		private const string LeaseKey = "ChestFlow.AutoFeedLeaseUntil.v1";

		private const int MaximumInventoryBytes = 65536;

		private static readonly FieldInfo TameableNetViewField = AccessTools.Field(typeof(Tameable), "m_nview");

		private static readonly FieldInfo MonsterAiField = AccessTools.Field(typeof(Tameable), "m_monsterAI");

		private static readonly MethodInfo ConsumedItemMethod = AccessTools.Method(typeof(Tameable), "OnConsumedItem", (Type[])null, (Type[])null);

		private static readonly FieldInfo ContainerNetViewField = AccessTools.Field(typeof(Container), "m_nview");

		private static readonly MethodInfo GetPrefabNameMethod = AccessTools.Method(typeof(ZNetView), "GetPrefabName", (Type[])null, (Type[])null);

		private static readonly MethodInfo InventoryChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", new Type[2]
		{
			typeof(bool),
			typeof(bool)
		}, (Type[])null);

		private static ConditionalWeakTable<Tameable, ScanCooldown> ScanCooldowns = new ConditionalWeakTable<Tameable, ScanCooldown>();

		private static readonly BoundedScanQueue<Tameable> ScanQueue = new BoundedScanQueue<Tameable>(256);

		private static readonly HashSet<Container> LoadedContainers = new HashSet<Container>();

		private static Container[]? _containerSnapshot;

		private static ZNet? _sessionNet;

		private static ZNetScene? _sessionScene;

		private static bool _discoverySeeded;

		private static readonly Stopwatch ScanBudget = new Stopwatch();

		private static Tameable? _scanningAnimal;

		private static Container[]? _scanContainers;

		private static Dictionary<string, ItemDrop>? _scanFood;

		private static int _scanIndex;

		private static Container? _nearestFood;

		private static float _nearestDistance;

		private static readonly Dictionary<int, ClientRequest> ClientRequests = new Dictionary<int, ClientRequest>();

		private static readonly Dictionary<string, ServerRequest> ServerRequests = new Dictionary<string, ServerRequest>(StringComparer.Ordinal);

		private static readonly FeedRequestLedger Receipts = new FeedRequestLedger();

		private static readonly HashSet<ZDOID> BusyAnimals = new HashSet<ZDOID>();

		private static readonly HashSet<ZDOID> BlockedChests = new HashSet<ZDOID>();

		private static readonly Dictionary<long, Queue<float>> RequestRates = new Dictionary<long, Queue<float>>();

		private static int nextRequestId;

		internal static void Attach(Container container)
		{
			EnsureSession();
			TrackContainer(container);
			ZNetView view = GetNetView(container);
			if ((Object)(object)view == (Object)null || !view.IsValid())
			{
				return;
			}
			view.Register<ZPackage>("ChestFlow_AutoFeedTake", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
			{
				ReceiveRequest(container, sender, package);
			});
			view.Register<int, bool>("ChestFlow_AutoFeedTakeResponse", (Action<long, int, bool>)delegate(long sender, int request, bool committed)
			{
				if (Plugin.IsActive && ChestAuthority.IsServerSender(sender) && ClientRequests.TryGetValue(request, out ClientRequest value) && !((Object)(object)value.Container != (Object)(object)container))
				{
					ClientRequests.Remove(request);
					view.InvokeRPC(sender, "ChestFlow_AutoFeedFinalize", new object[2] { request, committed });
				}
			});
			view.Register<int, bool>("ChestFlow_AutoFeedFinalize", (Action<long, int, bool>)delegate
			{
			});
			view.Register<ZPackage>("ChestFlow_AutoFeedPrepare", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
			{
				PrepareInventory(container, sender, package);
			});
			view.Register<ZPackage>("ChestFlow_AutoFeedPrepared", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
			{
				ReceivePrepared(container, sender, package);
			});
		}

		internal static void TryFeed(Tameable tameable)
		{
			if (!Plugin.IsActive)
			{
				return;
			}
			EnsureSession();
			if (!ModConfig.Enabled.Value || !ModConfig.AutoFeedEnabled.Value || (Object)(object)tameable == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			ZNetView animalView = default(ZNetView);
			ref ZNetView reference = ref animalView;
			object? value = TameableNetViewField.GetValue(tameable);
			reference = (ZNetView)((value is ZNetView) ? value : null);
			object? value2 = MonsterAiField.GetValue(tameable);
			MonsterAI val = (MonsterAI)((value2 is MonsterAI) ? value2 : null);
			if (!((Object)(object)animalView == (Object)null) && animalView.IsValid() && animalView.IsOwner() && !((Object)(object)val == (Object)null) && !((BaseAI)val).IsAlerted() && tameable.IsHungry())
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				ScanCooldown value3 = ScanCooldowns.GetValue(tameable, (Tameable _) => new ScanCooldown());
				if (AutoFeedPolicy.ShouldScan(realtimeSinceStartup, value3.Next) && !ClientRequests.Values.Any((ClientRequest request) => request.Animal == animalView.GetZDO().m_uid) && _scanningAnimal != tameable && ScanQueue.Enqueue(tameable))
				{
					value3.Next = realtimeSinceStartup + ModConfig.AutoFeedInterval.Value;
					(((Component)tameable).GetComponent<AutoFeedAnimalTracker>() ?? ((Component)tameable).gameObject.AddComponent<AutoFeedAnimalTracker>()).Animal = tameable;
				}
			}
		}

		private static void UpdateScans()
		{
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			if (!_discoverySeeded)
			{
				Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
				for (int i = 0; i < array.Length; i++)
				{
					TrackContainer(array[i]);
				}
				_discoverySeeded = true;
			}
			if (!ModConfig.Enabled.Value || !ModConfig.AutoFeedEnabled.Value)
			{
				ScanQueue.Clear();
				ClearScan();
				return;
			}
			ScanBudget.Restart();
			int num = 32;
			while (num > 0 && ScanBudget.ElapsedMilliseconds < 2)
			{
				if ((Object)(object)_scanningAnimal == (Object)null)
				{
					ClearScan();
					Tameable val = ScanQueue.Dequeue();
					if ((Object)(object)val == (Object)null)
					{
						if (ScanQueue.Count == 0)
						{
							break;
						}
						num--;
						continue;
					}
					if (!TryGetHungryOwner(val, out ZNetView _, out MonsterAI ai))
					{
						num--;
						continue;
					}
					_scanningAnimal = val;
					_scanFood = AcceptedFood(ai);
					_scanContainers = _containerSnapshot ?? (_containerSnapshot = LoadedContainers.ToArray());
					_nearestDistance = float.MaxValue;
				}
				if (_scanIndex < _scanContainers.Length)
				{
					num--;
					Container val2 = _scanContainers[_scanIndex++];
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					Vector3 val3 = ((Component)val2).transform.position - ((Component)_scanningAnimal).transform.position;
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					if (!(sqrMagnitude >= _nearestDistance) && !(sqrMagnitude > ModConfig.AutoFeedRange.Value * ModConfig.AutoFeedRange.Value))
					{
						long num2;
						if (!ZNet.instance.IsServer())
						{
							Player localPlayer = Player.m_localPlayer;
							num2 = ((localPlayer != null) ? localPlayer.GetPlayerID() : 0);
						}
						else
						{
							num2 = Creator(val2);
						}
						long actor = num2;
						if (IsEligible(val2, ((Component)_scanningAnimal).transform.position, actor) && HasFood(val2, _scanFood))
						{
							_nearestFood = val2;
							_nearestDistance = sqrMagnitude;
						}
					}
				}
				else
				{
					num--;
					Tameable scanningAnimal = _scanningAnimal;
					Container nearestFood = _nearestFood;
					ClearScan();
					if ((Object)(object)nearestFood != (Object)null)
					{
						DispatchFeed(scanningAnimal, nearestFood);
					}
				}
			}
			ScanBudget.Stop();
		}

		private static bool HasFood(Container container, Dictionary<string, ItemDrop> accepted)
		{
			return container.GetInventory().GetAllItems().Any((ItemData item) => !item.m_shared.m_questItem && accepted.ContainsKey(item.m_shared.m_name) && ChestReserveStore.Available(container, item) > 0);
		}

		private static bool TryGetHungryOwner(Tameable animal, out ZNetView? view, out MonsterAI? ai)
		{
			view = (ZNetView?)(((Object)(object)animal == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			ai = (MonsterAI?)(((Object)(object)animal == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)animal != (Object)null && (Object)(object)view != (Object)null && view.IsValid() && view.IsOwner() && (Object)(object)ai != (Object)null && !((BaseAI)ai).IsAlerted())
			{
				return animal.IsHungry();
			}
			return false;
		}

		private static void DispatchFeed(Tameable tameable, Container container)
		{
			//IL_004e: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !TryGetHungryOwner(tameable, out ZNetView view, out MonsterAI ai))
			{
				return;
			}
			long num;
			if (!ZNet.instance.IsServer())
			{
				Player localPlayer = Player.m_localPlayer;
				num = ((localPlayer != null) ? localPlayer.GetPlayerID() : 0);
			}
			else
			{
				num = Creator(container);
			}
			long actor = num;
			if (!IsEligible(container, ((Component)tameable).transform.position, actor) || !HasFood(container, AcceptedFood(ai)))
			{
				return;
			}
			ZDOID animal = view.GetZDO().m_uid;
			if (ClientRequests.Values.Any((ClientRequest request) => request.Animal == animal))
			{
				return;
			}
			int num2 = NextRequestId();
			if (ZNet.instance.IsServer())
			{
				BeginRequest(container, 0L, num2, animal);
				return;
			}
			ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
			if (serverPeer != null)
			{
				view.GetZDO().SetOwner(serverPeer.m_uid);
				ZDOMan.instance.ForceSendZDO(serverPeer.m_uid, animal);
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				ClientRequest clientRequest = new ClientRequest
				{
					Id = num2,
					Container = container,
					Animal = animal,
					Expires = realtimeSinceStartup + 12f,
					RetryAt = realtimeSinceStartup + 1f
				};
				ClientRequests[num2] = clientRequest;
				SendRequest(serverPeer.m_uid, clientRequest);
			}
		}

		private static void TrackContainer(Container container)
		{
			if (!((Object)(object)container == (Object)null))
			{
				if (LoadedContainers.Add(container))
				{
					_containerSnapshot = null;
				}
				(((Component)container).GetComponent<AutoFeedContainerTracker>() ?? ((Component)container).gameObject.AddComponent<AutoFeedContainerTracker>()).Container = container;
			}
		}

		internal static void ForgetContainer(Container container)
		{
			if (LoadedContainers.Remove(container))
			{
				_containerSnapshot = null;
			}
		}

		internal static void ForgetAnimal(Tameable animal)
		{
			ScanCooldowns.Remove(animal);
			ScanQueue.Remove(animal);
			if (_scanningAnimal == animal)
			{
				ClearScan();
			}
		}

		private static void ClearScan()
		{
			_scanningAnimal = null;
			_scanContainers = null;
			_scanFood = null;
			_scanIndex = 0;
			_nearestFood = null;
		}

		private static void EnsureSession()
		{
			if (_sessionNet != ZNet.instance || _sessionScene != ZNetScene.instance)
			{
				ResetState(returnAnimals: false);
				_sessionNet = ZNet.instance;
				_sessionScene = ZNetScene.instance;
			}
		}

		internal static void Update()
		{
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Expected O, but got Unknown
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.IsActive)
			{
				return;
			}
			EnsureSession();
			UpdateScans();
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			ClientRequest[] array = ClientRequests.Values.ToArray();
			foreach (ClientRequest clientRequest in array)
			{
				if ((Object)(object)clientRequest.Container == (Object)null || realtimeSinceStartup >= clientRequest.Expires)
				{
					ClientRequests.Remove(clientRequest.Id);
				}
				else if (!(realtimeSinceStartup < clientRequest.RetryAt))
				{
					clientRequest.RetryAt = realtimeSinceStartup + 1f;
					ZNet instance = ZNet.instance;
					ZNetPeer val = ((instance != null) ? instance.GetServerPeer() : null);
					if (val != null)
					{
						SendRequest(val.m_uid, clientRequest);
					}
				}
			}
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			ServerRequest[] array2 = ServerRequests.Values.ToArray();
			foreach (ServerRequest serverRequest in array2)
			{
				if ((Object)(object)serverRequest.Container == (Object)null || realtimeSinceStartup >= serverRequest.Expires)
				{
					Finish(serverRequest, committed: false);
					continue;
				}
				ZNetScene instance2 = ZNetScene.instance;
				GameObject obj = ((instance2 != null) ? instance2.FindInstance(serverRequest.Animal) : null);
				Tameable val2 = ((obj != null) ? obj.GetComponent<Tameable>() : null);
				ZNetView val3 = (ZNetView)(((Object)(object)val2 == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
				ZNetView netView = GetNetView(serverRequest.Container);
				if ((Object)(object)val3 == (Object)null || !val3.IsValid() || !val3.IsOwner() || (Object)(object)netView == (Object)null || !netView.IsOwner() || !serverRequest.Prepared)
				{
					continue;
				}
				bool committed = false;
				try
				{
					if (serverRequest.Inventory != null)
					{
						Inventory inventory = serverRequest.Container.GetInventory();
						Inventory val4 = new Inventory("ChestFlow feed validation", inventory.GetBkg(), inventory.GetWidth(), inventory.GetHeight());
						val4.Load(new ZPackage(serverRequest.Inventory));
						inventory.GetAllItems().Clear();
						inventory.GetAllItems().AddRange(val4.GetAllItems());
						InventoryChangedMethod.Invoke(inventory, new object[2] { false, false });
						serverRequest.Inventory = null;
						MultiUserContainerService.SaveContainer(serverRequest.Container);
					}
					else
					{
						MultiUserContainerService.LoadContainer(serverRequest.Container);
					}
					long num = ((serverRequest.Sender == 0L) ? Creator(serverRequest.Container) : serverRequest.Actor);
					if (serverRequest.Sender != 0L)
					{
						if (ChestAuthority.ResolveActor(serverRequest.Sender, out var playerId, out var position) && playerId == num)
						{
							Vector3 val5 = position - ((Component)val2).transform.position;
							if (!(((Vector3)(ref val5)).sqrMagnitude > 16384f))
							{
								goto IL_02bf;
							}
						}
						Finish(serverRequest, committed: false);
						continue;
					}
					goto IL_02bf;
					IL_02bf:
					if (IsEligible(serverRequest.Container, ((Component)val2).transform.position, num, ownLease: true))
					{
						committed = CompleteOperation(serverRequest, val2);
					}
				}
				catch (Exception ex)
				{
					Plugin.LogInstance.LogError((object)("Server Auto Feed operation failed: " + ex));
				}
				Finish(serverRequest, committed);
			}
			long[] array3 = RequestRates.Keys.Where((long peer) => ZNet.instance.GetPeer(peer) == null).ToArray();
			foreach (long key in array3)
			{
				RequestRates.Remove(key);
			}
		}

		private static void SendRequest(long server, ClientRequest request)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(request.Id);
			val.Write(request.Animal);
			ZNetView? netView = GetNetView(request.Container);
			if (netView != null)
			{
				netView.InvokeRPC(server, "ChestFlow_AutoFeedTake", new object[1] { val });
			}
		}

		private static void ReceiveRequest(Container container, long sender, ZPackage package)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.IsActive || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || package == null || package.Size() > 64 || !ChestAuthority.ResolveActor(sender, out var _, out var _))
			{
				return;
			}
			if (!RequestRates.TryGetValue(sender, out Queue<float> value))
			{
				RequestRates.Add(sender, value = new Queue<float>());
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			while (value.Count > 0 && realtimeSinceStartup - value.Peek() >= 1f)
			{
				value.Dequeue();
			}
			if (value.Count >= 20)
			{
				return;
			}
			value.Enqueue(realtimeSinceStartup);
			try
			{
				int num = package.ReadInt();
				ZDOID animal = package.ReadZDOID();
				if (num > 0 && package.GetPos() == package.Size())
				{
					BeginRequest(container, sender, num, animal);
				}
			}
			catch (Exception ex)
			{
				Plugin.LogInstance.LogWarning((object)("Rejected Auto Feed request: " + ex.Message));
			}
		}

		private unsafe static void BeginRequest(Container container, long sender, int id, ZDOID animal)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Expected O, but got Unknown
			ZNetView netView = GetNetView(container);
			if (!ModConfig.Enabled.Value || !ModConfig.AutoFeedEnabled.Value || (Object)(object)netView == (Object)null || !netView.IsValid() || BlockedChests.Contains(netView.GetZDO().m_uid))
			{
				return;
			}
			string text = sender + ":" + id;
			ZDOID uid = netView.GetZDO().m_uid;
			string? text2 = ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
			uid = animal;
			string context = text2 + "/" + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
			FeedRequestState feedRequestState = Receipts.Begin(text, context, Time.realtimeSinceStartup);
			if (feedRequestState != FeedRequestState.New)
			{
				if (sender != 0L && feedRequestState != FeedRequestState.Pending)
				{
					netView.InvokeRPC(sender, "ChestFlow_AutoFeedTakeResponse", new object[2]
					{
						id,
						feedRequestState == FeedRequestState.Committed
					});
				}
				return;
			}
			long playerId = Creator(container);
			if (sender != 0L && !ChestAuthority.ResolveActor(sender, out playerId, out var _))
			{
				Receipts.Complete(text, committed: false);
				return;
			}
			ZNetScene instance = ZNetScene.instance;
			GameObject obj = ((instance != null) ? instance.FindInstance(animal) : null);
			Tameable val = ((obj != null) ? obj.GetComponent<Tameable>() : null);
			if ((Object)(object)val == (Object)null || !IsEligible(container, ((Component)val).transform.position, playerId) || ServerRequests.Count >= 64 || BusyAnimals.Contains(animal))
			{
				Receipts.Complete(text, committed: false);
				if (sender != 0L)
				{
					netView.InvokeRPC(sender, "ChestFlow_AutoFeedTakeResponse", new object[2] { id, false });
				}
				ReturnAnimal(animal, sender);
				return;
			}
			string text3 = netView.GetZDO().GetString("ChestFlow.AutoFeedReceipt.v1", "");
			uid = animal;
			if (text3 == text + "/" + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString())
			{
				Receipts.Complete(text, committed: true);
				if (sender != 0L)
				{
					netView.InvokeRPC(sender, "ChestFlow_AutoFeedTakeResponse", new object[2] { id, true });
				}
				ReturnAnimal(animal, sender);
				return;
			}
			ServerRequest serverRequest = new ServerRequest
			{
				Key = text,
				Id = id,
				Sender = sender,
				Actor = playerId,
				Container = container,
				Animal = animal,
				PreviousOwner = netView.GetZDO().GetOwner(),
				Expires = Time.realtimeSinceStartup + 8f,
				Prepared = netView.IsOwner()
			};
			ServerRequests.Add(text, serverRequest);
			BusyAnimals.Add(animal);
			if (serverRequest.Prepared)
			{
				SetLease(netView);
			}
			else if (serverRequest.PreviousOwner == 0L)
			{
				netView.ClaimOwnership();
				serverRequest.Prepared = netView.IsOwner();
				if (serverRequest.Prepared)
				{
					SetLease(netView);
				}
			}
			else
			{
				ZPackage val2 = new ZPackage();
				val2.Write(text);
				netView.InvokeRPC(serverRequest.PreviousOwner, "ChestFlow_AutoFeedPrepare", new object[1] { val2 });
			}
		}

		private static void PrepareInventory(Container container, long sender, ZPackage package)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.IsActive)
			{
				return;
			}
			ZNetView netView = GetNetView(container);
			if (!ChestAuthority.IsServerSender(sender) || (Object)(object)netView == (Object)null || !netView.IsOwner() || container.IsInUse() || package == null || package.Size() > 128)
			{
				return;
			}
			try
			{
				string text = package.ReadString();
				if (text.Length <= 96 && package.GetPos() == package.Size())
				{
					MultiUserContainerService.SaveContainer(container);
					ZPackage val = new ZPackage();
					container.GetInventory().Save(val);
					byte[] array = val.GetArray();
					if (array.Length <= 65536)
					{
						ZPackage val2 = new ZPackage();
						val2.Write(text);
						val2.Write(array);
						SetLease(netView);
						netView.GetZDO().SetOwner(sender);
						ZDOMan.instance.ForceSendZDO(sender, netView.GetZDO().m_uid);
						netView.InvokeRPC(sender, "ChestFlow_AutoFeedPrepared", new object[1] { val2 });
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogInstance.LogWarning((object)("Could not prepare Auto Feed chest: " + ex.Message));
			}
		}

		private static void ReceivePrepared(Container container, long sender, ZPackage package)
		{
			if (!Plugin.IsActive || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || package == null || package.Size() > 65792)
			{
				return;
			}
			try
			{
				string text = package.ReadString();
				byte[] array = package.ReadByteArray();
				if (text.Length <= 96 && array.Length <= 65536 && package.GetPos() == package.Size() && ServerRequests.TryGetValue(text, out ServerRequest value) && !((Object)(object)value.Container != (Object)(object)container) && value.PreviousOwner == sender && !value.Prepared)
				{
					value.Inventory = array;
					value.Prepared = true;
				}
			}
			catch (Exception ex)
			{
				Plugin.LogInstance.LogWarning((object)("Rejected Auto Feed chest preparation: " + ex.Message));
			}
		}

		private unsafe static bool CompleteOperation(ServerRequest request, Tameable tameable)
		{
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			object? value = MonsterAiField.GetValue(tameable);
			MonsterAI val = (MonsterAI)((value is MonsterAI) ? value : null);
			if ((Object)(object)val == (Object)null || ((BaseAI)val).IsAlerted() || !tameable.IsHungry())
			{
				return false;
			}
			Dictionary<string, ItemDrop> accepted = AcceptedFood(val);
			Inventory inventory = request.Container.GetInventory();
			ItemData item = ((IEnumerable<ItemData>)inventory.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData candidate) => !candidate.m_shared.m_questItem && accepted.ContainsKey(candidate.m_shared.m_name) && ChestReserveStore.Available(request.Container, candidate) > 0));
			if (item == null)
			{
				return false;
			}
			ItemData[] originals = inventory.GetAllItems().ToArray();
			int[] stacks = originals.Select((ItemData candidate) => candidate.m_stack).ToArray();
			Vector2i[] positions = originals.Select((ItemData candidate) => candidate.m_gridPos).ToArray();
			ZDO animal = ((ZNetView)TameableNetViewField.GetValue(tameable)).GetZDO();
			long before = animal.GetLong(ZDOVars.s_tameLastFeeding, 0L);
			ZDO chest = GetNetView(request.Container).GetZDO();
			string oldReceipt = chest.GetString("ChestFlow.AutoFeedReceipt.v1", "");
			try
			{
				return FeedTransaction.Execute(() => inventory.RemoveItem(item, 1), delegate
				{
					ConsumedItemMethod.Invoke(tameable, new object[1] { accepted[item.m_shared.m_name] });
				}, () => !tameable.IsHungry(), delegate
				{
					//IL_0031: 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)
					MultiUserContainerService.SaveContainer(request.Container);
					ZDO obj = chest;
					string key = request.Key;
					ZDOID animal2 = request.Animal;
					obj.Set("ChestFlow.AutoFeedReceipt.v1", key + "/" + ((object)(*(ZDOID*)(&animal2))/*cast due to .constrained prefix*/).ToString());
				}, delegate
				{
					//IL_004e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0053: Unknown result type (might be due to invalid IL or missing references)
					inventory.GetAllItems().Clear();
					inventory.GetAllItems().AddRange(originals);
					for (int i = 0; i < originals.Length; i++)
					{
						originals[i].m_stack = stacks[i];
						originals[i].m_gridPos = positions[i];
					}
					animal.Set(ZDOVars.s_tameLastFeeding, before);
					chest.Set("ChestFlow.AutoFeedReceipt.v1", oldReceipt);
					InventoryChangedMethod.Invoke(inventory, new object[2] { false, false });
					MultiUserContainerService.SaveContainer(request.Container);
				});
			}
			catch (AggregateException ex)
			{
				BlockedChests.Add(chest.m_uid);
				Plugin.LogInstance.LogError((object)("Auto Feed could not finish rollback persistence. This chest is paused; preserve the world and logs before recovery: " + ex));
				return false;
			}
		}

		private static void Finish(ServerRequest request, bool committed)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			ServerRequests.Remove(request.Key);
			BusyAnimals.Remove(request.Animal);
			Receipts.Complete(request.Key, committed);
			ZNetView netView = GetNetView(request.Container);
			if ((Object)(object)netView != (Object)null && netView.IsOwner())
			{
				netView.GetZDO().Set("ChestFlow.AutoFeedLeaseUntil.v1", 0L);
			}
			if (request.Sender != 0L && (Object)(object)request.Container != (Object)null)
			{
				ZNetView? netView2 = GetNetView(request.Container);
				if (netView2 != null)
				{
					netView2.InvokeRPC(request.Sender, "ChestFlow_AutoFeedTakeResponse", new object[2] { request.Id, committed });
				}
			}
			ReturnAnimal(request.Animal, request.Sender);
		}

		private static void ReturnAnimal(ZDOID animal, long sender)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (sender == 0L)
			{
				return;
			}
			ZNet instance = ZNet.instance;
			if (((instance != null) ? instance.GetPeer(sender) : null) != null)
			{
				ZNetScene instance2 = ZNetScene.instance;
				object obj;
				if (instance2 == null)
				{
					obj = null;
				}
				else
				{
					GameObject obj2 = instance2.FindInstance(animal);
					obj = ((obj2 != null) ? obj2.GetComponent<ZNetView>() : null);
				}
				ZNetView val = (ZNetView)obj;
				if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner())
				{
					val.GetZDO().SetOwner(sender);
					ZDOMan.instance.ForceSendZDO(sender, animal);
				}
			}
		}

		internal static bool IsLocked(Container container)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			ZNetView? netView = GetNetView(container);
			ZDO val = ((netView != null) ? netView.GetZDO() : null);
			if (val != null)
			{
				if (!BlockedChests.Contains(val.m_uid))
				{
					if ((Object)(object)ZNet.instance != (Object)null)
					{
						return val.GetLong("ChestFlow.AutoFeedLeaseUntil.v1", 0L) > ZNet.instance.GetTime().Ticks;
					}
					return false;
				}
				return true;
			}
			return false;
		}

		private static void SetLease(ZNetView view)
		{
			view.GetZDO().Set("ChestFlow.AutoFeedLeaseUntil.v1", ZNet.instance.GetTime().AddSeconds(12.0).Ticks);
		}

		private static bool IsEligible(Container container, Vector3 animalPosition, long actor, bool ownLease = false)
		{
			//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)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)container == (Object)null) && ((Behaviour)container).isActiveAndEnabled && !container.IsInUse() && !ContainerCompatibility.IsPrivateNpcInventory(container) && (ownLease || !IsLocked(container)))
			{
				Vector3 val = ((Component)container).transform.position - animalPosition;
				if (!(((Vector3)(ref val)).sqrMagnitude > ModConfig.AutoFeedRange.Value * ModConfig.AutoFeedRange.Value) && !((Object)(object)((Component)container).GetComponent<Player>() != (Object)null) && !((Object)(object)((Component)container).GetComponent<TombStone>() != (Object)null))
				{
					if (!ModConfig.IncludeVehicleContainers.Value && ((Object)(object)container.m_wagon != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null))
					{
						return false;
					}
					Piece val2 = ((Component)container).GetComponent<Piece>() ?? ((Component)container).GetComponentInParent<Piece>();
					if (!ModConfig.IncludeWorldContainers.Value && ((Object)(object)val2 == (Object)null || !val2.IsPlacedByPlayer()))
					{
						return false;
					}
					ZNetView netView = GetNetView(container);
					if ((Object)(object)netView == (Object)null || !netView.IsValid() || !AutoFeedPolicy.MatchesContainerPrefix(GetPrefabNameMethod.Invoke(netView, Array.Empty<object>()) as string, ModConfig.AutoFeedContainerPrefix.Value))
					{
						return false;
					}
					if (MultiUserContainerService.HasAccess(container, actor))
					{
						return ChestAuthority.WardAccess(container, actor);
					}
					return false;
				}
			}
			return false;
		}

		private static long Creator(Container container)
		{
			Piece obj = ((Component)container).GetComponent<Piece>() ?? ((Component)container).GetComponentInParent<Piece>();
			if (obj == null)
			{
				return 0L;
			}
			return obj.GetCreator();
		}

		private static Dictionary<string, ItemDrop> AcceptedFood(MonsterAI monsterAi)
		{
			Dictionary<string, ItemDrop> dictionary = new Dictionary<string, ItemDrop>(StringComparer.Ordinal);
			foreach (ItemDrop item in monsterAi.m_consumeItems ?? new List<ItemDrop>())
			{
				string text = item?.m_itemData?.m_shared?.m_name;
				if ((Object)(object)item != (Object)null && !string.IsNullOrEmpty(text) && !dictionary.ContainsKey(text))
				{
					dictionary.Add(text, item);
				}
			}
			return dictionary;
		}

		private static ZNetView? GetNetView(Container container)
		{
			if (!((Object)(object)container == (Object)null))
			{
				object? value = ContainerNetViewField.GetValue(container);
				return (ZNetView?)((value is ZNetView) ? value : null);
			}
			return null;
		}

		private static int NextRequestId()
		{
			nextRequestId = ((nextRequestId == int.MaxValue) ? 1 : (nextRequestId + 1));
			return nextRequestId;
		}

		internal static void Reset()
		{
			ResetState(returnAnimals: true);
			_sessionNet = null;
			_sessionScene = null;
		}

		private static void ResetState(bool returnAnimals)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (returnAnimals)
			{
				ServerRequest[] array = ServerRequests.Values.ToArray();
				foreach (ServerRequest serverRequest in array)
				{
					ReturnAnimal(serverRequest.Animal, serverRequest.Sender);
				}
			}
			ServerRequests.Clear();
			ClientRequests.Clear();
			BusyAnimals.Clear();
			BlockedChests.Clear();
			Receipts.Clear();
			RequestRates.Clear();
			ScanCooldowns = new ConditionalWeakTable<Tameable, ScanCooldown>();
			ScanQueue.Clear();
			LoadedContainers.Clear();
			_containerSnapshot = null;
			_discoverySeeded = false;
			ClearScan();
		}
	}
	internal sealed class AutoFeedContainerTracker : MonoBehaviour
	{
		internal Container Container;

		private void OnDestroy()
		{
			if (Container != null)
			{
				AutoFeedService.ForgetContainer(Container);
			}
		}
	}
	internal sealed class AutoFeedAnimalTracker : MonoBehaviour
	{
		internal Tameable Animal;

		private void OnDestroy()
		{
			if (Animal != null)
			{
				AutoFeedService.ForgetAnimal(Animal);
			}
		}
	}
	internal static class ChestAuthority
	{
		private static readonly FieldInfo AllAreas = AccessTools.Field(typeof(PrivateArea), "m_allAreas");

		private static readonly MethodInfo IsPermitted = AccessTools.Method(typeof(PrivateArea), "IsPermitted", (Type[])null, (Type[])null);

		private static readonly MethodInfo IsInside = AccessTools.Method(typeof(PrivateArea), "IsInside", (Type[])null, (Type[])null);

		private static readonly MethodInfo IsEnabled = AccessTools.Method(typeof(PrivateArea), "IsEnabled", (Type[])null, (Type[])null);

		internal static bool IsServerSender(long sender)
		{
			if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
			{
				ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
				if (serverPeer == null)
				{
					return false;
				}
				return serverPeer.m_uid == sender;
			}
			return false;
		}

		internal static bool ResolveActor(long sender, out long playerId, out Vector3 position)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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)
			playerId = 0L;
			position = Vector3.zero;
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			ZNetPeer peer = instance.GetPeer(sender);
			if (instance.IsServer() && peer == null)
			{
				return false;
			}
			if (peer != null && peer.m_characterID != ZDOID.None)
			{
				ZDOMan instance2 = ZDOMan.instance;
				ZDO val = ((instance2 != null) ? instance2.GetZDO(peer.m_characterID) : null);
				if (val != null && val.GetOwner() == sender)
				{
					ZNetScene instance3 = ZNetScene.instance;
					object obj;
					if (instance3 == null)
					{
						obj = null;
					}
					else
					{
						GameObject prefab = instance3.GetPrefab(val.GetPrefab());
						obj = ((prefab != null) ? prefab.GetComponent<Player>() : null);
					}
					if (!((Object)obj == (Object)null))
					{
						playerId = val.GetLong(ZDOVars.s_playerID, 0L);
						position = val.GetPosition();
						return playerId != 0;
					}
				}
				return false;
			}
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				ZNetView component = ((Component)allPlayer).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO().GetOwner() == sender)
				{
					playerId = allPlayer.GetPlayerID();
					position = ((Component)allPlayer).transform.position;
					return playerId != 0;
				}
			}
			return false;
		}

		internal static bool CanUse(Container container, long sender, long claimedPlayerId)
		{
			//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)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!ResolveActor(sender, out var playerId, out var position) || playerId != claimedPlayerId)
			{
				return false;
			}
			float num = Mathf.Clamp(ModConfig.NearbyRange.Value, 4f, 100f);
			Vector3 val = ((Component)container).transform.position - position;
			if (((Vector3)(ref val)).sqrMagnitude <= num * num && MultiUserContainerService.HasAccess(container, playerId))
			{
				return WardAccess(container, playerId);
			}
			return false;
		}

		internal static bool WardAccess(Container container, long playerId)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			if (!container.m_checkGuardStone)
			{
				return true;
			}
			if (!(AllAreas.GetValue(null) is IEnumerable<PrivateArea> enumerable))
			{
				return false;
			}
			bool flag = false;
			bool flag2 = default(bool);
			foreach (PrivateArea item in enumerable)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				object obj = IsEnabled.Invoke(item, Array.Empty<object>());
				if (!(obj is bool) || !(bool)obj)
				{
					continue;
				}
				obj = IsInside.Invoke(item, new object[2]
				{
					((Component)container).transform.position,
					0f
				});
				if (!(obj is bool) || !(bool)obj)
				{
					continue;
				}
				flag = true;
				Piece component = ((Component)item).GetComponent<Piece>();
				if (playerId == 0L)
				{
					continue;
				}
				if (component == null || component.GetCreator() != playerId)
				{
					obj = IsPermitted.Invoke(item, new object[1] { playerId });
					int num;
					if (obj is bool)
					{
						flag2 = (bool)obj;
						num = 1;
					}
					else
					{
						num = 0;
					}
					if (((uint)num & (flag2 ? 1u : 0u)) == 0)
					{
						continue;
					}
				}
				return true;
			}
			return !flag;
		}
	}
	internal static class ChestReserveStore
	{
		internal const string Key = "ChestFlow.StorageReserves.v1";

		internal static string ReadRaw(Container container)
		{
			ZNetView component = ((Component)container).GetComponent<ZNetView>();
			object obj;
			if (component == null)
			{
				obj = null;
			}
			else
			{
				ZDO zDO = component.GetZDO();
				obj = ((zDO != null) ? zDO.GetString("ChestFlow.StorageReserves.v1", "") : null);
			}
			if (obj == null)
			{
				obj = "";
			}
			return (string)obj;
		}

		internal static int Available(Container container, ItemData item)
		{
			try
			{
				Dictionary<string, int> dictionary = StorageReserves.Decode(ReadRaw(container));
				string prefab = ValheimItemCategoryClassifier.PrefabName(item);
				if (!dictionary.TryGetValue(prefab, out var value))
				{
					return item.m_stack;
				}
				int total = (from candidate in container.GetInventory().GetAllItems()
					where string.Equals(ValheimItemCategoryClassifier.PrefabName(candidate), prefab, StringComparison.OrdinalIgnoreCase)
					select candidate).Sum((ItemData candidate) => candidate.m_stack);
				return Math.Min(item.m_stack, StorageReserves.Available(total, value));
			}
			catch (Exception)
			{
				return 0;
			}
		}

		internal static int Count(Container container, string name, int quality)
		{
			try
			{
				Dictionary<string, int> dictionary = StorageReserves.Decode(ReadRaw(container));
				int num = 0;
				foreach (IGrouping<string, ItemData> item in (from item in container.GetInventory().GetAllItems()
					where item.m_shared.m_name == name && !item.m_shared.m_questItem
					select item).GroupBy<ItemData, string>(ValheimItemCategoryClassifier.PrefabName, StringComparer.OrdinalIgnoreCase))
				{
					dictionary.TryGetValue(item.Key, out var value);
					num += Math.Min(item.Where((ItemData item) => item.m_worldLevel >= Game.m_worldLevel && (quality < 0 || item.m_quality == quality)).Sum((ItemData item) => item.m_stack), StorageReserves.Available(item.Sum((ItemData item) => item.m_stack), value));
				}
				return num;
			}
			catch (Exception)
			{
				return 0;
			}
		}

		internal static void Write(Container container, string encoded)
		{
			StorageReserves.Decode(encoded);
			ZNetView component = ((Component)container).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || AutoFeedService.IsLocked(container))
			{
				throw new InvalidOperationException("Open the chest and wait for ownership before changing its reserves.");
			}
			component.GetZDO().Set("ChestFlow.StorageReserves.v1", encoded);
		}
	}
	internal static class ChestRuleEditor
	{
		private sealed class ButtonVisual
		{
			internal RectTransform Rect { get; }

			internal Image Image { get; }

			internal Button Button { get; }

			internal TMP_Text Label { get; }

			internal Color NormalImageColor { get; }

			internal Color NormalLabelColor { get; }

			internal ButtonVisual(RectTransform rect, Image image, Button button, TMP_Text label, Color normalImageColor, Color normalLabelColor)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				Rect = rect;
				Image = image;
				Button = button;
				Label = label;
				NormalImageColor = normalImageColor;
				NormalLabelColor = normalLabelColor;
			}
		}

		private sealed class ItemChoice
		{
			internal string PrefabName { get; }

			internal string DisplayName { get; }

			internal ItemCategory Category { get; }

			internal Sprite? Icon { get; }

			internal string SearchText { get; }

			internal ItemChoice(string prefabName, string displayName, ItemCategory category, Sprite? icon)
			{
				PrefabName = prefabName;
				DisplayName = displayName;
				Category = category;
				Icon = icon;
				ItemCategoryDefinition itemCategoryDefinition = ItemCategoryCatalog.Get(category);
				SearchText = displayName + " " + prefabName + " " + itemCategoryDefinition.DisplayName + " " + itemCategoryDefinition.Group;
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Save;

			public static Func<Image, float> <1>__ImageArea;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__49_0;

			public static UnityAction <>9__49_1;

			public static Action<string> <>9__55_0;

			public static Func<ItemCategoryDefinition, bool> <>9__55_1;

			public static Action<string> <>9__56_0;

			public static UnityAction<string> <>9__59_0;

			public static Func<ItemChoice, bool> <>9__61_0;

			public static Func<ItemChoice, int> <>9__64_0;

			public static Func<ItemChoice, string> <>9__64_1;

			public static Func<ItemChoice, string> <>9__64_2;

			public static Func<Image, bool> <>9__81_0;

			internal void <Build>b__49_0()
			{
				Close();
			}

			internal void <Build>b__49_1()
			{
				Close();
			}

			internal void <BuildCategoryView>b__55_0(string groupId)
			{
				_activeCategoryGroupId = groupId;
				RenderScope();
			}

			internal bool <BuildCategoryView>b__55_1(ItemCategoryDefinition definition)
			{
				return string.Equals(definition.GroupId, _activeCategoryGroupId, StringComparison.OrdinalIgnoreCase);
			}

			internal void <BuildItemsView>b__56_0(string groupId)
			{
				_activeItemGroupId = groupId;
				RenderScope();
			}

			internal void <CreateSearchField>b__59_0(string value)
			{
				_itemSearch = value ?? string.Empty;
				RefreshItemTiles();
			}

			internal bool <RenderItemTiles>b__61_0(ItemChoice choice)
			{
				return string.Equals(ItemCategoryCatalog.Get(choice.Category).GroupId, _activeItemGroupId, StringComparison.OrdinalIgnoreCase);
			}

			internal int <CollectItemChoices>b__64_0(ItemChoice choice)
			{
				return ItemCategoryCatalog.SortRank(choice.Category);
			}

			internal string <CollectItemChoices>b__64_1(ItemChoice choice)
			{
				return choice.DisplayName;
			}

			internal string <CollectItemChoices>b__64_2(ItemChoice choice)
			{
				return choice.PrefabName;
			}

			internal bool <FindContainerBackground>b__81_0(Image candidate)
			{
				if ((Object)(object)candidate.sprite != (Object)null)
				{
					if (((Object)((Component)candidate).gameObject).name.IndexOf("bkg", StringComparison.OrdinalIgnoreCase) < 0)
					{
						return ((Object)((Component)candidate).gameObject).name.IndexOf("background", StringComparison.OrdinalIgnoreCase) >= 0;
					}
					return true;
				}
				return false;
			}
		}

		private const string Prefix = "ChestFlow_RuleEditor_";

		private const float PanelWidth = 900f;

		private const float PanelHeight = 650f;

		private const float RailWidth = 190f;

		private const float Gap = 10f;

		private static readonly Color Gold = new Color(1f, 0.66f, 0.24f, 1f);

		private static readonly Color GoldFaint = new Color(0.95f, 0.58f, 0.18f, 0.42f);

		private static readonly Color SelectedGold = new Color(1f, 0.76f, 0.42f, 1f);

		private static readonly Color Cream = new Color(0.9f, 0.87f, 0.79f, 1f);

		private static readonly Color Muted = new Color(0.73f, 0.69f, 0.61f, 1f);

		private static InventoryGui? _gui;

		private static Container? _container;

		private static GameObject? _root;

		private static RectTransform? _body;

		private static RectTransform? _itemContent;

		private static TMP_Text? _status;

		private static Image? _panelImage;

		private static Image? _sourcePanelImage;

		private static Button? _buttonTemplate;

		private static TMP_Text? _titleTemplate;

		private static Sprite? _buttonSprite;

		private static Type _buttonImageType;

		private static Color _buttonImageColor = Color.white;

		private static Color _buttonLabelColor = Gold;

		private static TMP_FontAsset? _bodyFont;

		private static Material? _bodyFontMaterial;

		private static Sprite? _panelSprite;

		private static Type _panelImageType;

		private static Color _panelImageColor = Color.white;

		private static Material? _panelMaterial;

		private static bool _panelFillCenter = true;

		private static bool _panelPreserveAspect;

		private static float _panelPixelsPerUnitMultiplier = 1f;

		private static bool _panelUseSpriteMesh;

		private static ChestRuleScope _scope;

		private static string _selectedGroupId = "materials";

		private static string _activeCategoryGroupId = "materials";

		private static string _activeItemGroupId = "materials";

		private static string _itemSearch = string.Empty;

		private static readonly HashSet<ItemCategory> SelectedCategories = new HashSet<ItemCategory>();

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

		private static readonly Dictionary<ChestRuleScope, ButtonVisual> ModeButtons = new Dictionary<ChestRuleScope, ButtonVisual>();

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

		private static readonly List<ItemChoice> ItemChoices = new List<ItemChoice>();

		internal static bool IsOpen => (Object)(object)_root != (Object)null;

		internal static void Open(InventoryGui gui, Container container)
		{
			if (!((Object)(object)gui == (Object)null) && !((Object)(object)container == (Object)null))
			{
				Close();
				_gui = gui;
				_container = container;
				ChestStorageRule chestStorageRule = ChestRuleStore.Read(container);
				_scope = chestStorageRule.Scope;
				_selectedGroupId = ((chestStorageRule.Scope == ChestRuleScope.Group) ? chestStorageRule.GroupId : "materials");
				_activeCategoryGroupId = FirstCategoryGroup(chestStorageRule) ?? "materials";
				_activeItemGroupId = "materials";
				_itemSearch = string.Empty;
				SelectedCategories.Clear();
				SelectedCategories.UnionWith(chestStorageRule.Categories);
				SelectedItems.Clear();
				SelectedItems.UnionWith(chestStorageRule.ItemPrefabNames);
				CollectItemChoices(container);
				Build(gui, container);
			}
		}

		internal static void Update()
		{
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			if ((Object)(object)_gui == (Object)null || (Object)(object)_container == (Object)null || !InventoryGui.IsVisible() || (Object)(object)InventoryAccess.CurrentContainer(_gui) != (Object)(object)_container)
			{
				Close();
				return;
			}
			RefreshPanelBackground();
			if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
			}
		}

		internal static void Close(InventoryGui? gui = null)
		{
			if (!((Object)(object)gui != (Object)null) || !((Object)(object)_gui != (Object)null) || !((Object)(object)gui != (Object)(object)_gui))
			{
				if ((Object)(object)_root != (Object)null)
				{
					_root.SetActive(false);
					Object.Destroy((Object)(object)_root);
				}
				_root = null;
				_body = null;
				_itemContent = null;
				_status = null;
				_panelImage = null;
				_sourcePanelImage = null;
				_gui = null;
				_container = null;
				ModeButtons.Clear();
				BrowserGroupButtons.Clear();
				ItemChoices.Clear();
			}
		}

		private static void Build(InventoryGui gui, Container container)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: 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_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Expected O, but got Unknown
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Expected O, but got Unknown
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Expected O, but got Unknown
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Expected O, but got Unknown
			//IL_045f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_046a: Expected O, but got Unknown
			Transform transform = ((Component)gui).transform;
			RectTransform val = (RectTransform)(object)(((transform is RectTransform) ? transform : null) ?? throw new InvalidOperationException("InventoryGui does not use a RectTransform root."));
			_root = new GameObject("ChestFlow_RuleEditor_Overlay", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			_root.transform.SetParent((Transform)(object)val, false);
			_root.transform.SetAsLastSibling();
			RectTransform val2 = (RectTransform)_root.transform;
			Stretch(val2, Vector2.zero, Vector2.zero);
			Image component = _root.GetComponent<Image>();
			((Graphic)component).color = new Color(0f, 0f, 0f, 0.52f);
			((Graphic)component).raycastTarget = true;
			CaptureVanillaStyle(gui, container);
			RectTransform val3 = CreateRect("ChestFlow_RuleEditor_Panel", (Transform)(object)val2);
			Vector2 val4 = default(Vector2);
			((Vector2)(ref val4))..ctor(0.5f, 0.5f);
			val3.anchorMax = val4;
			val3.anchorMin = val4;
			val3.pivot = new Vector2(0.5f, 0.5f);
			val3.anchoredPosition = Vector2.zero;
			val3.sizeDelta = new Vector2(900f, 650f);
			_panelImage = ((Component)val3).gameObject.AddComponent<Image>();
			ApplyPanelStyle(_panelImage);
			TMP_Text obj = CreateVanillaTitle((Transform)(object)val3, "ChestFlow_RuleEditor_Title", "Storage Rule", 30f);
			obj.alignment = (TextAlignmentOptions)514;
			SetTopRect((RectTransform)obj.transform, 70f, 8f, 70f, 40f);
			string content = (((Object)(object)gui.m_containerName != (Object)null && !string.IsNullOrWhiteSpace(gui.m_containerName.text)) ? gui.m_containerName.text : ((Localization.instance != null) ? Localization.instance.Localize(container.m_name) : container.m_name));
			TMP_Text obj2 = CreateText((Transform)(object)val3, "ChestFlow_RuleEditor_Subtitle", content, 13f, Gold, (TextAlignmentOptions)514);
			obj2.fontStyle = (FontStyles)1;
			SetTopRect((RectTransform)obj2.transform, 70f, 43f, 70f, 24f);
			ButtonVisual buttonVisual = CreateButton((Transform)(object)val3, "ChestFlow_RuleEditor_Close", "×", 16f, (TextAlignmentOptions)514);
			SetTopRect(buttonVisual.Rect, 842f, 10f, 14f, 38f);
			ButtonClickedEvent onClick = buttonVisual.Button.onClick;
			object obj3 = <>c.<>9__49_0;
			if (obj3 == null)
			{
				UnityAction val5 = delegate
				{
					Close();
				};
				<>c.<>9__49_0 = val5;
				obj3 = (object)val5;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj3);
			RectTransform obj4 = CreateRect("ChestFlow_RuleEditor_Modes", (Transform)(object)val3);
			SetTopRect(obj4, 24f, 72f, 24f, 36f);
			BuildModeButtons(obj4);
			RectTransform obj5 = CreateRect("ChestFlow_RuleEditor_ModeRule", (Transform)(object)val3);
			SetTopRect(obj5, 24f, 110f, 24f, 1f);
			((Graphic)((Component)obj5).gameObject.AddComponent<Image>()).color = GoldFaint;
			_body = CreateRect("ChestFlow_RuleEditor_Body", (Transform)(object)val3);
			SetInsets(_body, 24f, 120f, 24f, 68f);
			RectTransform obj6 = CreateRect("ChestFlow_RuleEditor_FooterRule", (Transform)(object)val3);
			SetTopRect(obj6, 24f, 589f, 24f, 1f);
			((Graphic)((Component)obj6).gameObject.AddComponent<Image>()).color = GoldFaint;
			_status = CreateText((Transform)(object)val3, "ChestFlow_RuleEditor_Status", ScopeHelp(_scope), 12f, Muted, (TextAlignmentOptions)4097);
			SetTopRect((RectTransform)_status.transform, 24f, 596f, 360f, 34f);
			_status.textWrappingMode = (TextWrappingModes)1;
			ButtonVisual buttonVisual2 = CreateButton((Transform)(object)val3, "ChestFlow_RuleEditor_Cancel", "Cancel", 15f, (TextAlignmentOptions)514);
			SetTopRect(buttonVisual2.Rect, 570f, 598f, 220f, 34f);
			ButtonClickedEvent onClick2 = buttonVisual2.Button.onClick;
			object obj7 = <>c.<>9__49_1;
			if (obj7 == null)
			{
				UnityAction val6 = delegate
				{
					Close();
				};
				<>c.<>9__49_1 = val6;
				obj7 = (object)val6;
			}
			((UnityEvent)onClick2).AddListener((UnityAction)obj7);
			ButtonVisual buttonVisual3 = CreateButton((Transform)(object)val3, "ChestFlow_RuleEditor_Save", "Save rule", 15f, (TextAlignmentOptions)514);
			SetTopRect(buttonVisual3.Rect, 690f, 598f, 24f, 34f);
			SetButtonSelected(buttonVisual3, selected: true);
			ButtonClickedEvent onClick3 = buttonVisual3.Button.onClick;
			object obj8 = <>O.<0>__Save;
			if (obj8 == null)
			{
				UnityAction val7 = Save;
				<>O.<0>__Save = val7;
				obj8 = (object)val7;
			}
			((UnityEvent)onClick3).AddListener((UnityAction)obj8);
			RenderScope();
			EventSystem current = EventSystem.current;
			if ((Object)(object)current != (Object)null && ModeButtons.TryGetValue(_scope, out ButtonVisual value))
			{
				current.SetSelectedGameObject(((Component)value.Button).gameObject);
			}
		}

		private static void BuildModeButtons(RectTransform parent)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			ModeButtons.Clear();
			ChestRuleScope[] array = new ChestRuleScope[4]
			{
				ChestRuleScope.Auto,
				ChestRuleScope.Group,
				ChestRuleScope.Categories,
				ChestRuleScope.Items
			};
			string[] array2 = new string[4] { "Auto", "Group", "Category", "Items" };
			float num = 208.5f;
			for (int i = 0; i < array.Length; i++)
			{
				ChestRuleScope selectedScope = array[i];
				ButtonVisual buttonVisual = CreateButton((Transform)(object)parent, "ChestFlow_RuleEditor_Mode_" + array2[i], array2[i], 12f, (TextAlignmentOptions)514);
				buttonVisual.Rect.anchorMin = new Vector2(0f, 0f);
				buttonVisual.Rect.anchorMax = new Vector2(0f, 1f);
				buttonVisual.Rect.pivot = new Vector2(0f, 0.5f);
				buttonVisual.Rect.anchoredPosition = new Vector2((float)i * (num + 6f), 0f);
				buttonVisual.Rect.sizeDelta = new Vector2(num, 0f);
				((UnityEvent)buttonVisual.Button.onClick).AddListener((UnityAction)delegate
				{
					_scope = selectedScope;
					SetStatus(ScopeHelp(_scope), error: false);
					RenderScope();
				});
				ModeButtons.Add(selectedScope, buttonVisual);
			}
			UpdateModeAppearance();
		}

		private static void RenderScope()
		{
			if (!((Object)(object)_body == (Object)null))
			{
				ClearChildren(_body);
				BrowserGroupButtons.Clear();
				UpdateModeAppearance();
				switch (_scope)
				{
				case ChestRuleScope.Group:
					BuildGroupView(_body);
					break;
				case ChestRuleScope.Categories:
					BuildCategoryView(_body);
					break;
				case ChestRuleScope.Items:
					BuildItemsView(_body);
					break;
				default:
					BuildAutoView(_body);
					break;
				}
			}
		}

		private static void BuildAutoView(RectTransform body)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_0059: 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_008c: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			TMP_Text obj = CreateText((Transform)(object)body, "ChestFlow_RuleEditor_AutoHeading", "Automatic by chest contents", 18f, Gold, (TextAlignmentOptions)257);
			obj.fontStyle = (FontStyles)1;
			SetTopRect((RectTransform)obj.transform, 18f, 12f, 18f, 38f);
			TMP_Text obj2 = CreateText((Transform)(object)body, "ChestFlow_RuleEditor_AutoText", "ChestFlow reads the items already stored in this chest as seeds. Exact item matches always qualify. With category matching enabled, one item also seeds its detailed category.\n\nChoose GROUP for every item under a main heading, CATEGORY for one or more detailed categories, or ITEMS for exact combinations such as Corewood + Finewood.", 15f, Cream, (TextAlignmentOptions)257);
			SetTopRect((RectTransform)obj2.transform, 18f, 62f, 18f, 138f);
			obj2.textWrappingMode = (TextWrappingModes)1;
			CreateExampleCard(body, new Vector2(18f, -226f), "Seed", "Wood in chest", "Accepts the Wood category");
			CreateExampleCard(body, new Vector2(292f, -226f), "Exact", "Obsidian in chest", "Always accepts Obsidian");
			CreateExampleCard(body, new Vector2(566f, -226f), "Empty", "No stored items", "No automatic destination");
		}

		private static void CreateExampleCard(RectTransform parent, Vector2 position, string tag, string title, string detail)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			RectTransform obj = CreateRect("ChestFlow_RuleEditor_Example_" + tag, (Transform)(object)parent);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			obj.anchorMax = val;
			obj.anchorMin = val;
			obj.pivot = new Vector2(0f, 1f);
			obj.anchoredPosition = position;
			obj.sizeDelta = new Vector2(256f, 112f);
			Image obj2 = ((Component)obj).gameObject.AddComponent<Image>();
			ApplyButtonSprite(obj2);
			((Graphic)obj2).color = _buttonImageColor;
			((Graphic)obj2).raycastTarget = false;
			TMP_Text obj3 = CreateText((Transform)(object)obj, "ChestFlow_RuleEditor_Tag", tag, 11f, Gold, (TextAlignmentOptions)257);
			obj3.fontStyle = (FontStyles)1;
			SetTopRect((RectTransform)obj3.transform, 12f, 8f, 12f, 22f);
			TMP_Text obj4 = CreateText((Transform)(object)obj, "ChestFlow_RuleEditor_CardTitle", title, 14f, Cream, (TextAlignmentOptions)257);
			obj4.fontStyle = (FontStyles)1;
			SetTopRect((RectTransform)obj4.transform, 12f, 32f, 12f, 26f);
			TMP_Text obj5 = CreateText((Transform)(object)obj, "ChestFlow_RuleEditor_CardDetail", detail, 12f, Muted, (TextAlignmentOptions)257);
			SetTopRect((RectTransform)obj5.transform, 12f, 62f, 12f, 36f);
			obj5.textWrappingMode = (TextWrappingModes)1;
		}

		private static void BuildGroupView(RectTransform body)
		{
			//IL_0089: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Expected O, but got Unknown
			CreateSectionIntro(body, "Main category", "Choose one broad destination. Every subcategory beneath it will be accepted.");
			float num = 66f;
			float num2 = 419f;
			Vector2 val = default(Vector2);
			for (int i = 0; i < ItemCategoryCatalog.Groups.Count; i++)
			{
				ItemCategoryGroupDefinition itemCategoryGroupDefinition = ItemCategoryCatalog.Groups[i];
				int num3 = i % 2;
				int num4 = i / 2;
				ButtonVisual buttonVisual = CreateButton((Transform)(object)body, "ChestFlow_RuleEditor_Group_" + itemCategoryGroupDefinition.Id, itemCategoryGroupDefinition.DisplayName, 14f, (TextAlignmentOptions)4097);
				RectTransform rect = buttonVisual.Rect;
				RectTransform rect2 = buttonVisual.Rect;
				((Vector2)(ref val))..ctor(0f, 1f);
				rect2.anchorMax = val;
				rect.anchorMin = val;
				buttonVisual.Rect.pivot = new Vector2(0f, 1f);
				buttonVisual.Rect.anchoredPosition = new Vector2((float)num3 * (num2 + 14f), 0f - (num + (float)num4 * 58f));
				buttonVisual.Rect.sizeDelta = new Vector2(num2, 48f);
				string groupId = itemCategoryGroupDefinition.Id;
				((UnityEvent)buttonVisual.Button.onClick).AddListener((UnityAction)delegate
				{
					_selectedGroupId = groupId;
					UpdateGroupSelection();
				});
				BrowserGroupButtons[itemCategoryGroupDefinition.Id] = buttonVisual;
			}
			UpdateGroupSelection();
		}

		private static void BuildCategoryView(RectTransform body)
		{
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Expected O, but got Unknown
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Expected O, but got Unknown
			CreateSectionIntro(body, "Detailed categories", "Select one or more categories. Main headings remain filters, not a third tier.");
			RectTransform obj = CreateRect("ChestFlow_RuleEditor_CategoryRail", (Transform)(object)body);
			SetInsets(obj, 0f, 62f, 662f, 0f);
			RectTransform val = CreateRect("ChestFlow_RuleEditor_CategoryContent", (Transform)(object)body);
			SetInsets(val, 200f, 62f, 0f, 0f);
			BuildBrowserRail(obj, _activeCategoryGroupId, includeAll: false, delegate(string groupId)
			{
				_activeCategoryGroupId = groupId;
				RenderScope();
			});
			ScrollRect scroll;
			RectTransform val2 = CreateScrollContent(val, "ChestFlow_RuleEditor_CategoryScroll", out scroll);
			List<ItemCategoryDefinition> list = ItemCategoryCatalog.All.Where((ItemCategoryDefinition definition) => string.Equals(definition.GroupId, _activeCategoryGroupId, StringComparison.OrdinalIgnoreCase)).ToList();
			float num = 0f;
			foreach (ItemCategoryDefinition item in list)
			{
				ButtonVisual visual = CreateButton((Transform)(object)val2, "ChestFlow_RuleEditor_Category_" + item.Id, item.DisplayName, 13f, (TextAlignmentOptions)4097);
				visual.Rect.anchorMin = new Vector2(0f, 1f);
				visual.Rect.anchorMax = new Vector2(1f, 1f);
				visual.Rect.pivot = new Vector2(0.5f, 1f);
				visual.Rect.anchoredPosition = new Vector2(0f, 0f - num);
				visual.Rect.sizeDelta = new Vector2(-4f, 42f);
				TMP_Text check = CreateText((Transform)(object)visual.Rect, "ChestFlow_RuleEditor_Check", "✓", 16f, Gold, (TextAlignmentOptions)514);
				SetRightFill((RectTransform)check.transform, 34f, 8f, 4f, 8f);
				SetCategoryVisual(visual, check, SelectedCategories.Contains(item.Category));
				ItemCategory category = item.Category;
				((UnityEvent)visual.Button.onClick).AddListener((UnityAction)delegate
				{
					if (!SelectedCategories.Add(category))
					{
						SelectedCategories.Remove(category);
					}
					SetCategoryVisual(visual, check, SelectedCategories.Contains(category));
					RefreshBrowserRailCounts(items: false);
				});
				num += 48f;
			}
			SetContentHeight(val2, num);
			RefreshBrowserRailCounts(items: false);
		}

		private static void BuildItemsView(RectTransform body)
		{
			SetTopRect(CreateSearchField(body), 0f, 6f, 0f, 36f);
			RectTransform obj = CreateRect("ChestFlow_RuleEditor_ItemRail", (Transform)(object)body);
			SetInsets(obj, 0f, 52f, 662f, 0f);
			RectTransform val = CreateRect("ChestFlow_RuleEditor_ItemContent", (Transform)(object)body);
			SetInsets(val, 200f, 52f, 0f, 0f);
			BuildBrowserRail(obj, _activeItemGroupId, includeAll: true, delegate(string groupId)
			{
				_activeItemGroupId = groupId;
				RenderScope();
			});
			_itemContent = CreateScrollContent(val, "ChestFlow_RuleEditor_ItemScroll", out ScrollRect _);
			RenderItemTiles(_itemContent);
			RefreshBrowserRailCounts(items: true);
		}

		private static void BuildBrowserRail(RectTransform rail, string activeGroupId, bool includeAll, Action<string> onSelected)
		{
			float num = 0f;
			if (includeAll)
			{
				AddRailButton(rail, "all", "All items", activeGroupId, num, onSelected);
				num += 34f;
			}
			foreach (ItemCategoryGroupDefinition group in ItemCategoryCatalog.Groups)
			{
				AddRailButton(rail, group.Id, group.DisplayName, activeGroupId, num, onSelected);
				num += 34f;
			}
		}

		private static void AddRailButton(RectTransform rail, string groupId, string label, string activeGroupId, float y, Action<string> onSelected)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Expected O, but got Unknown
			ButtonVisual buttonVisual = CreateButton((Transform)(object)rail, "ChestFlow_RuleEditor_Rail_" + groupId, label, 10.5f, (TextAlignmentOptions)4097);
			buttonVisual.Rect.anchorMin = new Vector2(0f, 1f);
			buttonVisual.Rect.anchorMax = new Vector2(1f, 1f);
			buttonVisual.Rect.pivot = new Vector2(0.5f, 1f);
			buttonVisual.Rect.anchoredPosition = new Vector2(0f, 0f - y);
			buttonVisual.Rect.sizeDelta = new Vector2(0f, 30f);
			SetButtonSelected(buttonVisual, string.Equals(groupId, activeGroupId, StringComparison.OrdinalIgnoreCase));
			((UnityEvent)buttonVisual.Button.onClick).AddListener((UnityAction)delegate
			{
				onSelected(groupId);
			});
			BrowserGroupButtons[groupId] = buttonVisual;
		}

		private static RectTransform CreateSearchField(RectTransform parent)
		{
			//IL_0025: 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_0066: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00a9: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00d5: 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_00eb: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Expected O, but got Unknown
			RectTransform val = CreateRect("ChestFlow_RuleEditor_Search", (Transform)(object)parent);
			Image val2 = ((Component)val).gameObject.AddComponent<Image>();
			ApplyButtonSprite(val2);
			((Graphic)val2).color = _buttonImageColor;
			TMP_InputField input = ((Component)val).gameObject.AddComponent<TMP_InputField>();
			RectTransform val3 = CreateRect("ChestFlow_RuleEditor_SearchViewport", (Transform)(object)val);
			Stretch(val3, new Vector2(8f, 2f), new Vector2(-30f, -2f));
			((Component)val3).gameObject.AddComponent<RectMask2D>();
			TextMeshProUGUI val4 = (TextMeshProUGUI)CreateText((Transform)(object)val3, "ChestFlow_RuleEditor_SearchText", string.Empty, 12f, Cream, (TextAlignmentOptions)4097);
			Stretch((RectTransform)((TMP_Text)val4).transform, Vector2.zero, Vector2.zero);
			((TMP_Text)val4).fontStyle = (FontStyles)0;
			TextMeshProUGUI val5 = (TextMeshProUGUI)CreateText((Transform)(object)val3, "ChestFlow_RuleEditor_SearchPlaceholder", "Search known items", 12f, Muted, (TextAlignmentOptions)4097);
			Stretch((RectTransform)((TMP_Text)val5).transform, Vector2.zero, Vector2.zero);
			((TMP_Text)val5).fontStyle = (FontStyles)0;
			((Selectable)input).targetGraphic = (Graphic)(object)val2;
			input.textViewport = val3;
			input.textComponent = (TMP_Text)(object)val4;
			input.placeholder = (Graphic)(object)val5;
			input.lineType = (LineType)0;
			input.characterLimit = 64;
			input.caretColor = Gold;
			input.selectionColor = new Color(SelectedGold.r, SelectedGold.g, SelectedGold.b, 0.55f);
			input.SetTextWithoutNotify(_itemSearch);
			((UnityEvent<string>)(object)input.onValueChanged).AddListener((UnityAction<string>)delegate(string value)
			{
				_itemSearch = value ?? string.Empty;
				RefreshItemTiles();
			});
			ButtonVisual buttonVisual = CreateButton((Transform)(object)val, "ChestFlow_RuleEditor_SearchClear", "×", 15f, (TextAlignmentOptions)514);
			SetRightFill(buttonVisual.Rect, 26f, 2f, 2f, 2f);
			((UnityEvent)buttonVisual.Button.onClick).AddListener((UnityAction)delegate
			{
				_itemSearch = string.Empty;
				input.SetTextWithoutNotify(string.Empty);
				RefreshItemTiles();
			});
			return val;
		}

		private static void RefreshItemTiles()
		{
			if (!((Object)(object)_itemContent == (Object)null))
			{
				ClearChildren(_itemContent);
				RenderItemTiles(_itemContent);
				RefreshBrowserRailCounts(items: true);
			}
		}

		private static void RenderItemTiles(RectTransform content)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Expected O, but got Unknown
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Expected O, but got Unknown
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Expected O, but got Unknown
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0417: Expected O, but got Unknown
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d2: Expected O, but got Unknown
			IEnumerable<ItemChoice> source = ItemChoices;
			if (!string.Equals(_activeItemGroupId, "all", StringComparison.OrdinalIgnoreCase))
			{
				source = source.Where((ItemChoice choice) => string.Equals(ItemCategoryCatalog.Get(choice.Category).GroupId, _activeItemGroupId, StringComparison.OrdinalIgnoreCase));
			}
			string query = (_itemSearch ?? string.Empty).Trim();
			if (query.Length > 0)
			{
				source = source.Where((ItemChoice choice) => choice.SearchText.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0);
			}
			List<ItemChoice> list = source.ToList();
			float num = 620f;
			Transform parent = ((Transform)content).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if (val != null)
			{
				Rect rect = val.rect;
				if (((Rect)(ref rect)).width > 10f)
				{
					rect = val.rect;
					num = ((Rect)(ref rect)).width;
				}
			}
			float num2 = (num - 14f - 4f) / 3f;
			Vector2 val2 = default(Vector2);
			for (int num3 = 0; num3 < list.Count; num3++)
			{
				ItemChoice itemChoice = list[num3];
				int num4 = num3 % 3;
				int num5 = num3 / 3;
				ButtonVisual visual = CreateButton((Transform)(object)content, "ChestFlow_RuleEditor_Item_" + num3, string.Empty, 11f, (TextAlignmentOptions)514);
				RectTransform rect2 = visual.Rect;
				RectTransform rect3 = visual.Rect;
				((Vector2)(ref val2))..ctor(0f, 1f);
				rect3.anchorMax = val2;
				rect2.anchorMin = val2;
				visual.Rect.pivot = new Vector2(0f, 1f);
				visual.Rect.anchoredPosition = new Vector2((float)num4 * (num2 + 7f), (float)(-num5) * 65f);
				visual.Rect.sizeDelta = new Vector2(num2, 58f);
				((Component)visual.Label).gameObject.SetActive(false);
				RectTransform obj = CreateRect("ChestFlow_RuleEditor_Icon", (Transform)(object)visual.Rect);
				((Vector2)(ref val2))..ctor(0f, 0.5f);
				obj.anchorMax = val2;
				obj.anchorMin = val2;
				obj.pivot = new Vector2(0f, 0.5f);
				obj.anchoredPosition = new Vector2(8f, 0f);
				obj.sizeDelta = new Vector2(40f, 40f);
				Image val3 = ((Component)obj).gameObject.AddComponent<Image>();
				val3.sprite = itemChoice.Icon;
				val3.preserveAspect = true;
				((Graphic)val3).raycastTarget = false;
				if ((Object)(object)itemChoice.Icon == (Object)null)
				{
					((Graphic)val3).color = new Color(1f, 1f, 1f, 0.2f);
				}
				TMP_Text obj2 = CreateText((Transform)(object)visual.Rect, "ChestFlow_RuleEditor_ItemName", itemChoice.DisplayName, 11.5f, Cream, (TextAlignmentOptions)257);
				SetTopRect((RectTransform)obj2.transform, 54f, 7f, 24f, 24f);
				obj2.textWrappingMode = (TextWrappingModes)1;
				obj2.overflowMode = (TextOverflowModes)1;
				SetTopRect((RectTransform)CreateText((Transform)(object)visual.Rect, "ChestFlow_RuleEditor_ItemCategory", ItemCategoryCatalog.Get(itemChoice.Category).DisplayName, 8.5f, Gold, (TextAlignmentOptions)1025).transform, 54f, 32f, 24f, 18f);
				TMP_Text check = CreateText((Transform)(object)visual.Rect, "ChestFlow_RuleEditor_ItemCheck", "✓", 14f, Gold, (TextAlignmentOptions)514);
				SetRightFill((RectTransform)check.transform, 22f, 2f, 2f, 36f);
				SetCategoryVisual(visual, check, SelectedItems.Contains(itemChoice.PrefabName));
				string prefabName = itemChoice.PrefabName;
				((UnityEvent)visual.Button.onClick).AddListener((UnityAction)delegate
				{
					if (!SelectedItems.Add(prefabName))
					{
						SelectedItems.Remove(prefabName);
					}
					SetCategoryVisual(visual, check, SelectedItems.Contains(prefabName));
					RefreshBrowserRailCounts(items: true);
				});
				if ((Object)(object)_gui != (Object)null)
				{
					VanillaTooltip.Attach(((Component)visual.Button).gameObject, (Component)(object)_gui, itemChoice.DisplayName, itemChoice.PrefabName);
				}
			}
			int num6 = (list.Count + 3 - 1) / 3;
			SetContentHeight(content, Mathf.Max(20f, (float)num6 * 65f));
			if (list.Count == 0)
			{
				SetTopRect((RectTransform)CreateText((Transform)(object)content, "ChestFlow_RuleEditor_NoItems", "No known items match this filter", 12f, Muted, (TextAlignmentOptions)257).transform, 8f, 8f, 8f, 26f);
			}