Decompiled source of Stackmaster v1.4.4

plugins/Stackmaster/Stackmaster.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Stackmaster.Core;
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.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("JStack424")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Inventory sorting and nearby-storage planning for Valheim.")]
[assembly: AssemblyFileVersion("1.4.4.0")]
[assembly: AssemblyInformationalVersion("1.4.4+100d406b7cf7013739d0964b152c21b93c2ee790")]
[assembly: AssemblyProduct("Stackmaster")]
[assembly: AssemblyTitle("Stackmaster")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/JStack424/Stackmaster")]
[assembly: AssemblyVersion("1.4.4.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 Stackmaster
{
	internal static class AtomicReservationFileStore
	{
		private const string DirectoryName = "Stackmaster.Reservations";

		internal static bool TryRead(string logicalKey, out string payload, out bool exists)
		{
			payload = string.Empty;
			exists = false;
			string path = PathFor(logicalKey);
			if (!File.Exists(path))
			{
				return true;
			}
			payload = File.ReadAllText(path, Encoding.UTF8);
			exists = true;
			return true;
		}

		internal static bool TryWrite(string logicalKey, string previousPayload, string candidatePayload)
		{
			if (string.IsNullOrEmpty(logicalKey) || previousPayload == null || candidatePayload == null)
			{
				return false;
			}
			string text = PathFor(logicalKey);
			Directory.CreateDirectory(Path.GetDirectoryName(text));
			string text2 = text + "." + Guid.NewGuid().ToString("N") + ".tmp";
			try
			{
				WriteThrough(text2, candidatePayload);
				try
				{
					if (File.Exists(text))
					{
						File.Replace(text2, text, null);
					}
					else
					{
						File.Move(text2, text);
					}
					text2 = null;
					return true;
				}
				catch
				{
					if (DestinationEquals(text, candidatePayload))
					{
						text2 = null;
						return true;
					}
					if (DestinationEquals(text, previousPayload))
					{
						return false;
					}
					throw;
				}
			}
			finally
			{
				if (!string.IsNullOrEmpty(text2))
				{
					try
					{
						File.Delete(text2);
					}
					catch
					{
					}
				}
			}
		}

		private static bool DestinationEquals(string path, string expected)
		{
			if (File.Exists(path))
			{
				return string.Equals(File.ReadAllText(path, Encoding.UTF8), expected, StringComparison.Ordinal);
			}
			return false;
		}

		private static void WriteThrough(string path, string payload)
		{
			byte[] bytes = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(payload);
			using FileStream fileStream = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None, 4096, FileOptions.WriteThrough);
			fileStream.Write(bytes, 0, bytes.Length);
			fileStream.Flush(flushToDisk: true);
		}

		private static string PathFor(string logicalKey)
		{
			if (string.IsNullOrEmpty(logicalKey))
			{
				throw new ArgumentException("A reservation storage key is required.", "logicalKey");
			}
			byte[] array;
			using (SHA256 sHA = SHA256.Create())
			{
				array = sHA.ComputeHash(Encoding.UTF8.GetBytes(logicalKey));
			}
			string path = BitConverter.ToString(array).Replace("-", string.Empty).ToLowerInvariant() + ".json";
			return Path.Combine(Paths.ConfigPath, "Stackmaster.Reservations", path);
		}
	}
	internal static class ChestSortPreferences
	{
		private static readonly FieldInfo NetworkViewField = AccessTools.Field(typeof(Container), "m_nview");

		private static readonly HashSet<string> SessionDisabled = new HashSet<string>(StringComparer.Ordinal);

		private static bool _storageHealthy;

		private static bool _failureLogged;

		internal static void Initialize()
		{
			SessionDisabled.Clear();
			_storageHealthy = true;
			_failureLogged = false;
		}

		internal static bool TryGet(Container container, out string key, out bool enabled)
		{
			key = string.Empty;
			enabled = false;
			if (!TryCreateKey(container, out key))
			{
				LogFailureOnce("Opened chest has no stable local player/world/ZDO identity; chest auto-sort was skipped.");
				return false;
			}
			if (SessionDisabled.Contains(key))
			{
				return true;
			}
			if (!_storageHealthy)
			{
				return false;
			}
			try
			{
				bool num = PlayerPrefs.HasKey(key);
				int storedValue = ((!num) ? 1 : PlayerPrefs.GetInt(key, -1));
				if (!ChestSortPreferencePolicy.TryInterpretStoredValue(num, storedValue, out enabled))
				{
					DisableStorage("A saved chest auto-sort preference had an invalid value; chest auto-sort was disabled safely.");
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				DisableStorage("Local chest auto-sort preferences could not be read; chest auto-sort was disabled safely: " + ex.GetType().Name);
				return false;
			}
		}

		internal static bool TrySet(string key, bool enabled)
		{
			if (string.IsNullOrEmpty(key) || !_storageHealthy)
			{
				return false;
			}
			if (enabled)
			{
				SessionDisabled.Remove(key);
			}
			else
			{
				SessionDisabled.Add(key);
			}
			try
			{
				if (enabled)
				{
					PlayerPrefs.DeleteKey(key);
				}
				else
				{
					PlayerPrefs.SetInt(key, 0);
				}
				PlayerPrefs.Save();
				return true;
			}
			catch (Exception ex)
			{
				SessionDisabled.Add(key);
				DisableStorage("Local chest auto-sort preferences could not be saved; chest auto-sort was disabled safely: " + ex.GetType().Name);
				return false;
			}
		}

		internal static void Shutdown()
		{
			SessionDisabled.Clear();
			_storageHealthy = false;
		}

		private static bool TryCreateKey(Container container, out string key)
		{
			key = string.Empty;
			if ((Object)(object)container == (Object)null || ((object)container).GetType() != typeof(Container) || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || NetworkViewField == null)
			{
				return false;
			}
			object? value = NetworkViewField.GetValue(container);
			ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return false;
			}
			ZDO zDO = val.GetZDO();
			if (zDO == null || ((ZDOID)(ref zDO.m_uid)).IsNone())
			{
				return false;
			}
			return ChestSortPreferencePolicy.TryCreateKey(Player.m_localPlayer.GetPlayerID(), ZNet.instance.GetWorldUID(), ((object)Unsafe.As<ZDOID, ZDOID>(ref zDO.m_uid)/*cast due to .constrained prefix*/).ToString(), out key);
		}

		private static void DisableStorage(string message)
		{
			_storageHealthy = false;
			LogFailureOnce(message);
		}

		private static void LogFailureOnce(string message)
		{
			if (!_failureLogged)
			{
				_failureLogged = true;
				Plugin plugin = RuntimeContext.Plugin;
				if (plugin != null)
				{
					plugin.Log.LogWarning((object)message);
				}
			}
		}
	}
	internal sealed class CompatibilityResult
	{
		internal bool IsCompatible { get; }

		internal string Reason { get; }

		internal string Diagnostics { get; }

		internal CompatibilityResult(bool isCompatible, string reason, string diagnostics = "")
		{
			IsCompatible = isCompatible;
			Reason = reason;
			Diagnostics = diagnostics;
		}
	}
	internal static class CompatibilityGate
	{
		internal static CompatibilityResult Evaluate()
		{
			List<string> list = new List<string>();
			string diagnostics = DescribeRuntimeIdentity();
			Type[] array = new Type[47]
			{
				typeof(InventoryGui),
				typeof(Container),
				typeof(InventoryGrid),
				typeof(ItemData),
				typeof(SharedData),
				typeof(Vector2i),
				typeof(Modifier),
				typeof(GameObject),
				typeof(Transform),
				typeof(Requirement),
				typeof(Player),
				typeof(Hud),
				typeof(BuildUi),
				typeof(ZDOID),
				typeof(ZDO),
				typeof(Inventory),
				typeof(ZPackage),
				typeof(ZNetView),
				typeof(Humanoid),
				typeof(Game),
				typeof(ZNet),
				typeof(ZDOMan),
				typeof(Character),
				typeof(TextViewer),
				typeof(GameCamera),
				typeof(PlayerPrefs),
				typeof(Recipe),
				typeof(RequirementMode),
				typeof(ZInput),
				typeof(SplitDialog),
				typeof(CraftingStation),
				typeof(ZNetScene),
				typeof(PrivateArea),
				typeof(Fireplace),
				typeof(Smelter),
				typeof(ItemConversion),
				typeof(CookingStation),
				typeof(ShieldGenerator),
				typeof(SiegeMachine),
				typeof(ItemDrop),
				typeof(Vector3),
				typeof(ZDOVars),
				typeof(TextInput),
				typeof(KeyHints),
				typeof(Localization),
				typeof(Text),
				typeof(InventoryElement)
			};
			foreach (Type type in array)
			{
				RuntimeContractValidator.RequireType(list, type);
			}
			HarmonyTargetManifest.Validate(list);
			RequireMethod(list, typeof(InventoryGui), "IsContainerOpen");
			RequireMethod(list, typeof(InventoryGui), "UpdateRecipe", typeof(Player), typeof(float));
			RequireStaticMethod(list, typeof(InventoryGui), "get_instance");
			RequireMethod(list, typeof(Container), "CheckAccess", typeof(long));
			RequireMethod(list, typeof(Container), "CheckForChanges");
			RequireMethod(list, typeof(Container), "GetInventory");
			RequireMethod(list, typeof(ZDOID), "IsNone");
			RequireMethod(list, typeof(ZDO), "GetByteArray", typeof(int), typeof(byte[]));
			RequireMethod(list, typeof(ZDO), "get_DataRevision");
			RequireMethod(list, typeof(ZDO), "get_OwnerRevision");
			RequireMethod(list, typeof(Inventory), "Load", typeof(ZPackage));
			RequireConstructor(list, typeof(Inventory), typeof(bool));
			RequireConstructor(list, typeof(ZPackage), typeof(byte[]));
			RequireMethod(list, typeof(ZNetView), "HasOwner");
			RequireMethod(list, typeof(Container), "IsOwner");
			RequireMethod(list, typeof(Container), "IsInUse");
			RequireMethod(list, typeof(Container), "SetInUse", typeof(bool));
			RequireMethod(list, typeof(Container), "StackAll");
			RequireMethod(list, typeof(Container), "RPC_RequestStack", typeof(long), typeof(long));
			RequireMethod(list, typeof(ZDO), "GetOwner");
			RequireMethod(list, typeof(ZDO), "SetOwner", typeof(long));
			RequireStaticMethod(list, typeof(ZDOMan), "GetSessionID");
			RequireMethod(list, typeof(ZDOMan), "GetZDO", typeof(ZDOID));
			RequireMethod(list, typeof(ZDOMan), "ForceSendZDO", typeof(ZDOID));
			RequireMethod(list, typeof(Character), "IsDead");
			RequireMethod(list, typeof(Character), "InCutscene");
			RequireMethod(list, typeof(Character), "IsTeleporting");
			RequireStaticMethod(list, typeof(TextViewer), "get_instance");
			RequireMethod(list, typeof(TextViewer), "IsVisible");
			RequireStaticMethod(list, typeof(GameCamera), "InFreeFly");
			RequireMethod(list, typeof(InventoryGrid), "GetInventory");
			RequireMethod(list, typeof(InventoryGrid), "GetHoveredElement");
			RequireMethod(list, typeof(Inventory), "MoveItemToThis", typeof(Inventory), typeof(ItemData), typeof(int), typeof(int), typeof(int));
			RequireMethod(list, typeof(Inventory), "GetWidth");
			RequireMethod(list, typeof(Inventory), "GetHeight");
			RequireMethod(list, typeof(Inventory), "GetTotalWeight");
			RequireMethod(list, typeof(Inventory), "ContainsItem", typeof(ItemData));
			RequireMethod(list, typeof(Inventory), "GetAllItems");
			RequireMethod(list, typeof(Inventory), "GetItemAt", typeof(int), typeof(int));
			RequireMethod(list, typeof(Inventory), "RemoveAll");
			RequireMethod(list, typeof(Inventory), "CountItems", typeof(string), typeof(int), typeof(bool));
			RequireMethod(list, typeof(Inventory), "RemoveItem", typeof(ItemData), typeof(int));
			RequireMethod(list, typeof(Inventory), "RemoveItem", typeof(string), typeof(int), typeof(int), typeof(bool));
			RequireMethod(list, typeof(Inventory), "AddItem", typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool));
			RequireMethod(list, typeof(Player), "ConsumeResources", typeof(Requirement[]), typeof(int), typeof(int), typeof(int));
			RequireMethod(list, typeof(ItemData), "Clone");
			RequireMethod(list, typeof(ItemData), "GetWeight", typeof(int));
			RequireMethod(list, typeof(Requirement), "GetAmount", typeof(int));
			RequireMethod(list, typeof(Recipe), "GetAmount", typeof(int), typeof(int).MakeByRefType(), typeof(ItemData).MakeByRefType(), typeof(int));
			RequireMethod(list, typeof(Player), "GetHoverObject");
			RequireMethod(list, typeof(Player), "GetMaxCarryWeight");
			RequireMethod(list, typeof(Player), "GetPlayerID");
			RequireMethod(list, typeof(ZNet), "GetWorldUID");
			RequireStaticMethod(list, typeof(PlayerPrefs), "HasKey", typeof(string));
			RequireStaticMethod(list, typeof(PlayerPrefs), "GetInt", typeof(string), typeof(int));
			RequireStaticMethod(list, typeof(PlayerPrefs), "GetString", typeof(string), typeof(string));
			RequireStaticMethod(list, typeof(PlayerPrefs), "SetInt", typeof(string), typeof(int));
			RequireStaticMethod(list, typeof(PlayerPrefs), "SetString", typeof(string), typeof(string));
			RequireStaticMethod(list, typeof(PlayerPrefs), "DeleteKey", typeof(string));
			RequireStaticMethod(list, typeof(PlayerPrefs), "Save");
			RequireStaticMethod(list, typeof(ZInput), "ResetButtonStatus", typeof(string));
			RequireStaticMethod(list, typeof(ZInput), "IsGamepadActive");
			RequireMethod(list, typeof(Localization), "RemoveTextFromCache", typeof(Text));
			RequireMethod(list, typeof(SplitDialog), "get_IsActive");
			RequireMethod(list, typeof(ZNetView), "IsOwner");
			RequireMethod(list, typeof(ZNetView), "IsValid");
			RequireMethod(list, typeof(ZNetView), "GetZDO");
			RequireStaticMethod(list, typeof(CraftingStation), "get_Instances");
			RequireStaticMethod(list, typeof(CraftingStation), "HaveBuildStationInRange", typeof(string), typeof(Vector3));
			RequireMethod(list, typeof(CraftingStation), "GetStationBuildRange");
			RequireMethod(list, typeof(CraftingStation), "GetLevel", typeof(bool));
			RequireMethod(list, typeof(CraftingStation), "CheckUsable", typeof(Player), typeof(bool));
			RequireStaticMethod(list, typeof(ZNetScene), "get_instance");
			RequireMethod(list, typeof(ZNetScene), "GetPrefab", typeof(string));
			RequireMethod(list, typeof(ZNetScene), "GetPrefabHash", typeof(GameObject));
			RequireMethod(list, typeof(ZDO), "GetPrefab");
			RequireMethod(list, typeof(ZNetView), "InvokeRPC", typeof(string), typeof(object[]));
			RequireStaticMethod(list, typeof(PrivateArea), "CheckAccess", typeof(Vector3), typeof(float), typeof(bool), typeof(bool));
			RequireField(list, typeof(InventoryGui), "m_pvp");
			RequireField(list, typeof(InventoryGui), "m_container");
			RequireField(list, typeof(InventoryGui), "m_playerGrid");
			RequireField(list, typeof(InventoryGui), "m_currentContainer");
			RequireField(list, typeof(InventoryGui), "m_craftTimer");
			RequireField(list, typeof(InventoryGui), "m_craftRecipe");
			RequireField(list, typeof(InventoryGui), "m_selectedRecipe");
			RequireField(list, typeof(InventoryGui), "m_reqList");
			RequireField(list, typeof(InventoryGui), "m_craftUpgradeItem");
			RequireField(list, typeof(InventoryGui), "m_selectedVariant");
			RequireField(list, typeof(InventoryGui), "m_craftVariant");
			RequireField(list, typeof(InventoryGui), "m_touchMultiCrafting");
			Type type2 = AccessTools.Inner(typeof(InventoryGui), "RecipeDataPair");
			if (type2 == null)
			{
				list.Add("InventoryGui.RecipeDataPair missing");
			}
			else
			{
				RequireProperty(list, type2, "Recipe");
				RequireProperty(list, type2, "ItemData");
			}
			RequireField(list, typeof(InventoryGui), "m_multiCrafting");
			RequireField(list, typeof(InventoryGui), "m_multiCraftAmount");
			RequireField(list, typeof(InventoryGui), "m_dragItem");
			RequireField(list, typeof(InventoryGui), "m_dragInventory");
			RequireField(list, typeof(InventoryGui), "m_trophiesPanel");
			RequireField(list, typeof(InventoryGui), "m_achievementsPanel");
			RequireField(list, typeof(InventoryGui), "m_skillsDialog");
			RequireField(list, typeof(InventoryGui), "m_textsDialog");
			RequireField(list, typeof(InventoryGui), "m_splitDialog");
			RequireField(list, typeof(InventoryGui), "m_variantDialog");
			RequireField(list, typeof(Hud), "m_requirementItems");
			RuntimeContractValidator.RequireField(list, typeof(Hud), "m_hoverName", typeof(TextMeshProUGUI), mustBeStatic: false);
			RequireField(list, typeof(KeyHints), "m_buildMenuHintsKB");
			RequireField(list, typeof(Container), "m_nview");
			RequireField(list, typeof(Container), "m_wagon");
			RequireField(list, typeof(ZDO), "m_uid");
			RequireField(list, typeof(ZDOVars), "s_items");
			RequireField(list, typeof(Inventory), "m_onChanged");
			RequireField(list, typeof(Inventory), "m_inventory");
			RequireField(list, typeof(Player), "m_customData");
			RequireField(list, typeof(Player), "m_noPlacementCost");
			RequireField(list, typeof(TextInput), "m_inputField");
			RequireProperty(list, typeof(InventoryElement), "Position");
			RequireField(list, typeof(ItemData), "m_gridPos");
			RuntimeContractValidator.RequireField(list, typeof(ItemData), "m_shared", typeof(SharedData), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(SharedData), "m_maxStackSize", typeof(int), mustBeStatic: false);
			RequireField(list, typeof(ItemData), "m_stack");
			RequireField(list, typeof(ItemData), "m_quality");
			RequireField(list, typeof(ItemData), "m_dropPrefab");
			RequireField(list, typeof(ItemData), "m_worldLevel");
			RequireField(list, typeof(ItemData), "m_equipped");
			RequireField(list, typeof(Piece), "m_resources");
			RuntimeContractValidator.RequireField(list, typeof(Piece), "m_name", typeof(string), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Piece), "m_enabled", typeof(bool), mustBeStatic: false);
			RequireMethod(list, typeof(Piece), "IsPlacedByPlayer");
			RequireField(list, typeof(Requirement), "m_resItem");
			RequireField(list, typeof(Requirement), "m_amount");
			RequireField(list, typeof(Piece), "m_craftingStation");
			RuntimeContractValidator.RequireField(list, typeof(Player), "m_placementGhost", typeof(GameObject), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Player), "m_placementStatus", typeof(PlacementStatus), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(CraftingStation), "m_name", typeof(string), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(ItemDrop), "m_itemData", typeof(ItemData), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Fireplace), "m_canRefill", typeof(bool), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Fireplace), "m_infiniteFuel", typeof(bool), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Fireplace), "m_maxFuel", typeof(float), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Fireplace), "m_fuelItem", typeof(ItemDrop), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Smelter), "m_maxFuel", typeof(int), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Smelter), "m_fuelItem", typeof(ItemDrop), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Smelter), "m_conversion", typeof(List<ItemConversion>), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(ItemConversion), "m_from", typeof(ItemDrop), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(ShieldGenerator), "m_fuelItems", typeof(List<ItemDrop>), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(SiegeMachine), "m_engine", typeof(Smelter), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(CookingStation), "m_useFuel", typeof(bool), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(CookingStation), "m_maxFuel", typeof(int), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(CookingStation), "m_fuelItem", typeof(ItemDrop), mustBeStatic: false);
			RequireField(list, typeof(Recipe), "m_resources");
			RequireField(list, typeof(Recipe), "m_requireOnlyOneIngredient");
			if (list.Count != 0)
			{
				return new CompatibilityResult(isCompatible: false, string.Join("; ", list), diagnostics);
			}
			return new CompatibilityResult(isCompatible: true, "verified runtime contract", diagnostics);
		}

		internal static CompatibilityResult EvaluateExpeditionReservationUi()
		{
			List<string> list = new List<string>();
			RuntimeContractValidator.RequireField(list, typeof(Piece), "m_icon", typeof(Sprite), mustBeStatic: false);
			if (list.Count != 0)
			{
				return new CompatibilityResult(isCompatible: false, string.Join("; ", list));
			}
			return new CompatibilityResult(isCompatible: true, "verified optional reservation UI contract");
		}

		internal static CompatibilityResult EvaluateBuildMenuReservationUi()
		{
			List<string> list = new List<string>();
			RuntimeContractValidator.RequireField(list, typeof(Piece), "m_icon", typeof(Sprite), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(Hud), "m_buildUi", typeof(BuildUi), mustBeStatic: false);
			RuntimeContractValidator.RequireField(list, typeof(BuildUi), "m_tabContainer", typeof(RectTransform), mustBeStatic: false);
			RuntimeContractValidator.RequireMethod(list, typeof(Hud), "IsPieceSelectionVisible", true, false);
			RuntimeContractValidator.RequireMethod(list, typeof(BuildUi), "OnSelectPiece", false, false, typeof(Piece));
			if (list.Count != 0)
			{
				return new CompatibilityResult(isCompatible: false, string.Join("; ", list));
			}
			return new CompatibilityResult(isCompatible: true, "verified optional build-menu reservation UI contract");
		}

		private static string DescribeRuntimeIdentity()
		{
			//IL_000f: 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)
			Assembly assembly = typeof(Player).Assembly;
			string text = ((object)Version.CurrentVersion/*cast due to .constrained prefix*/).ToString();
			string unityVersion = Application.unityVersion;
			string text2 = typeof(BaseUnityPlugin).Assembly.GetName().Version?.ToString() ?? "unknown";
			string text3 = typeof(Harmony).Assembly.GetName().Version?.ToString() ?? "unknown";
			Guid moduleVersionId = assembly.ManifestModule.ModuleVersionId;
			string[] obj = new string[12]
			{
				"Valheim label ",
				Application.version,
				", API ",
				text,
				", Unity ",
				unityVersion,
				", BepInEx ",
				text2,
				", Harmony ",
				text3,
				", assembly_valheim MVID ",
				null
			};
			Guid guid = moduleVersionId;
			obj[11] = guid.ToString();
			return string.Concat(obj);
		}

		private static void RequireMethod(ICollection<string> failures, Type type, string name, params Type[] parameters)
		{
			RuntimeContractValidator.RequireMethod(failures, type, name, mustBeStatic: false, declaredOnly: false, parameters);
		}

		private static void RequireStaticMethod(ICollection<string> failures, Type type, string name, params Type[] parameters)
		{
			RuntimeContractValidator.RequireMethod(failures, type, name, mustBeStatic: true, declaredOnly: false, parameters);
		}

		private static void RequireConstructor(ICollection<string> failures, Type type, params Type[] parameters)
		{
			RuntimeContractValidator.RequireConstructor(failures, type, parameters);
		}

		private static void RequireProperty(ICollection<string> failures, Type type, string name)
		{
			RuntimeContractValidator.RequireProperty(failures, type, name);
		}

		private static void RequireField(ICollection<string> failures, Type type, string name)
		{
			RuntimeContractValidator.RequireField(failures, type, name);
		}
	}
	internal static class ConfigMigration
	{
		internal static ConfigEntry<KeyboardShortcut> BindRenamedKeyboardShortcut(ConfigFile config, string section, string legacyKey, string currentKey, KeyboardShortcut defaultShortcut, string currentDescription)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			bool saveOnConfigSet = config.SaveOnConfigSet;
			config.SaveOnConfigSet = false;
			try
			{
				ConfigEntry<KeyboardShortcut> val = config.Bind<KeyboardShortcut>(section, legacyKey, defaultShortcut, "Legacy Stackmaster setting; migrated automatically and removed from the saved configuration.");
				ConfigEntry<KeyboardShortcut> val2 = config.Bind<KeyboardShortcut>(section, currentKey, defaultShortcut, currentDescription);
				if (((object)val2.Value/*cast due to .constrained prefix*/).Equals((object?)defaultShortcut) && !((object)val.Value/*cast due to .constrained prefix*/).Equals((object?)defaultShortcut))
				{
					val2.Value = val.Value;
				}
				if (!config.Remove(((ConfigEntryBase)val).Definition))
				{
					throw new InvalidOperationException("Could not retire legacy Stackmaster configuration key: " + legacyKey);
				}
				config.Save();
				return val2;
			}
			finally
			{
				config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		internal static ConfigEntry<bool> BindRenamedDefaultEnabledBoolean(ConfigFile config, string section, string legacyKey, string currentKey, string currentDescription)
		{
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			bool saveOnConfigSet = config.SaveOnConfigSet;
			config.SaveOnConfigSet = false;
			try
			{
				ConfigEntry<bool> val = config.Bind<bool>(section, legacyKey, true, "Legacy Stackmaster setting; migrated automatically and removed from the saved configuration.");
				ConfigEntry<bool> val2 = config.Bind<bool>(section, currentKey, true, currentDescription);
				val2.Value = val.Value && val2.Value;
				if (!config.Remove(((ConfigEntryBase)val).Definition))
				{
					throw new InvalidOperationException("Could not retire legacy Stackmaster configuration key: " + legacyKey);
				}
				config.Save();
				return val2;
			}
			finally
			{
				config.SaveOnConfigSet = saveOnConfigSet;
			}
		}
	}
	internal sealed class ContainerHandle
	{
		internal string Id { get; }

		internal Container Container { get; }

		internal ZNetView NetworkView { get; }

		internal ZDO CapturedZdo { get; }

		internal ContainerSnapshot Snapshot { get; }

		internal Inventory ResourceInventory { get; }

		internal uint ResourceDataRevision { get; }

		internal uint ObservedDataRevision { get; }

		internal ZDOID ResourceZdoId { get; }

		internal ushort ResourceOwnerRevision { get; }

		internal long ResourceOwner { get; }

		internal bool ResourceReadable { get; }

		internal ContainerHandle(string id, Container container, ZNetView networkView, ZDO capturedZdo, ContainerSnapshot snapshot, Inventory resourceInventory, uint resourceDataRevision, uint observedDataRevision, ZDOID resourceZdoId, ushort resourceOwnerRevision, long resourceOwner, bool resourceReadable)
		{
			//IL_0044: 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)
			Id = id;
			Container = container;
			NetworkView = networkView;
			CapturedZdo = capturedZdo;
			Snapshot = snapshot;
			ResourceInventory = resourceInventory;
			ResourceDataRevision = resourceDataRevision;
			ObservedDataRevision = observedDataRevision;
			ResourceZdoId = resourceZdoId;
			ResourceOwnerRevision = resourceOwnerRevision;
			ResourceOwner = resourceOwner;
			ResourceReadable = resourceReadable;
		}
	}
	internal sealed class TargetDiscoveryDiagnostic
	{
		internal bool TargetPresent { get; }

		internal double Distance { get; }

		internal string Scope { get; }

		internal bool WithinScope { get; }

		internal bool Discovered { get; set; }

		internal string ObservedType { get; set; }

		internal bool? IsVanilla { get; set; }

		internal bool? HasNetworkView { get; set; }

		internal bool? NetworkViewValid { get; set; }

		internal bool? HasZdo { get; set; }

		internal bool? Refreshed { get; set; }

		internal bool? HasInventory { get; set; }

		internal bool? InUse { get; set; }

		internal bool? AccessGranted { get; set; }

		internal string RefreshFailure { get; set; }

		internal string AccessFailure { get; set; }

		internal TargetDiscoveryDiagnostic(bool targetPresent, double distance, StorageScope scope, Vector3 targetPosition)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			TargetPresent = targetPresent;
			Distance = distance;
			Scope = ((scope != null) ? scope.Description : "unavailable");
			WithinScope = targetPresent && scope != null && scope.Contains(targetPosition);
		}

		internal string Format(DiscoveryResult discovery)
		{
			return string.Format(CultureInfo.InvariantCulture, "targetPresent={0} discovered={1} distance={2} scope={3} withinScope={4} searchTruncated={5} truncationReason={6} searchMs={7:0.00} objectScanMs={8:0.00} inspectionMs={9:0.00} budgetMs={10:0.00} candidates={11} inspected={12} minimumBeforeBudget={13} maximumNearby={14} type={15} vanilla={16} nview={17} nviewValid={18} zdo={19} refresh={20} inventory={21} inUse={22} access={23} refreshError={24} accessError={25}", TargetPresent, Discovered, double.IsPositiveInfinity(Distance) ? "n/a" : Distance.ToString("0.0", CultureInfo.InvariantCulture), Scope, WithinScope, discovery.Truncated, discovery.TruncationReason ?? "none", discovery.SearchMilliseconds, discovery.ObjectScanMilliseconds, discovery.InspectionMilliseconds, 25.0, discovery.NearbyCandidates, discovery.InspectedNearby, 8, 128, ObservedType ?? "n/a", FormatNullable(IsVanilla), FormatNullable(HasNetworkView), FormatNullable(NetworkViewValid), FormatNullable(HasZdo), FormatNullable(Refreshed), FormatNullable(HasInventory), FormatNullable(InUse), FormatNullable(AccessGranted), Sanitize(RefreshFailure), Sanitize(AccessFailure));
		}

		private static string FormatNullable(bool? value)
		{
			if (!value.HasValue)
			{
				return "n/a";
			}
			return value.Value.ToString();
		}

		private static string Sanitize(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return "none";
			}
			string text = value.Replace('\r', ' ').Replace('\n', ' ').Trim();
			if (text.Length > 160)
			{
				return text.Substring(0, 160) + "…";
			}
			return text;
		}
	}
	internal sealed class DiscoveryResult
	{
		internal IReadOnlyList<ContainerHandle> Containers { get; }

		internal bool Truncated { get; }

		internal double SearchMilliseconds { get; }

		internal double ObjectScanMilliseconds { get; }

		internal double InspectionMilliseconds { get; }

		internal int NearbyCandidates { get; }

		internal int InspectedNearby { get; }

		internal string TruncationReason { get; }

		internal TargetDiscoveryDiagnostic TargetDiagnostic { get; }

		internal StorageScope Scope { get; }

		internal DiscoveryResult(IReadOnlyList<ContainerHandle> containers, bool truncated, double searchMilliseconds, double objectScanMilliseconds, double inspectionMilliseconds, int nearbyCandidates, int inspectedNearby, string truncationReason, TargetDiscoveryDiagnostic targetDiagnostic, StorageScope scope)
		{
			Containers = containers;
			Truncated = truncated;
			SearchMilliseconds = searchMilliseconds;
			ObjectScanMilliseconds = objectScanMilliseconds;
			InspectionMilliseconds = inspectionMilliseconds;
			NearbyCandidates = nearbyCandidates;
			InspectedNearby = inspectedNearby;
			TruncationReason = truncationReason;
			TargetDiagnostic = targetDiagnostic;
			Scope = scope;
		}
	}
	internal static class ContainerDiscovery
	{
		internal const double SearchBudgetMilliseconds = 25.0;

		internal const int MinimumNearbyContainersBeforeBudget = 8;

		internal const int MaximumNearbyContainers = 128;

		private static readonly NearbyInspectionPolicy NearbyPolicy = new NearbyInspectionPolicy(8, 128, 25.0);

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

		private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null);

		private static readonly MethodInfo CheckForChangesMethod = AccessTools.Method(typeof(Container), "CheckForChanges", (Type[])null, (Type[])null);

		internal static DiscoveryResult Discover(Player player, Container target, CompatibilityCatalog catalog, StorageScope scope, bool requireComplete = false, bool resourceReadOnly = false)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			List<ContainerHandle> list = new List<ContainerHandle>();
			scope = scope ?? StorageScopeProvider.Resolve(player);
			double distance = (((Object)(object)target != (Object)null) ? ((double)Vector3.Distance(((Component)player).transform.position, ((Component)target).transform.position)) : double.PositiveInfinity);
			TargetDiscoveryDiagnostic targetDiscoveryDiagnostic = new TargetDiscoveryDiagnostic((Object)(object)target != (Object)null, distance, scope, (Vector3)(((Object)(object)target != (Object)null) ? ((Component)target).transform.position : default(Vector3)));
			if ((Object)(object)target != (Object)null && scope.Contains(((Component)target).transform.position))
			{
				list.Add(Inspect(player, target, catalog, distance, isTarget: true, targetDiscoveryDiagnostic, resourceReadOnly));
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			Stopwatch stopwatch2 = Stopwatch.StartNew();
			var array = (from container in Object.FindObjectsByType<Container>((FindObjectsInactive)0, (FindObjectsSortMode)0)
				where (Object)(object)container != (Object)null && (Object)(object)container != (Object)(object)target
				select new
				{
					Container = container,
					Distance = (double)Vector3.Distance(((Component)player).transform.position, ((Component)container).transform.position)
				} into candidate
				where scope.Contains(((Component)candidate.Container).transform.position)
				orderby candidate.Distance, ((Object)candidate.Container).GetInstanceID()
				select candidate).ToArray();
			stopwatch2.Stop();
			Stopwatch stopwatch3 = Stopwatch.StartNew();
			int num = 0;
			string text = null;
			var array2 = array;
			foreach (var anon in array2)
			{
				double totalMilliseconds = stopwatch3.Elapsed.TotalMilliseconds;
				if (!requireComplete && !scope.RequiresCompleteDiscovery && !NearbyPolicy.CanInspectNext(num, totalMilliseconds))
				{
					text = NearbyPolicy.StopReason(num, totalMilliseconds);
					break;
				}
				list.Add(Inspect(player, anon.Container, catalog, anon.Distance, isTarget: false, null, resourceReadOnly));
				num++;
			}
			stopwatch3.Stop();
			stopwatch.Stop();
			bool flag = num < array.Length;
			if (flag && string.IsNullOrEmpty(text))
			{
				text = "responsiveness limit reached";
			}
			return new DiscoveryResult(list, flag, stopwatch.Elapsed.TotalMilliseconds, stopwatch2.Elapsed.TotalMilliseconds, stopwatch3.Elapsed.TotalMilliseconds, array.Length, num, text, targetDiscoveryDiagnostic, scope);
		}

		private static ContainerHandle Inspect(Player player, Container container, CompatibilityCatalog catalog, double distance, bool isTarget, TargetDiscoveryDiagnostic diagnostic, bool resourceReadOnly)
		{
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			object? value = NetworkViewField.GetValue(container);
			ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
			bool flag = (Object)(object)val != (Object)null && val.IsValid();
			ZDO val2 = (flag ? val.GetZDO() : null);
			string text = ((val2 != null) ? ((object)Unsafe.As<ZDOID, ZDOID>(ref val2.m_uid)/*cast due to .constrained prefix*/).ToString() : ("instance:" + ((Object)container).GetInstanceID()));
			Type type = ((object)container).GetType();
			bool flag2 = type == typeof(Container) && type.Assembly == typeof(Container).Assembly;
			string failure = null;
			bool flag3 = !resourceReadOnly && flag2 && flag && val2 != null && TryRefreshFromNetwork(container, out failure);
			Inventory val3 = (flag3 ? container.GetInventory() : null);
			bool flag4 = flag3 && val3 != null;
			bool flag5 = isTarget && StorageAction.IsLocalOpenTarget(container);
			bool flag6 = flag4 && ((!flag5 && container.IsInUse()) || ((Object)(object)container.m_wagon != (Object)null && container.m_wagon.InUse()));
			string failure2 = null;
			bool num;
			if (!resourceReadOnly)
			{
				num = flag4;
			}
			else
			{
				if (!(flag2 && flag))
				{
					goto IL_0140;
				}
				num = val2 != null;
			}
			if (!num)
			{
				goto IL_0140;
			}
			int num2 = (TryCheckAccess(player, container, out failure2) ? 1 : 0);
			goto IL_0141;
			IL_0140:
			num2 = 0;
			goto IL_0141;
			IL_0141:
			bool flag7 = (byte)num2 != 0;
			Inventory inventory = null;
			uint dataRevision = 0u;
			string failure3 = null;
			bool flag8 = resourceReadOnly && flag2 && flag && val2 != null && TryReadSerializedInventory(container, val2, out inventory, out dataRevision, out failure3);
			ResourceSnapshotReadPlan resourceSnapshotReadPlan = ResourceSnapshotPolicy.Evaluate(resourceReadOnly, flag4, flag7, flag6, flag8);
			bool captureLiveInventory = resourceSnapshotReadPlan.CaptureLiveInventory;
			int capacity = ((val3 != null) ? (val3.GetWidth() * val3.GetHeight()) : 0);
			IReadOnlyList<ItemStackSnapshot> readOnlyList2;
			if (!captureLiveInventory || val3 == null)
			{
				IReadOnlyList<ItemStackSnapshot> readOnlyList = Array.Empty<ItemStackSnapshot>();
				readOnlyList2 = readOnlyList;
			}
			else
			{
				readOnlyList2 = InventorySnapshots.CaptureInventory(text, val3, catalog).Items;
			}
			IReadOnlyList<ItemStackSnapshot> items = readOnlyList2;
			bool useDetachedInventory = resourceSnapshotReadPlan.UseDetachedInventory;
			if (!flag8 && string.IsNullOrEmpty(failure))
			{
				failure = failure3;
			}
			if (diagnostic != null)
			{
				diagnostic.Discovered = true;
				diagnostic.ObservedType = type.FullName;
				diagnostic.IsVanilla = flag2;
				diagnostic.HasNetworkView = (Object)(object)val != (Object)null;
				diagnostic.NetworkViewValid = flag;
				diagnostic.HasZdo = val2 != null;
				diagnostic.Refreshed = flag3;
				diagnostic.HasInventory = val3 != null;
				diagnostic.InUse = (flag4 ? new bool?(flag6) : ((bool?)null));
				diagnostic.AccessGranted = (flag4 ? new bool?(flag7) : ((bool?)null));
				diagnostic.RefreshFailure = failure;
				diagnostic.AccessFailure = failure2;
			}
			ContainerSnapshot snapshot = new ContainerSnapshot(text, distance, isTarget, flag4, captureLiveInventory, flag2, flag6, capacity, items);
			return new ContainerHandle(text, container, val, val2, snapshot, useDetachedInventory ? inventory : null, dataRevision, (val2 != null) ? val2.DataRevision : 0u, (ZDOID)(((??)val2?.m_uid) ?? default(ZDOID)), (ushort)((val2 != null) ? val2.OwnerRevision : 0), (val2 != null) ? val2.GetOwner() : 0, useDetachedInventory);
		}

		internal static bool TryReadSerializedInventory(Container container, ZDO zdo, out Inventory inventory, out uint dataRevision, out string failure)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			inventory = null;
			dataRevision = 0u;
			failure = null;
			try
			{
				uint dataRevision2 = zdo.DataRevision;
				byte[] byteArray = zdo.GetByteArray(ZDOVars.s_items, (byte[])null);
				uint dataRevision3 = zdo.DataRevision;
				if (dataRevision2 != dataRevision3)
				{
					failure = "container data revision changed while reading its serialized inventory";
					return false;
				}
				Inventory val = new Inventory(true);
				if (byteArray != null)
				{
					val.Load(new ZPackage(byteArray));
				}
				if (zdo.DataRevision != dataRevision3)
				{
					failure = "container data revision changed while decoding its serialized inventory";
					return false;
				}
				if (!DetachedItemHydrator.TryHydrate(val.GetAllItems(), delegate(ItemData item)
				{
					ItemDrop val2 = (((Object)(object)item.m_dropPrefab != (Object)null) ? item.m_dropPrefab.GetComponent<ItemDrop>() : null);
					return (!((Object)(object)val2 != (Object)null) || val2.m_itemData == null) ? null : val2.m_itemData.m_shared;
				}, delegate(ItemData item, SharedData shared)
				{
					item.m_shared = shared;
				}))
				{
					failure = "detached inventory item metadata could not be resolved";
					return false;
				}
				inventory = val;
				dataRevision = dataRevision3;
				return true;
			}
			catch (Exception ex)
			{
				failure = ex.Message;
				return false;
			}
		}

		internal static bool PersistedInventoryMatchesLive(Container container, out string failure)
		{
			failure = null;
			if ((Object)(object)container == (Object)null)
			{
				failure = "container disappeared before persistence verification";
				return false;
			}
			try
			{
				object? value = NetworkViewField.GetValue(container);
				ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
				ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null);
				Inventory inventory = container.GetInventory();
				if (val2 == null || inventory == null || !TryReadSerializedInventory(container, val2, out var inventory2, out var _, out failure))
				{
					if (string.IsNullOrEmpty(failure))
					{
						failure = "container persistence state was unavailable";
					}
					return false;
				}
				IEnumerable<string> first = InventoryRows(inventory);
				IEnumerable<string> second = InventoryRows(inventory2);
				if (!first.SequenceEqual<string>(second, StringComparer.Ordinal))
				{
					failure = "container inventory mutation was not persisted to its network state";
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				failure = "container persistence verification failed: " + ex.GetType().Name;
				return false;
			}
		}

		private static IEnumerable<string> InventoryRows(Inventory inventory)
		{
			return from item in inventory.GetAllItems()
				orderby item.m_gridPos.y, item.m_gridPos.x
				select string.Join("\u001f", item.m_gridPos.x.ToString(CultureInfo.InvariantCulture), item.m_gridPos.y.ToString(CultureInfo.InvariantCulture), InventorySnapshots.PersistentItemKey(item), item.m_stack.ToString(CultureInfo.InvariantCulture));
		}

		internal static bool RefreshFromNetwork(Container container)
		{
			string failure;
			bool num = TryRefreshFromNetwork(container, out failure);
			if (!num && (Object)(object)RuntimeContext.Plugin != (Object)null)
			{
				RuntimeContext.Plugin.Log.LogWarning((object)("Container refresh failed safely: " + failure));
			}
			return num;
		}

		private static bool TryRefreshFromNetwork(Container container, out string failure)
		{
			failure = null;
			try
			{
				CheckForChangesMethod.Invoke(container, null);
				return true;
			}
			catch (Exception ex)
			{
				TargetInvocationException ex2 = ex as TargetInvocationException;
				failure = ((ex2 == null) ? ex.Message : (ex2.InnerException?.Message ?? ex2.Message));
				return false;
			}
		}

		internal static bool CheckAccess(Player player, Container container)
		{
			string failure;
			bool num = TryCheckAccess(player, container, out failure);
			if (!num && !string.IsNullOrEmpty(failure) && (Object)(object)RuntimeContext.Plugin != (Object)null)
			{
				RuntimeContext.Plugin.Log.LogWarning((object)("Container access check failed safely: " + failure));
			}
			return num;
		}

		private static bool TryCheckAccess(Player player, Container container, out string failure)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			failure = null;
			try
			{
				if (container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false))
				{
					return false;
				}
				return (bool)CheckAccessMethod.Invoke(container, new object[1] { player.GetPlayerID() });
			}
			catch (Exception ex)
			{
				TargetInvocationException ex2 = ex as TargetInvocationException;
				failure = ((ex2 == null) ? ex.Message : (ex2.InnerException?.Message ?? ex2.Message));
				return false;
			}
		}
	}
	internal sealed class SessionToken
	{
		internal ZNet Network { get; }

		internal long LocalSession { get; }

		internal SessionToken(ZNet network, long localSession)
		{
			Network = network;
			LocalSession = localSession;
		}

		internal static bool TryCapture(out SessionToken token)
		{
			token = null;
			if (!RuntimeContext.Compatibility.IsCompatible || (Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null)
			{
				return false;
			}
			token = new SessionToken(ZNet.instance, ZDOMan.GetSessionID());
			return true;
		}

		internal bool IsCurrent()
		{
			if (RuntimeContext.Compatibility.IsCompatible && Network == ZNet.instance && ZDOMan.instance != null)
			{
				return ZDOMan.GetSessionID() == LocalSession;
			}
			return false;
		}
	}
	internal sealed class CraftingIntent
	{
		internal InventoryGui Gui { get; }

		internal Player Player { get; }

		internal Recipe Recipe { get; }

		internal ItemData UpgradeItem { get; }

		internal int Quality { get; }

		internal int Variant { get; }

		internal bool MultiCrafting { get; }

		internal int Multiplier { get; }

		internal CraftingStation Station { get; }

		internal int StationLevel { get; }

		internal Vector3 PlayerPosition { get; }

		internal string ScopeSignature { get; }

		internal SessionToken Session { get; }

		internal CraftingIntent(InventoryGui gui, Player player, Recipe recipe, ItemData upgradeItem, int quality, int variant, bool multiCrafting, int multiplier, CraftingStation station, StorageScope scope, SessionToken session)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			Gui = gui;
			Player = player;
			Recipe = recipe;
			UpgradeItem = upgradeItem;
			Quality = quality;
			Variant = variant;
			MultiCrafting = multiCrafting;
			Multiplier = multiplier;
			Station = station;
			StationLevel = ((!((Object)(object)station == (Object)null)) ? station.GetLevel(true) : 0);
			PlayerPosition = ((Component)player).transform.position;
			ScopeSignature = scope?.Signature;
			Session = session;
		}
	}
	internal static class CraftingPreflightAction
	{
		private const float OwnershipTimeoutSeconds = 3f;

		private static readonly CraftingActionLifecycle Lifecycle = new CraftingActionLifecycle();

		private static readonly MethodInfo OnCraftPressedMethod = AccessTools.Method(typeof(InventoryGui), "OnCraftPressed", Type.EmptyTypes, (Type[])null);

		private static readonly FieldInfo SelectedRecipeField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");

		private static readonly Type RecipeDataPairType = AccessTools.Inner(typeof(InventoryGui), "RecipeDataPair");

		private static readonly PropertyInfo SelectedRecipeProperty = AccessTools.Property(RecipeDataPairType, "Recipe");

		private static readonly PropertyInfo SelectedUpgradeItemProperty = AccessTools.Property(RecipeDataPairType, "ItemData");

		private static readonly FieldInfo SelectedVariantField = AccessTools.Field(typeof(InventoryGui), "m_selectedVariant");

		private static readonly FieldInfo CraftRecipeField = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe");

		private static readonly FieldInfo CraftUpgradeItemField = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem");

		private static readonly FieldInfo CraftVariantField = AccessTools.Field(typeof(InventoryGui), "m_craftVariant");

		private static readonly FieldInfo MultiCraftingField = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting");

		private static readonly FieldInfo MultiCraftAmountField = AccessTools.Field(typeof(InventoryGui), "m_multiCraftAmount");

		private static readonly FieldInfo TouchMultiCraftingField = AccessTools.Field(typeof(InventoryGui), "m_touchMultiCrafting");

		private static readonly FieldInfo CraftTimerField = AccessTools.Field(typeof(InventoryGui), "m_craftTimer");

		private static CraftingIntent _intent;

		private static CraftingResourcePlan _plan;

		private static PreparedCraftingResources _prepared;

		private static OwnershipBatch _ownership;

		private static int _generation;

		private static bool _resuming;

		internal static bool Prefix(InventoryGui gui)
		{
			if (_resuming)
			{
				return true;
			}
			if (!RuntimeContext.Compatibility.IsCompatible || (Object)(object)RuntimeContext.Plugin == (Object)null || !RuntimeContext.Plugin.CraftingFromNearbyChestsEnabled.Value)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || localPlayer.NoCostCheat() || ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)25)))
			{
				return true;
			}
			if (Lifecycle.IsActive)
			{
				if (_intent != null && IsSelectionCurrent(_intent, requireCraftFields: false))
				{
					Show("Stackmaster: securing the required nearby materials.");
					return false;
				}
				Cancel("a newer crafting intent replaced the pending craft", notify: false);
			}
			if (ShouldUseVanillaPlayerInventory(gui))
			{
				VanillaPlayerCraftContext.Begin();
				return true;
			}
			if (!TryCaptureIntent(gui, out var intent))
			{
				return true;
			}
			if (!NearbyResourceService.TryPlanCraftingResources(intent.Player, intent.Recipe, intent.Quality, intent.Multiplier, out var planned, out var failure))
			{
				if (NearbyResourceService.IsTooFarFailure(failure))
				{
					Show("Stackmaster: You're too far away from the required resources (over 100 m); nothing was consumed.");
					return false;
				}
				return true;
			}
			if (planned.Plan.RequiredUnits == 0)
			{
				return true;
			}
			_intent = intent;
			_plan = planned;
			ContainerHandle[] array = planned.RequiredHandles.Where((ContainerHandle handle) => !handle.NetworkView.IsOwner() || !handle.Container.IsOwner()).ToArray();
			_generation = Lifecycle.Begin(array.Length != 0);
			if (array.Length == 0)
			{
				if (!TryPrepare(out failure))
				{
					Cancel(failure, notify: true);
					return false;
				}
				return true;
			}
			Show("Stackmaster: securing the required nearby materials.");
			((MonoBehaviour)RuntimeContext.Plugin).StartCoroutine(AcquireAndResume(_generation, intent.Session, array));
			return false;
		}

		internal static void AfterVanillaStart(InventoryGui gui)
		{
			VanillaPlayerCraftContext.End();
			if (!Lifecycle.Matches(_generation) || Lifecycle.Phase != CraftingActionPhase.Reserved || _intent == null || gui != _intent.Gui)
			{
				return;
			}
			if (_resuming)
			{
				MultiCraftingField.SetValue(gui, _intent.MultiCrafting);
				if (_intent.MultiCrafting)
				{
					MultiCraftAmountField.SetValue(gui, _intent.Multiplier);
				}
			}
			if (!IsSelectionCurrent(_intent, requireCraftFields: true) || GetCraftTimer(gui) < 0f || !Lifecycle.MarkCrafting(_generation))
			{
				Cancel("vanilla did not start the reserved craft", notify: true);
			}
		}

		internal static Exception Finalizer(Exception exception)
		{
			VanillaPlayerCraftContext.End();
			if (exception != null && Lifecycle.IsActive)
			{
				Cancel("craft start threw " + exception.GetType().Name, notify: true);
			}
			return exception;
		}

		internal static void Update(InventoryGui gui)
		{
			if (!Lifecycle.IsActive || _intent == null || gui != _intent.Gui)
			{
				return;
			}
			if (!RuntimeContext.Compatibility.IsCompatible || !_intent.Session.IsCurrent())
			{
				Cancel("the network session changed during crafting", notify: false);
				return;
			}
			bool flag = Lifecycle.Phase == CraftingActionPhase.Crafting;
			if (!IsSelectionCurrent(_intent, flag))
			{
				Cancel("the player, crafting selection, station, or storage scope changed", notify: true);
			}
			else if (flag && GetCraftTimer(gui) < 0f)
			{
				Cancel("the craft was canceled before completion", notify: false);
			}
		}

		internal static bool TryBeginPreparedTransaction(InventoryGui gui, Player player, Recipe recipe, int quality, int multiplier, out bool handled, out string failure)
		{
			handled = Lifecycle.IsActive;
			failure = null;
			if (!handled)
			{
				return false;
			}
			if (_intent == null || _prepared == null || gui != _intent.Gui || player != _intent.Player || recipe != _intent.Recipe || quality != _intent.Quality || multiplier != _intent.Multiplier || !IsSelectionCurrent(_intent, requireCraftFields: true) || !Lifecycle.TransferToTransaction(_generation))
			{
				failure = "the prepared crafting intent no longer matches the finishing craft";
				Cancel(failure, notify: true);
				return false;
			}
			PreparedCraftingResources prepared = _prepared;
			_prepared = null;
			ClearReferences();
			Lifecycle.FinishTransferred(_generation);
			if (!NearbyResourceService.TryBeginPreparedCraftingTransaction(player, prepared, out failure))
			{
				NearbyResourceService.ReleasePreparedCraftingResources(prepared);
				return false;
			}
			return true;
		}

		internal static void Cancel(string reason, bool notify)
		{
			if (Lifecycle.IsActive || _intent != null || _prepared != null || _ownership != null)
			{
				if (_intent != null && (Object)(object)_intent.Gui != (Object)null)
				{
					CraftTimerField.SetValue(_intent.Gui, -1f);
				}
				Lifecycle.Cancel();
				if (_prepared != null)
				{
					NearbyResourceService.ReleasePreparedCraftingResources(_prepared);
				}
				if (_ownership != null)
				{
					OwnershipCoordinator.Cancel(_ownership, reason);
				}
				ClearReferences();
				if (notify && !string.IsNullOrWhiteSpace(reason))
				{
					Show("Stackmaster: craft canceled — " + reason + ".");
				}
			}
		}

		internal static void Shutdown(string reason)
		{
			Cancel(reason, notify: false);
		}

		private static IEnumerator AcquireAndResume(int generation, SessionToken session, ContainerHandle[] unowned)
		{
			if (!Lifecycle.Matches(generation) || !session.IsCurrent())
			{
				yield break;
			}
			OwnershipBatch ownership;
			try
			{
				ownership = (_ownership = OwnershipCoordinator.Begin(unowned));
			}
			catch (Exception ex)
			{
				Cancel("ownership request failed: " + ex.GetType().Name, notify: true);
				yield break;
			}
			float deadline = Time.realtimeSinceStartup + 3f;
			while (Lifecycle.Matches(generation) && session.IsCurrent())
			{
				try
				{
					ownership.Refresh();
				}
				catch (Exception ex2)
				{
					Cancel("ownership refresh failed: " + ex2.GetType().Name, notify: true);
					yield break;
				}
				if (ownership.IsComplete)
				{
					break;
				}
				if (Time.realtimeSinceStartup >= deadline)
				{
					ownership.Timeout();
					break;
				}
				yield return null;
			}
			if (!Lifecycle.Matches(generation) || !session.IsCurrent())
			{
				if (_ownership == ownership)
				{
					OwnershipCoordinator.Cancel(ownership, "craft acquisition became stale");
					_ownership = null;
				}
				yield break;
			}
			try
			{
				ownership.Refresh();
				if (!ownership.IsComplete)
				{
					ownership.Timeout();
				}
				if (ownership.FailedContainerIds.Count != 0)
				{
					Cancel((ownership.OwnerRejectedContainerIds.Count != 0) ? "The required materials are currently in use" : "Stackmaster could not safely acquire the required materials", notify: true);
					yield break;
				}
				OwnershipLeaseManager.HoldForCrafting(ownership);
				OwnershipCoordinator.End(ownership);
				_ownership = null;
				if (!TryPrepare(out var failure))
				{
					OwnershipLeaseManager.ReleaseBatch(ownership, "craft reservation failed");
					Cancel(failure, notify: true);
					yield break;
				}
				if (!Lifecycle.MarkReserved(generation))
				{
					Cancel("the ownership callback was stale", notify: true);
					yield break;
				}
				TouchMultiCraftingField.SetValue(_intent.Gui, _intent.MultiCrafting);
				SelectedVariantField.SetValue(_intent.Gui, _intent.Variant);
				try
				{
					_resuming = true;
					OnCraftPressedMethod.Invoke(_intent.Gui, null);
				}
				finally
				{
					_resuming = false;
				}
			}
			catch (TargetInvocationException ex3)
			{
				Cancel("vanilla craft start threw " + (ex3.InnerException ?? ex3).GetType().Name, notify: true);
			}
			catch (Exception ex4)
			{
				Cancel("ownership preparation threw " + ex4.GetType().Name, notify: true);
			}
			finally
			{
				if (_ownership == ownership)
				{
					OwnershipCoordinator.Cancel(ownership, "craft acquisition ended before reservation");
					_ownership = null;
				}
			}
		}

		private static bool TryPrepare(out string failure)
		{
			failure = null;
			if (_intent == null || _plan == null || !IsSelectionCurrent(_intent, requireCraftFields: false))
			{
				failure = "the crafting selection changed before reservation";
				return false;
			}
			return NearbyResourceService.TryPrepareCraftingResources(_intent.Player, _plan, out _prepared, out failure);
		}

		private static bool ShouldUseVanillaPlayerInventory(InventoryGui gui)
		{
			Player localPlayer = Player.m_localPlayer;
			object value = SelectedRecipeField.GetValue(gui);
			Recipe val = (Recipe)((value == null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)localPlayer == (Object)null || value == null || (Object)(object)val == (Object)null)
			{
				return false;
			}
			object? value2 = SelectedUpgradeItemProperty.GetValue(value, null);
			ItemData val2 = (ItemData)((value2 is ItemData) ? value2 : null);
			int qualityLevel = ((val2 == null) ? 1 : (val2.m_quality + 1));
			int craftMultiplier = ((val2 != null || (!ZInput.GetButton("AltPlace") && !ZInput.GetButton("JoyLStick") && !(bool)TouchMultiCraftingField.GetValue(gui))) ? 1 : Math.Max(1, (int)MultiCraftAmountField.GetValue(gui)));
			return NearbyResourceService.ShouldUseVanillaPlayerInventoryCraft(localPlayer, val, qualityLevel, craftMultiplier);
		}

		private static bool TryCaptureIntent(InventoryGui gui, out CraftingIntent intent)
		{
			intent = null;
			Player localPlayer = Player.m_localPlayer;
			object value = SelectedRecipeField.GetValue(gui);
			Recipe val = (Recipe)((value == null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)localPlayer == (Object)null || value == null || (Object)(object)val == (Object)null)
			{
				return false;
			}
			object? value2 = SelectedUpgradeItemProperty.GetValue(value, null);
			ItemData val2 = (ItemData)((value2 is ItemData) ? value2 : null);
			int quality = ((val2 == null) ? 1 : (val2.m_quality + 1));
			bool flag = val2 == null && (ZInput.GetButton("AltPlace") || ZInput.GetButton("JoyLStick") || (bool)TouchMultiCraftingField.GetValue(gui));
			int multiplier = ((!flag) ? 1 : Math.Max(1, (int)MultiCraftAmountField.GetValue(gui)));
			StorageScope storageScope = StorageScopeProvider.Resolve(localPlayer);
			if (storageScope == null || !SessionToken.TryCapture(out var token))
			{
				return false;
			}
			intent = new CraftingIntent(gui, localPlayer, val, val2, quality, (int)SelectedVariantField.GetValue(gui), flag, multiplier, localPlayer.GetCurrentCraftingStation(), storageScope, token);
			return true;
		}

		private static bool IsSelectionCurrent(CraftingIntent intent, bool requireCraftFields)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			if (intent != null && !((Object)(object)intent.Player == (Object)null) && !((Object)(object)intent.Gui == (Object)null) && Player.m_localPlayer == intent.Player && !((Character)intent.Player).IsDead() && !((Character)intent.Player).IsTeleporting() && !((Character)intent.Player).InCutscene() && intent.Player.GetCurrentCraftingStation() == intent.Station && (!((Object)(object)intent.Station != (Object)null) || (intent.Station.CheckUsable(intent.Player, false) && intent.Station.GetLevel(true) == intent.StationLevel)))
			{
				Vector3 val = ((Component)intent.Player).transform.position - intent.PlayerPosition;
				if (!(((Vector3)(ref val)).sqrMagnitude > 0.0025f))
				{
					object value = SelectedRecipeField.GetValue(intent.Gui);
					if (value == null || SelectedRecipeProperty.GetValue(value, null) != intent.Recipe || SelectedUpgradeItemProperty.GetValue(value, null) != intent.UpgradeItem || (int)SelectedVariantField.GetValue(intent.Gui) != intent.Variant)
					{
						return false;
					}
					StorageScope storageScope = StorageScopeProvider.Resolve(intent.Player);
					if (storageScope == null || !string.Equals(storageScope.Signature, intent.ScopeSignature, StringComparison.Ordinal))
					{
						return false;
					}
					if (!requireCraftFields)
					{
						return true;
					}
					if (CraftRecipeField.GetValue(intent.Gui) == intent.Recipe && CraftUpgradeItemField.GetValue(intent.Gui) == intent.UpgradeItem && (int)CraftVariantField.GetValue(intent.Gui) == intent.Variant && (bool)MultiCraftingField.GetValue(intent.Gui) == intent.MultiCrafting)
					{
						if (intent.MultiCrafting)
						{
							return (int)MultiCraftAmountField.GetValue(intent.Gui) == intent.Multiplier;
						}
						return true;
					}
					return false;
				}
			}
			return false;
		}

		private static float GetCraftTimer(InventoryGui gui)
		{
			return (float)CraftTimerField.GetValue(gui);
		}

		private static void ClearReferences()
		{
			_intent = null;
			_plan = null;
			_prepared = null;
			_ownership = null;
		}

		private static void Show(string message)
		{
			MessageHud instance = MessageHud.instance;
			if (instance != null)
			{
				instance.ShowMessage((MessageType)2, message, 0, (Sprite)null, false, true);
			}
		}
	}
	internal static class DistanceDiagnosticTracker
	{
		private sealed class TrackedChest
		{
			internal string Id { get; }

			internal ZDOID ZdoId { get; }

			internal Vector3 Position { get; }

			internal Container OriginalContainer { get; }

			internal ZNetView OriginalView { get; }

			internal ZDO OriginalZdo { get; }

			internal TrackedChest(string id, ZDOID zdoId, Vector3 position, Container originalContainer, ZNetView originalView, ZDO originalZdo)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Id = id;
				ZdoId = zdoId;
				Position = position;
				OriginalContainer = originalContainer;
				OriginalView = originalView;
				OriginalZdo = originalZdo;
			}
		}

		private const int MaximumTrackedChests = 16;

		private const float ObservationIntervalSeconds = 0.5f;

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

		private static readonly BoundedDiagnosticTransitionTracker Transitions = new BoundedDiagnosticTransitionTracker(16);

		private static float _nextObservationTime;

		private static bool _capacityLogged;

		private static bool _failureLogged;

		internal static void TrackRequiredHandles(IEnumerable<ContainerHandle> handles)
		{
			//IL_00e2: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if (handles == null)
			{
				return;
			}
			try
			{
				foreach (ContainerHandle item in handles.Where((ContainerHandle item) => item != null))
				{
					if (Tracked.ContainsKey(item.Id))
					{
						continue;
					}
					if (Tracked.Count >= 16)
					{
						if (!_capacityLogged && (Object)(object)RuntimeContext.Plugin != (Object)null)
						{
							_capacityLogged = true;
							RuntimeContext.Plugin.Log.LogWarning((object)"Distance diagnostic registry reached its 16-container session limit; existing tracked sources remain active.");
						}
						break;
					}
					ZDO originalZdo = (((Object)(object)item.NetworkView != (Object)null && item.NetworkView.IsValid()) ? item.NetworkView.GetZDO() : null);
					Vector3 position = (((Object)(object)item.Container != (Object)null) ? ((Component)item.Container).transform.position : Vector3.zero);
					Tracked.Add(item.Id, new TrackedChest(item.Id, item.ResourceZdoId, position, item.Container, item.NetworkView, originalZdo));
				}
			}
			catch (Exception exception)
			{
				ReportFailureOnce(exception);
			}
		}

		internal static void ObserveCapture(Player player, StorageScope scope, IReadOnlyList<ContainerHandle> includedSources)
		{
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (Tracked.Count == 0 || (Object)(object)player == (Object)null || Time.realtimeSinceStartup < _nextObservationTime)
				{
					return;
				}
				_nextObservationTime = Time.realtimeSinceStartup + 0.5f;
				Dictionary<string, ContainerHandle> dictionary = (includedSources ?? Array.Empty<ContainerHandle>()).Where((ContainerHandle handle) => handle != null).GroupBy<ContainerHandle, string>((ContainerHandle handle) => handle.Id, StringComparer.Ordinal).ToDictionary<IGrouping<string, ContainerHandle>, string, ContainerHandle>((IGrouping<string, ContainerHandle> group) => group.Key, (IGrouping<string, ContainerHandle> group) => group.First(), StringComparer.Ordinal);
				TrackedChest[] array = Tracked.Values.ToArray();
				foreach (TrackedChest trackedChest in array)
				{
					Container val = ResolveSceneContainer(trackedChest);
					ZNetView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null);
					bool flag = (Object)(object)val2 != (Object)null && val2.IsValid();
					ZDO val3 = (flag ? val2.GetZDO() : null);
					ZDO val4 = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(trackedChest.ZdoId) : null);
					ZDO val5 = val4 ?? val3;
					ContainerHandle value;
					bool flag2 = dictionary.TryGetValue(trackedChest.Id, out value);
					int sourceUnits = ((flag2 && value.ResourceInventory != null) ? (from item in value.ResourceInventory.GetAllItems()
						where item != null
						select item).Sum((ItemData item) => item.m_stack) : 0);
					bool scopeContainsKnownPosition = scope?.Contains(trackedChest.Position) ?? false;
					ContainerStreamDiagnosticState containerStreamDiagnosticState = new ContainerStreamDiagnosticState((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null && ((Component)val).gameObject.activeInHierarchy, val == trackedChest.OriginalContainer, (Object)(object)val2 != (Object)null, flag, val2 == trackedChest.OriginalView, val3 != null, val4 != null, val3 != null && val4 != null && val3 == val4, val4 != null && trackedChest.OriginalZdo != null && val4 == trackedChest.OriginalZdo, (val5 != null) ? val5.GetOwner() : 0, (ushort)((val5 != null) ? val5.OwnerRevision : 0), (val5 != null) ? val5.DataRevision : 0u, scopeContainsKnownPosition, flag2, sourceUnits);
					DiagnosticEmissionDecision diagnosticEmissionDecision = Transitions.Observe(trackedChest.Id, containerStreamDiagnosticState.Fingerprint);
					if (diagnosticEmissionDecision != DiagnosticEmissionDecision.SuppressDuplicate && diagnosticEmissionDecision != DiagnosticEmissionDecision.SuppressCapacity)
					{
						Plugin plugin = RuntimeContext.Plugin;
						if (plugin != null)
						{
							plugin.Log.LogWarning((object)("Nearby-resource distance diagnostic transition: containerId=" + trackedChest.Id + " transition=" + diagnosticEmissionDecision.ToString() + " distance=" + Vector3.Distance(((Component)player).transform.position, trackedChest.Position).ToString("0.0", CultureInfo.InvariantCulture) + " scope=" + ScopeSummary(scope) + " scopeContainsKnownPosition=" + containerStreamDiagnosticState.ScopeContainsKnownPosition + " sourceIncluded=" + containerStreamDiagnosticState.SourceIncluded + " sourceUnits=" + containerStreamDiagnosticState.SourceUnits.ToString(CultureInfo.InvariantCulture) + " containerLoaded=" + containerStreamDiagnosticState.ContainerLoaded + " capturedContainerRef=" + containerStreamDiagnosticState.CapturedContainerReferenceMatches + " nviewPresent=" + containerStreamDiagnosticState.NetworkViewPresent + " nviewValid=" + containerStreamDiagnosticState.NetworkViewValid + " capturedNviewRef=" + containerStreamDiagnosticState.CapturedNetworkViewReferenceMatches + " sceneZdo=" + containerStreamDiagnosticState.SceneZdoPresent + " managerZdo=" + containerStreamDiagnosticState.ManagerZdoPresent + " sceneManagerZdoRef=" + containerStreamDiagnosticState.SceneAndManagerZdoReferenceMatch + " capturedZdoRef=" + containerStreamDiagnosticState.CapturedZdoReferenceMatches + " owner=" + containerStreamDiagnosticState.Owner.ToString(CultureInfo.InvariantCulture) + " ownerRevision=" + containerStreamDiagnosticState.OwnerRevision.ToString(CultureInfo.InvariantCulture) + " dataRevision=" + containerStreamDiagnosticState.DataRevision.ToString(CultureInfo.InvariantCulture) + "."));
						}
					}
				}
			}
			catch (Exception exception)
			{
				ReportFailureOnce(exception);
			}
		}

		internal static void ResetSession()
		{
			Tracked.Clear();
			Transitions.Reset();
			_nextObservationTime = 0f;
			_capacityLogged = false;
			_failureLogged = false;
		}

		private static Container ResolveSceneContainer(TrackedChest tracked)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)tracked.OriginalContainer != (Object)null && (Object)(object)((Component)tracked.OriginalContainer).gameObject != (Object)null && ((Component)tracked.OriginalContainer).gameObject.activeInHierarchy)
			{
				return tracked.OriginalContainer;
			}
			Container[] array = Object.FindObjectsByType<Container>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			foreach (Container val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					ZNetView component = ((Component)val).GetComponent<ZNetView>();
					ZDO val2 = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
					if (val2 != null && ((ZDOID)(ref val2.m_uid)).Equals(tracked.ZdoId))
					{
						return val;
					}
				}
			}
			return null;
		}

		private static string ScopeSummary(StorageScope scope)
		{
			if (scope == null || scope.Plan == null)
			{
				return "unavailable";
			}
			IReadOnlyList<WorkbenchZone> connectedZones = scope.Plan.ConnectedZones;
			if (scope.Kind != StorageScopeKind.WorkbenchMesh || connectedZones.Count == 0)
			{
				return scope.Kind.ToString();
			}
			return scope.Kind.ToString() + "(zones=" + connectedZones.Count.ToString(CultureInfo.InvariantCulture) + ",first=" + connectedZones[0].Id + ",last=" + connectedZones[connectedZones.Count - 1].Id + ")";
		}

		private static void ReportFailureOnce(Exception exception)
		{
			if (_failureLogged)
			{
				return;
			}
			_failureLogged = true;
			try
			{
				Plugin plugin = RuntimeContext.Plugin;
				if (plugin != null)
				{
					plugin.Log.LogWarning((object)("Distance diagnostics failed open without changing gameplay: " + exception.GetType().Name + "."));
				}
			}
			catch
			{
			}
		}
	}
	internal static class OwnershipDistanceDiagnosticLog
	{
		internal static void LogActionSelection(Player player, StorageScope scope, IEnumerable<ContainerHandle> handles)
		{
			if (handles == null)
			{
				return;
			}
			RunFailOpen(delegate
			{
				DistanceDiagnosticTracker.TrackRequiredHandles(handles);
				foreach (ContainerHandle item in handles.Where((ContainerHandle item) => item != null))
				{
					LogSnapshot("action-selection", item, player, scope, 0f, OwnershipLeaseManager.DescribeLifecycle(item.Id), null, includeScope: true, null);
				}
			});
		}

		internal static void LogImmediateResult(ContainerHandle handle, string reason)
		{
			if (handle != null)
			{
				RunFailOpen(delegate
				{
					LogResult(handle, Time.realtimeSinceStartup, OwnershipLeaseManager.DescribeLifecycle(handle.Id), reason);
				});
			}
		}

		internal static float CurrentTimeOrZero()
		{
			float current = 0f;
			RunFailOpen(delegate
			{
				current = Time.realtimeSinceStartup;
			});
			return current;
		}

		internal static string DescribeLifecycleOrFallback(ContainerHandle handle, string suffix = "")
		{
			string description = "diagnostic-unavailable" + (suffix ?? string.Empty);
			if (handle == null)
			{
				return description;
			}
			RunFailOpen(delegate
			{
				description = OwnershipLeaseManager.DescribeLifecycle(handle.Id) + (suffix ?? string.Empty);
			});
			return description;
		}

		internal static void LogTransition(ContainerHandle handle, float startedAt, string lifecyclePath, BoundedDiagnosticTransitionTracker transitions, string phase)
		{
			if (handle == null || transitions == null)
			{
				return;
			}
			RunFailOpen(delegate
			{
				OwnershipDiagnosticState ownershipDiagnosticState = Capture(handle);
				DiagnosticEmissionDecision diagnosticEmissionDecision = transitions.Observe(handle.Id, ownershipDiagnosticState.Fingerprint);
				if (diagnosticEmissionDecision != DiagnosticEmissionDecision.SuppressDuplicate && diagnosticEmissionDecision != DiagnosticEmissionDecision.SuppressCapacity)
				{
					LogSnapshot(phase, handle, Player.m_localPlayer, null, Time.realtimeSinceStartup - startedAt, lifecyclePath, ownershipDiagnosticState, includeScope: false, diagnosticEmissionDecision.ToString());
				}
			});
		}

		internal static void LogResult(ContainerHandle handle, float startedAt, string lifecyclePath, string result)
		{
			if (handle != null)
			{
				RunFailOpen(delegate
				{
					LogSnapshot("final", handle, Player.m_localPlayer, null, Time.realtimeSinceStartup - startedAt, lifecyclePath, Capture(handle), includeScope: false, result);
				});
			}
		}

		private static OwnershipDiagnosticState Capture(ContainerHandle handle)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			Container container = handle.Container;
			bool flag = (Object)(object)container != (Object)null && (Object)(object)((Component)container).gameObject != (Object)null && ((Component)container).gameObject.activeInHierarchy;
			ZNetView val = (flag ? ((Component)container).GetComponent<ZNetView>() : null);
			bool flag2 = (Object)(object)val != (Object)null && val.IsValid();
			ZDO val2 = (flag2 ? val.GetZDO() : null);
			ZDO val3 = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(handle.ResourceZdoId) : null);
			ZDO val4 = val3 ?? val2;
			return new OwnershipDiagnosticState((val4 != null) ? val4.GetOwner() : 0, (ushort)((val4 != null) ? val4.OwnerRevision : 0), (val4 != null) ? val4.DataRevision : 0u, (Object)(object)val != (Object)null && val.HasOwner(), (Object)(object)val != (Object)null && val.IsOwner(), flag && container.IsOwner(), flag, flag && container == handle.Container, flag2, val == handle.NetworkView, val3 != null, val2 != null, val4 != null && string.Equals(((object)Unsafe.As<ZDOID, ZDOID>(ref val4.m_uid)/*cast due to .constrained prefix*/).ToString(), handle.Id, StringComparison.Ordinal), val4 != null && handle.CapturedZdo != null && val4 == handle.CapturedZdo, val2 != null && val3 != null && val2 == val3);
		}

		private static void RunFailOpen(Action action)
		{
			if (DiagnosticFailureBoundary.TryRun(action, out Exception failure))
			{
				return;
			}
			try
			{
				Plugin plugin = RuntimeContext.Plugin;
				if (plugin != null)
				{
					plugin.Log.LogWarning((object)("Ownership diagnostics failed open without changing the action: " + failure.GetType().Name + "."));
				}
			}
			catch
			{
			}
		}

		private static void LogSnapshot(string phase, ContainerHandle handle, Player player, StorageScope scope, float elapsed, string lifecyclePath, OwnershipDiagnosticState suppliedState, bool includeScope, string result)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				OwnershipDiagnosticState ownershipDiagnosticState = suppliedState ?? Capture(handle);
				long num = ((ZDOMan.instance != null) ? ZDOMan.GetSessionID() : 0);
				float num2 = (((Object)(object)player != (Object)null && (Object)(object)handle.Container != (Object)null) ? Vector3.Distance(((Component)player).transform.position, ((Component)handle.Container).transform.position) : ((handle.Snapshot != null) ? ((float)handle.Snapshot.Distance) : (-1f)));
				Plugin plugin = RuntimeContext.Plugin;
				if (plugin != null)
				{
					plugin.Log.LogWarning((object)("Nearby-resource ownership diagnostic: phase=" + phase + " lifecycle=" + lifecyclePath + " containerId=" + handle.Id + " elapsedMs=" + (elapsed * 1000f).ToString("0", CultureInfo.InvariantCulture) + " distance=" + num2.ToString("0.0", CultureInfo.InvariantCulture) + " localSession=" + num.ToString(CultureInfo.InvariantCulture) + " capturedOwner=" + handle.ResourceOwner.ToString(CultureInfo.InvariantCulture) + " capturedOwnerRevision=" + handle.ResourceOwnerRevision.ToString(CultureInfo.InvariantCulture) + " owner=" + ownershipDiagnosticState.Owner.ToString(CultureInfo.InvariantCulture) + " ownerRevision=" + ownershipDiagnosticState.OwnerRevision.ToString(CultureInfo.InvariantCulture) + " dataRevision=" + ownershipDiagnosticState.DataRevision.ToString(CultureInfo.InvariantCulture) + " hasOwner=" + ownershipDiagnosticState.HasOwner + " nviewIsOwner=" + ownershipDiagnosticState.NetworkViewIsOwner + " containerIsOwner=" + ownershipDiagnosticState.ContainerIsOwner + " containerLoaded=" + ownershipDiagnosticState.ContainerLoaded + " capturedContainerRef=" + ownershipDiagnosticState.CapturedContainerReferenceMatches + " nviewValid=" + ownershipDiagnosticState.NetworkViewValid + " capturedNviewRef=" + ownershipDiagnosticState.CapturedNetworkViewReferenceMatches + " managerZdo=" + ownershipDiagnosticState.ManagerZdoPresent + " sceneZdo=" + ownershipDiagnosticState.SceneZdoPresent + " zdoIdentity=" + ownershipDiagnosticState.ZdoIdentityMatches + " capturedZdoRef=" + ownershipDiagnosticState.CapturedZdoReferenceMatches + " sceneManagerZdoRef=" + ownershipDiagnosticState.SceneAndManagerZdoReferenceMatch + (includeScope ? (" scope=" + ((scope != null) ? scope.Description : "unavailable")) : string.Empty) + ((!string.IsNullOrEmpty(result)) ? (" result=" + result) : string.Empty) + "."));
				}
			}
			catch (Exception ex)
			{
				try
				{
					Plugin plugin2 = RuntimeContext.Plugin;
					if (plugin2 != null)
					{
						plugin2.Log.LogWarning((object)("Ownership diagnostics failed open without changing the action: " + ex.GetType().Name + "."));
					}
				}
				catch
				{
				}
			}
		}
	}
	internal static class ExpeditionMaterialVisuals
	{
		internal static bool TryAllocate(Player player, ProtectionState protection, out IReadOnlyDictionary<ItemData, int> allocations)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			allocations = new Dictionary<ItemData, int>();
			try
			{
				if ((Object)(object)player == (Object)null || protection == null)
				{
					return false;
				}
				Inventory inventory = ((Humanoid)player).GetInventory();
				InventorySnapshot snapshot = InventorySnapshots.CapturePlayer(player, protection, new CompatibilityCatalog());
				if (!TryAllocateSlots(player, snapshot, out var allocations2))
				{
					return false;
				}
				Dictionary<ItemData, int> dictionary = new Dictionary<ItemData, int>();
				foreach (ReservationSlotAllocation item in allocations2)
				{
					Vector2i val = InventorySnapshots.PositionForSlot(inventory, item.PlayerSlot);
					ItemData itemAt = inventory.GetItemAt(val.x, val.y);
					if (itemAt != null)
					{
						dictionary[itemAt] = item.Quantity;
					}
				}
				allocations = dictionary;
				return true;
			}
			catch (Exception ex)
			{
				Plugin plugin = RuntimeContext.Plugin;
				if (plugin != null)
				{
					plugin.Log.LogWarning((object)("Expedition material highlights were skipped safely: " + ex.GetType().Name));
				}
				allocations = new Dictionary<ItemData, int>();
				return false;
			}
		}

		internal static bool TryAllocateSlots(Player player, InventorySnapshot snapshot, out IReadOnlyList<ReservationSlotAllocation> allocations)
		{
			allocations = Array.Empty<ReservationSlotAllocation>();
			if ((Object)(object)player == (Object)null || snapshot == null || !ExpeditionReservations.TryGetAggregateRequirements(player, out var requirements))
			{
				return false;
			}
			List<ReservationSlotAllocation> list = new List<ReservationSlotAllocation>();
			Dictionary<int, int> dictionary = snapshot.Items.ToDictionary((ItemStackSnapshot item) => item.Slot, (ItemStackSnapshot item) => item.Quantity);
			foreach (ResourceRequirement requirement in requirements.OrderBy<ResourceRequirement, string>((ResourceRequirement item) => item.ItemName, StringComparer.Ordinal).ThenBy((ResourceRequirement item) => item.Quality))
			{
				int num = requirement.Quantity;
				foreach (ItemStackSnapshot item in from item in snapshot.Items
					where !item.IsFixed && string.Equals(item.ResourceItemName, requirement.ItemName, StringComparison.Ordinal) && (requirement.Quality < 0 || item.ResourceQuality == requirement.Quality)
					orderby item.Slot
					select item)
				{
					if (num == 0)
					{
						break;
					}
					int num2 = Math.Min(dictionary[item.Slot], num);
					if (num2 > 0)
					{
						list.Add(new ReservationSlotAllocation(item.Slot, item.CompatibilityKey, item.ResourceItemName, item.ResourceQuality, num2));
						dictionary[item.Slot] -= num2;
						num -= num2;
					}
				}
			}
			allocations = list;
			return true;
		}
	}
	internal static class ExpeditionReservationBuildUi
	{
		private const string RootName = "StackmasterBuildMenuReservations";

		private static readonly FieldInfo TabContainerField = typeof(BuildUi).GetField("m_tabContainer", BindingFlags.Instance | BindingFlags.NonPublic);

		private static ReservationStripView _view;

		private static BuildUi _owner;

		private static Player _player;

		private static RectTransform _menuRect;

		private static RectTransform _hostRect;

		private static string _digest;

		private static bool _refreshRequested = true;

		private static bool _disabled;

		private static bool _failureLogged;

		internal static void Tick()
		{
			if (_disabled)
			{
				return;
			}
			try
			{
				Player localPlayer = Player.m_localPlayer;
				Hud instance = Hud.instance;
				BuildUi val = (((Object)(object)instance != (Object)null) ? instance.m_buildUi : null);
				if ((Object)(object)localPlayer == (Object)null || (Object)(object)val == (Object)null || !ReservationCardInteractions.HasActiveHammer(localPlayer) || !Hud.IsPieceSelectionVisible() || !((Component)val).gameObject.activeInHierarchy)
				{
					Hide();
					return;
				}
				if (_owner != val || _player != localPlayer || _view == null || !_view.IsAlive || (Object)(object)_menuRect == (Object)null || (Object)(object)_hostRect == (Object)null)
				{
					Attach(val, localPlayer);
				}
				if (!_disabled && _view != null && _view.IsAlive)
				{
					_view.Root.transform.SetAsLastSibling();
					RefreshVisible(localPlayer);
					UpdateGeometry(_menuRect, _hostRect);
				}
			}
			catch (Exception exception)
			{
				Disable("The optional build-menu reservation row stopped safely", exception);
			}
		}

		internal static void RequestRefresh()
		{
			_refreshRequested = true;
			RefreshVisible(Player.m_localPlayer);
		}

		internal static void RefreshVisible(Player player)
		{
			if (_view != null && !_view.IsAlive)
			{
				Destroy();
			}
			else
			{
				if (_disabled || _view == null || (Object)(object)_owner == (Object)null || (Object)(object)player == (Object)null || player != Player.m_localPlayer || player != _player || (((Object)(object)Hud.instance != (Object)null) ? Hud.instance.m_buildUi : null) != _owner)
				{
					return;
				}
				if (!((Component)_owner).gameObject.activeInHierarchy || !Hud.IsPieceSelectionVisible() || !ReservationCardInteractions.HasActiveHammer(player))
				{
					Hide();
					return;
				}
				if (!ExpeditionReservations.TryGetRecords(player, out var records) || records.Count == 0)
				{
					_digest = string.Empty;
					if (!_view.SetVisible(visible: false))
					{
						Destroy();
					}
					return;
				}
				string text = Digest(records);
				if (_refreshRequested || !string.Equals(text, _digest, StringComparison.Ordinal))
				{
					_view.Render(records, SelectPiece, ReleaseOne);
					_digest = text;
					_refreshRequested = false;
				}
				if (!_view.SetVisible(visible: true))
				{
					Destroy();
				}
			}
		}

		internal static void RearmSession()
		{
			Destroy();
			_disabled = false;
			_failureLogged = false;
			_refreshRequested = true;
		}

		internal static void Destroy()
		{
			ReservationStripView view = _view;
			_view = null;
			_owner = null;
			_player = null;
			_menuRect = null;
			_hostRect = null;
			_digest = null;
			_refreshRequested = true;
			view?.Destroy();
		}

		private static void Attach(BuildUi buildUi, Player player)
		{
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: 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)
			Destroy();
			CompatibilityResult compatibilityResult = CompatibilityGate.EvaluateBuildMenuReservationUi();
			if (!compatibilityResult.IsCompatible)
			{
				Disable("The optional build-menu reservation row is unavailable: " + compatibilityResult.Reason);
				return;
			}
			object? obj = TabContainerField?.GetValue(buildUi);
			RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				throw new InvalidOperationException("BuildUi tab container is unavailable.");
			}
			Transform parent = ((Component)buildUi).transform.parent;
			RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if ((Object)(object)val2 == (Object)null)
			{
				throw new InvalidOperationException("BuildUi parent UI root is unavailable.");
			}
			Transform val3 = ((Transform)val2).Find("StackmasterBuildMenuReservations");
			if ((Object)(object)val3 != (Object)null)
			{
				((Component)val3).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)val3).gameObject);
			}
			Transform val4 = ((Component)buildUi).transform.Find("StackmasterBuildMenuReservations");
			if ((Object)(object)val4 != (Object)null)
			{
				((Component)val4).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)val4).gameObject);
			}
			TMP_Text textTemplate = ((IEnumerable<TMP_Text>)((Component)buildUi).GetComponentsInChildren<TMP_Text>(true)).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text candidate) => (Object)(object)candidate != (Object)null && (Object)(object)candidate.font != (Object)null));
			_view = new ReservationStripView((Transform)(object)val2, "StackmasterBuildMenuReservations", textTemplate);
			_owner = buildUi;
			_player = player;
			_menuRect = val;
			_hostRect = val2;
			RectTransform rootRect = _view.RootRect;
			Vector2 anchorMin = (_view.RootRect.anchorMax = val2.pivot);
			rootRect.anchorMin = anchorMin;
			_view.RootRect.pivot = Vector2.zero;
			RectTransform rootRect2 = _view.RootRect;
			Rect rect = val.rect;
			rootRect2.sizeDelta = new Vector2(((Rect)(ref rect)).width, 54f);
			_view.Root.transform.SetAsLastSibling();
			_refreshRequested = true;
		}

		private static void UpdateGeometry(RectTransform menuRect, RectTransform hostRect)
		{
			//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)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			if (_view == null || !_view.IsAlive || (Object)(object)menuRect == (Object)null || (Object)(object)hostRect == (Object)null)
			{
				if (_view != null && !_view.IsAlive)
				{
					Destroy();
				}
				return;
			}
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			menuRect.GetWorldCorners(array);
			float num = float.PositiveInfinity;
			float num2 = float.NegativeInfinity;
			float num3 = float.NegativeInfinity;
			Vector3[] array2 = array;
			foreach (Vector3 val in array2)
			{
				Vector3 val2 = ((Transform)hostRect).InverseTransformPoint(val);
				num = Mathf.Min(num, val2.x);
				num2 = Mathf.Max(num2, val2.x);
				num3 = Mathf.Max(num3, val2.y);
			}
			Vector3[] array3 = (Vector3[])(object)new Vector3[4];
			hostRect.GetWorldCorners(array3);
			float num4 = Mathf.Abs(((Transform)hostRect).lossyScale.x);
			float num5 = Mathf.Abs(((Transform)hostRect).lossyScale.y);
			if (num4 <= 0.0001f || num5 <= 0.0001f)
			{
				throw new InvalidOperationException("The build-menu canvas root had an invalid UI scale.");
			}
			Rect safeArea = Screen.safeArea;
			Rect rect = hostRect.rect;
			float safeLeft = ((Rect)(ref rect)).xMin + (((Rect)(ref safeArea)).xMin - array3[0].x) / num4;
			float safeRight = ((Rect)(ref rect)).xMin + (((Rect)(ref safeArea)).xMax - array3[0].x) / num4;
			float safeTop = ((Rect)(ref rect)).yMin + (((Rect)(ref safeArea)).yMax - array3[0].y) / num5;
			BuildMenuReservationLayout buildMenuReservationLayout = BuildMenuReservationLayoutPlanner.Plan(num, num2, num3, safeLeft, safeRight, safeTop);
			if (!buildMenuReservationLayout.Visible)
			{
				if (!_view.SetVisible(visible: false))
				{
					Destroy();
				}
			}
			else
			{
				_view.RootRect.anchoredPosition = new Vector2(buildMenuReservationLayout.Left, buildMenuReservationLayout.Bottom);
				_view.RootRect.sizeDelta = new Vector2(buildMenuReservationLayout.Width, buildMenuReservationLayout.Height);
				ReservationStripLayout reservationStripLayout = ReservationStripLayoutPlanner.Plan(buildMenuReservationLayout.Width, 1f, _view.PreferredLabelWidth);
				_view.ApplyInnerGeometry(buildMenuReservationLayout.Width, reservationStripLayout.LabelWidth, reservationStripLayout.ViewportLeft, reservationStripLayout.ViewportRight);
			}
		}

		private static void SelectPiece(string pieceKey)
		{
			if (ReservationCardInteractions.SelectFromBuildMenu(pieceKey, _owner))
			{
				Hide();
			}
		}

		private static void ReleaseOne(string pieceKey, string visibleName)
		{
			try
			{
				ReservationCardInteractions.ReleaseOne(pieceKey, visibleName);
			}
			catch (Exception exception)
			{
				Disable("A build-menu reservation card could not be used safely", exception);
			}
		}

		private static void Hide()
		{
			if (_view != null && !_view.SetVisible(visible: false))
			{
				Destroy();
				return;
			}
			_digest = null;
			_refreshRequested = true;
		}

		private static string Digest(IEnumerable<ExpeditionReservationRecord> records)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (ExpeditionReservationRecord item in records.OrderBy<ExpeditionReservationRecord, string>((ExpeditionReservationRecord value) => value.PieceKey, StringComparer.Ordinal))
			{
				stringBuilder.Append(item.PieceKey).Append('\u001f').Append(item.DisplayName)
					.Append('\u001f')
					.Append(item.Count)
					.Append('\u001e');
			}
			return stringBuilder.ToString();
		}

		private static void Disable(string message, Exception exception = null)
		{
			Destroy();
			_disabled = true;
			if (!_failureLogged && !((Object)(object)RuntimeContext.Plugin == (Object)null))
			{
				_failureLogged = true;
				RuntimeContext.Plugin.Log.LogWarning((object)((exception == null) ? message : (message + ": " + exception)));
			}
		}
	}
	internal enum SuccessfulBuildReservationResult
	{
		NotApplicable,
		NotReserved,
		Consumed,
		PersistenceFailed
	}
	internal static class ExpeditionReservations
	{
		private const string CloneSuffix = "(Clone)";

		private const string PiecePrefix = "prefab:";

		private static ExpeditionReservationState _state = new ExpeditionReservationState();

		private static string _loadedKey;

		private static bool _storageHealthy = true;

		private static bool _writesHealthy = true;

		private static bool _failureLogged;

		private static bool _buildConsumeWarningShown;

		internal static void Initialize()
		{
			_state = new ExpeditionReservationState();
			_loadedKey = null;
			_storageHealthy = true;
			_writesHealthy = true;
			_failureLogged = false;
			_buildConsumeWarningShown = false;
		}

		internal static void Shutdown()
		{
			_state = new ExpeditionReservationState();
			_loadedKey = null;
			_storageHealthy = false;
			_writesHealthy = false;
		}

		internal static bool CanCommitQuickGrab(Player player)
		{
			try
			{
				return _storageHealthy && _writesHealthy && (Object)(object)player != (Object)null && EnsureLoaded(player);
			}
			catch (Exception ex)
			{
				DisableStorage("Expedition reservations could not be prepared and were disabled for this session: " + ex.GetType().Name);
				return false;
			}
		}

		internal static bool CanRecordQuickGrab(Player player, string pieceKey, string displayName, IReadOnlyList<ResourceRequirement> requirements, out string failure)
		{
			failure = null;
			try
			{
				if (!CanCommitQuickGrab(player) || string.IsNullOrEmpty(pieceKey) || string.IsNullOrEmpty(displayName) || requirements == null)
				{
					failure = "reservations are unavailable";
					return false;
				}
				if (ExpeditionReservationPersistence.TryAddDurably(_state, pieceKey, displayName, requirements, (string payload) => true, out ExpeditionReservationState _, out ExpeditionReservationPersistenceResult result))
				{
					return true;
				}
				failure = FailureFor(result);
				return false;
			}
			catch (InvalidOperationException)
			{
				failure = "the safe reservation storage limit was reached";
				return false;
			}
			catch (Exception ex2)
			{
				DisableStorage("Expedition reservations could not be validated and were disabled for this session: " + ex2.GetType().Name);
				failure = "reservations are unavailable";
				return false;
			}
		}

		internal static bool TryAddQuickGrabReservation(Player player, Piece piece, string pieceKey, string displayName, IReadOnlyList<ResourceRequirement> requirements, out bool reservationCreated, out int committedCount, out string failure)
		{
			reservationCreated = false;
			committedCount = 0;
			failure = null;
			try
			{
				if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null || string.IsNullOrEmpty(pieceKey) || string.IsNullOrEmpty(displayName) || requirements == null)
				{
					failure = "the material request could not be identified safely";
					return false;
				}
				if (IsMaterialOnlyQuickGrabPiece(piece, pieceKey, displayName))
				{
					return true;
				}
				if (!_storageHealthy || !_writesHealthy || !EnsureLoaded(player))
				{
					failure = "reservations are unavailable";
					return false;
				}
				string previousPayload = _state.Serialize();
				Exception persistenceFailure = null;
				if (!ExpeditionReservationPersistence.TryAddDurably(_state, pieceKey, displayName, requirements, delegate(string payload)
				{
					try
					{
						return AtomicReservationFileStore.TryWrite(_loadedKey, previousPayload, payload);
					}
					catch (Exception ex4)
					{
						persistenceFailure = ex4;
						_writesHealthy = false;
						return false;
					}
				}, out ExpeditionReservationState committed, out ExpeditionReservationPersistenceResult result))
				{
					failure = FailureFor(result);
					if (persistenceFailure != null)
					{
						LogFailureOnce("Quick Grab reservation could not be saved and was left unchanged: " + persistenceFailure.GetType().Name);
					}
					return false;
				}
				_state = committed;
				reservationCreated = true;
				committedCount = (from record in committed.Records
					where string.Equals(record.PieceKey, pieceKey, StringComparison.Ordinal)
					select record.Count).Single();
				try
				{
					InventoryIntegration.RequestExpeditionRefresh();
				}
				catch (Exception ex)
				{
					Plugin plugin = RuntimeContext.Plugin;
					if (plugin != null)
					{
						plugin.Log.LogWarning((object)("Quick Grab reservation UI refresh failed after save: " + ex.GetType().Name));
					}
				}
				return true;
			}
			catch (InvalidOperationException)
			{
				failure = "the safe reservation storage limit was reached";
				return false;