Decompiled source of RunicInventory v1.0.0

RunicInventory.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Runic.Foundation.Core;
using RunicInventory.Api;
using RunicInventory.Core;
using RunicInventory.Integration;
using UnityEngine;
using UnityEngine.EventSystems;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Runic Inventory")]
[assembly: AssemblyDescription("Labeled native-row equipment and quick slots with automatic empty-role equip, lossless armor swaps, locks, sort, and pickup controls for Valheim.")]
[assembly: AssemblyCompany("Chazman")]
[assembly: AssemblyProduct("Runic Inventory")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: InternalsVisibleTo("RunicInventory.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Runic.Foundation.Core
{
	public static class RunicIdentifier
	{
		public static bool IsValid(string value)
		{
			if (string.IsNullOrEmpty(value) || value.Length > 128)
			{
				return false;
			}
			bool flag = false;
			bool flag2 = false;
			foreach (char c in value)
			{
				if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
				{
					flag = true;
					flag2 = false;
					continue;
				}
				switch (c)
				{
				case '-':
					if (!flag || flag2)
					{
						return false;
					}
					flag2 = true;
					break;
				case '.':
					if (!flag || flag2)
					{
						return false;
					}
					flag = false;
					flag2 = false;
					break;
				default:
					return false;
				}
			}
			if (flag)
			{
				return !flag2;
			}
			return false;
		}

		public static string Require(string value, string parameterName)
		{
			if (!IsValid(value))
			{
				throw new ArgumentException("Runic identifiers must be lowercase dot-separated tokens containing only ASCII letters, digits, and internal hyphens.", parameterName);
			}
			return value;
		}
	}
	public sealed class InputChord : IEquatable<InputChord>
	{
		private readonly IReadOnlyList<string> _modifiers;

		public string DeviceId { get; }

		public string PrimaryControl { get; }

		public IReadOnlyList<string> Modifiers => _modifiers;

		public string CanonicalId { get; }

		public InputChord(string deviceId, string primaryControl, IEnumerable<string> modifiers = null)
		{
			DeviceId = RunicIdentifier.Require(deviceId, "deviceId");
			PrimaryControl = RequireControl(primaryControl, "primaryControl");
			string text = CanonicalizeControl(PrimaryControl);
			SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>(StringComparer.Ordinal);
			if (modifiers != null)
			{
				foreach (string modifier in modifiers)
				{
					string text2 = RequireControl(modifier, "modifiers");
					string text3 = CanonicalizeControl(text2);
					if (string.Equals(text3, text, StringComparison.Ordinal))
					{
						throw new ArgumentException("The primary control cannot also be a modifier.", "modifiers");
					}
					if (sortedDictionary.ContainsKey(text3))
					{
						throw new ArgumentException("Duplicate input modifier: " + text2, "modifiers");
					}
					sortedDictionary.Add(text3, text2);
				}
			}
			string[] array = new string[sortedDictionary.Count];
			int num = 0;
			foreach (string value in sortedDictionary.Values)
			{
				array[num++] = value;
			}
			_modifiers = Array.AsReadOnly(array);
			StringBuilder stringBuilder = new StringBuilder(DeviceId).Append(':');
			foreach (string key in sortedDictionary.Keys)
			{
				stringBuilder.Append(key).Append('+');
			}
			stringBuilder.Append(text);
			CanonicalId = stringBuilder.ToString();
		}

		public bool Equals(InputChord other)
		{
			if (other != null)
			{
				return string.Equals(CanonicalId, other.CanonicalId, StringComparison.Ordinal);
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			return Equals(obj as InputChord);
		}

		public override int GetHashCode()
		{
			return StringComparer.Ordinal.GetHashCode(CanonicalId);
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < _modifiers.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(" + ");
				}
				stringBuilder.Append(_modifiers[i]);
			}
			if (_modifiers.Count > 0)
			{
				stringBuilder.Append(" + ");
			}
			return stringBuilder.Append(PrimaryControl).Append(" [").Append(DeviceId)
				.Append(']')
				.ToString();
		}

		private static string RequireControl(string value, string parameterName)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				throw new ArgumentException("An input control name is required.", parameterName);
			}
			string text = value.Trim();
			if (text.Length > 64)
			{
				throw new ArgumentException("Input control names cannot exceed 64 characters.", parameterName);
			}
			string text2 = text;
			foreach (char c in text2)
			{
				if (char.IsControl(c) || c == ':' || c == '+' || c == '|')
				{
					throw new ArgumentException("The input control name contains a reserved character.", parameterName);
				}
			}
			if (CanonicalizeControl(text).Length == 0)
			{
				throw new ArgumentException("The input control name has no canonical characters.", parameterName);
			}
			return text;
		}

		private static string CanonicalizeControl(string value)
		{
			StringBuilder stringBuilder = new StringBuilder(value.Length);
			foreach (char c in value)
			{
				if (!char.IsWhiteSpace(c) && c != '_' && c != '-')
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}
	}
	public sealed class KeybindingDescriptor
	{
		public string ModuleId { get; }

		public string BindingId { get; }

		public string QualifiedId => ModuleId + "/" + BindingId;

		public string DisplayName { get; }

		public InputChord Chord { get; }

		public string Context { get; }

		public KeybindingDescriptor(string moduleId, string bindingId, string displayName, InputChord chord, string context = "gameplay")
		{
			ModuleId = RunicIdentifier.Require(moduleId, "moduleId");
			BindingId = RunicIdentifier.Require(bindingId, "bindingId");
			Context = RunicIdentifier.Require(context, "context");
			if (string.IsNullOrWhiteSpace(displayName))
			{
				throw new ArgumentException("A keybinding display name is required.", "displayName");
			}
			Chord = chord ?? throw new ArgumentNullException("chord");
			DisplayName = displayName.Trim();
		}
	}
	public sealed class KeybindingConflict
	{
		public InputChord Chord { get; }

		public IReadOnlyList<KeybindingDescriptor> Bindings { get; }

		internal KeybindingConflict(InputChord chord, IReadOnlyList<KeybindingDescriptor> bindings)
		{
			Chord = chord;
			Bindings = bindings;
		}
	}
	public enum KeybindingChangeKind
	{
		Registered,
		Unregistered
	}
	public sealed class KeybindingsChangedEventArgs : EventArgs
	{
		public KeybindingChangeKind Kind { get; }

		public KeybindingDescriptor Binding { get; }

		public KeybindingConflict Conflict { get; }

		internal KeybindingsChangedEventArgs(KeybindingChangeKind kind, KeybindingDescriptor binding, KeybindingConflict conflict)
		{
			Kind = kind;
			Binding = binding;
			Conflict = conflict;
		}
	}
	public sealed class KeybindingConflictRegistry
	{
		private sealed class BindingEntry
		{
			internal KeybindingDescriptor Binding { get; }

			internal long Token { get; }

			internal BindingEntry(KeybindingDescriptor binding, long token)
			{
				Binding = binding;
				Token = token;
			}
		}

		private readonly object _sync = new object();

		private readonly Dictionary<string, BindingEntry> _byQualifiedId = new Dictionary<string, BindingEntry>(StringComparer.Ordinal);

		private readonly Dictionary<string, List<BindingEntry>> _byChord = new Dictionary<string, List<BindingEntry>>(StringComparer.Ordinal);

		private long _nextToken;

		public event EventHandler<KeybindingsChangedEventArgs> Changed;

		public KeybindingRegistration Register(KeybindingDescriptor binding)
		{
			if (binding == null)
			{
				throw new ArgumentNullException("binding");
			}
			long token;
			KeybindingConflict conflict;
			lock (_sync)
			{
				if (_byQualifiedId.ContainsKey(binding.QualifiedId))
				{
					throw new InvalidOperationException("A keybinding is already registered as '" + binding.QualifiedId + "'.");
				}
				if (_nextToken == long.MaxValue)
				{
					throw new InvalidOperationException("The keybinding registration token space is exhausted.");
				}
				token = ++_nextToken;
				BindingEntry bindingEntry = new BindingEntry(binding, token);
				_byQualifiedId.Add(binding.QualifiedId, bindingEntry);
				if (!_byChord.TryGetValue(binding.Chord.CanonicalId, out var value))
				{
					value = new List<BindingEntry>();
					_byChord.Add(binding.Chord.CanonicalId, value);
				}
				value.Add(bindingEntry);
				conflict = CreateConflictLocked(binding.Chord.CanonicalId);
			}
			RaiseChanged(new KeybindingsChangedEventArgs(KeybindingChangeKind.Registered, binding, conflict));
			return new KeybindingRegistration(this, binding, token);
		}

		public bool Unregister(string moduleId, string bindingId)
		{
			RunicIdentifier.Require(moduleId, "moduleId");
			RunicIdentifier.Require(bindingId, "bindingId");
			return Unregister(moduleId + "/" + bindingId, (long?)null);
		}

		public bool TryGetBinding(string moduleId, string bindingId, out KeybindingDescriptor binding)
		{
			binding = null;
			if (!RunicIdentifier.IsValid(moduleId) || !RunicIdentifier.IsValid(bindingId))
			{
				return false;
			}
			lock (_sync)
			{
				if (!_byQualifiedId.TryGetValue(moduleId + "/" + bindingId, out var value))
				{
					return false;
				}
				binding = value.Binding;
				return true;
			}
		}

		public IReadOnlyList<KeybindingDescriptor> GetBindings()
		{
			lock (_sync)
			{
				List<KeybindingDescriptor> list = new List<KeybindingDescriptor>(_byQualifiedId.Count);
				foreach (BindingEntry value in _byQualifiedId.Values)
				{
					list.Add(value.Binding);
				}
				list.Sort((KeybindingDescriptor left, KeybindingDescriptor right) => StringComparer.Ordinal.Compare(left.QualifiedId, right.QualifiedId));
				return list.AsReadOnly();
			}
		}

		public IReadOnlyList<KeybindingConflict> GetConflicts()
		{
			lock (_sync)
			{
				List<KeybindingConflict> list = new List<KeybindingConflict>();
				foreach (string key in _byChord.Keys)
				{
					KeybindingConflict keybindingConflict = CreateConflictLocked(key);
					if (keybindingConflict != null)
					{
						list.Add(keybindingConflict);
					}
				}
				list.Sort((KeybindingConflict left, KeybindingConflict right) => StringComparer.Ordinal.Compare(left.Chord.CanonicalId, right.Chord.CanonicalId));
				return list.AsReadOnly();
			}
		}

		public IReadOnlyList<KeybindingConflict> GetConflictsFor(string moduleId)
		{
			RunicIdentifier.Require(moduleId, "moduleId");
			IReadOnlyList<KeybindingConflict> conflicts = GetConflicts();
			List<KeybindingConflict> list = new List<KeybindingConflict>();
			foreach (KeybindingConflict item in conflicts)
			{
				foreach (KeybindingDescriptor binding in item.Bindings)
				{
					if (string.Equals(binding.ModuleId, moduleId, StringComparison.Ordinal))
					{
						list.Add(item);
						break;
					}
				}
			}
			return list.AsReadOnly();
		}

		internal bool IsActive(string qualifiedId, long token)
		{
			lock (_sync)
			{
				BindingEntry value;
				return _byQualifiedId.TryGetValue(qualifiedId, out value) && value.Token == token;
			}
		}

		internal bool Unregister(string qualifiedId, long? requiredToken)
		{
			KeybindingDescriptor binding;
			KeybindingConflict conflict;
			lock (_sync)
			{
				if (!_byQualifiedId.TryGetValue(qualifiedId, out var entry) || (requiredToken.HasValue && entry.Token != requiredToken.Value))
				{
					return false;
				}
				binding = entry.Binding;
				_byQualifiedId.Remove(qualifiedId);
				List<BindingEntry> list = _byChord[binding.Chord.CanonicalId];
				list.RemoveAll((BindingEntry candidate) => candidate.Token == entry.Token);
				if (list.Count == 0)
				{
					_byChord.Remove(binding.Chord.CanonicalId);
				}
				conflict = CreateConflictLocked(binding.Chord.CanonicalId);
			}
			RaiseChanged(new KeybindingsChangedEventArgs(KeybindingChangeKind.Unregistered, binding, conflict));
			return true;
		}

		private KeybindingConflict CreateConflictLocked(string chordId)
		{
			if (!_byChord.TryGetValue(chordId, out var value) || value.Count < 2)
			{
				return null;
			}
			List<KeybindingDescriptor> list = new List<KeybindingDescriptor>(value.Count);
			foreach (BindingEntry item in value)
			{
				list.Add(item.Binding);
			}
			list.Sort((KeybindingDescriptor left, KeybindingDescriptor right) => StringComparer.Ordinal.Compare(left.QualifiedId, right.QualifiedId));
			return new KeybindingConflict(list[0].Chord, list.AsReadOnly());
		}

		private void RaiseChanged(KeybindingsChangedEventArgs arguments)
		{
			EventHandler<KeybindingsChangedEventArgs> eventHandler = this.Changed;
			if (eventHandler == null)
			{
				return;
			}
			Delegate[] invocationList = eventHandler.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				EventHandler<KeybindingsChangedEventArgs> eventHandler2 = (EventHandler<KeybindingsChangedEventArgs>)invocationList[i];
				try
				{
					eventHandler2(this, arguments);
				}
				catch (Exception)
				{
				}
			}
		}
	}
	public sealed class KeybindingRegistration : IDisposable
	{
		private readonly KeybindingConflictRegistry _registry;

		private readonly long _token;

		public KeybindingDescriptor Binding { get; }

		public bool IsActive => _registry.IsActive(Binding.QualifiedId, _token);

		internal KeybindingRegistration(KeybindingConflictRegistry registry, KeybindingDescriptor binding, long token)
		{
			_registry = registry;
			Binding = binding;
			_token = token;
		}

		public void Dispose()
		{
			_registry.Unregister(Binding.QualifiedId, _token);
		}
	}
}
namespace RunicInventory
{
	internal static class Diagnostics
	{
		private static ManualLogSource _log;

		internal static void Initialize(ManualLogSource log)
		{
			_log = log;
		}

		internal static void Info(string value)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)Bound(value));
			}
		}

		internal static void Warn(string value)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogWarning((object)Bound(value));
			}
		}

		internal static void Error(Exception exception, string context)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogError((object)(Bound(context) + " " + ((exception == null) ? "unknown" : (exception.GetType().Name + ": " + Bound(exception.Message)))));
			}
		}

		internal static void Trace(string value)
		{
			ConfigEntry<bool> verboseDiagnostics = InventoryConfig.VerboseDiagnostics;
			if (verboseDiagnostics != null && verboseDiagnostics.Value)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)Bound(value));
				}
			}
		}

		private static string Bound(string value)
		{
			string text = value ?? string.Empty;
			if (text.Length > 512)
			{
				return text.Substring(0, 512);
			}
			return text;
		}
	}
	internal static class InventoryConfig
	{
		internal static ConfigEntry<bool> Enabled { get; private set; }

		internal static ConfigEntry<bool> ShowInventoryStatus { get; private set; }

		internal static ConfigEntry<bool> ShowRoleLabels { get; private set; }

		internal static ConfigEntry<bool> ShowPickupPreview { get; private set; }

		internal static ConfigEntry<string> FilteredPickupItems { get; private set; }

		internal static ConfigEntry<string> SortRows { get; private set; }

		internal static ConfigEntry<KeyboardShortcut> Quick1 { get; private set; }

		internal static ConfigEntry<KeyboardShortcut> Quick2 { get; private set; }

		internal static ConfigEntry<KeyboardShortcut> Quick3 { get; private set; }

		internal static ConfigEntry<KeyboardShortcut> Sort { get; private set; }

		internal static ConfigEntry<KeyboardShortcut> ToggleLock { get; private set; }

		internal static ConfigEntry<bool> ControllerEnabled { get; private set; }

		internal static ConfigEntry<string> ControllerModifier { get; private set; }

		internal static ConfigEntry<string> ControllerQuick1 { get; private set; }

		internal static ConfigEntry<string> ControllerQuick2 { get; private set; }

		internal static ConfigEntry<string> ControllerQuick3 { get; private set; }

		internal static ConfigEntry<string> ControllerSort { get; private set; }

		internal static ConfigEntry<string> ControllerToggleLock { get; private set; }

		internal static ConfigEntry<bool> VerboseDiagnostics { get; private set; }

		internal static void Bind(ConfigFile config)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the validated native-row topology. Disabling never removes or serializes an item.");
			ShowInventoryStatus = config.Bind<bool>("UI", "ShowInventoryStatus", false, "Show the bounded topology/authority panel while the player inventory is open.");
			ShowRoleLabels = config.Bind<bool>("UI", "ShowRoleLabels", true, "Label and subtly outline the eight native bottom-row equipment and quick slots while inventory is open.");
			ShowPickupPreview = config.Bind<bool>("UI", "ShowPickupPreview", true, "Append a bounded local capacity/weight preview to nearby world-item hover text.");
			FilteredPickupItems = config.Bind<string>("Pickup Filter", "Items", string.Empty, "Exact comma/semicolon/newline-separated prefab IDs or shared-name tokens to refuse before pickup mutation; maximum 128 safe entries. Quest items always bypass the filter.");
			SortRows = config.Bind<string>("Sort", "Rows", "1,2", "Zero-based general rows eligible for regional sort. Row 0 and the bottom special row are always rejected. Empty means every proven general row.");
			Quick1 = config.Bind<KeyboardShortcut>("Keyboard", "UseQuickSlot1", new KeyboardShortcut((KeyCode)49, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Manually use quick slot 1 for the owning local player, including a dedicated-server client.");
			Quick2 = config.Bind<KeyboardShortcut>("Keyboard", "UseQuickSlot2", new KeyboardShortcut((KeyCode)50, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Manually use quick slot 2 for the owning local player, including a dedicated-server client.");
			Quick3 = config.Bind<KeyboardShortcut>("Keyboard", "UseQuickSlot3", new KeyboardShortcut((KeyCode)51, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Manually use quick slot 3 for the owning local player, including a dedicated-server client.");
			Sort = config.Bind<KeyboardShortcut>("Keyboard", "SortSelectedRows", new KeyboardShortcut((KeyCode)105, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Sort only configured safe general rows while the inventory is open.");
			ToggleLock = config.Bind<KeyboardShortcut>("Keyboard", "ToggleFocusedSlotLock", new KeyboardShortcut((KeyCode)108, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Optional keyboard fallback for slot locking. The primary gesture is Left Alt + right-click on a player slot.");
			ControllerEnabled = config.Bind<bool>("Controller", "Enabled", true, "Enable raw, effective-path-validated controller chords.");
			ControllerModifier = config.Bind<string>("Controller", "ModifierAction", "JoyAltKeys", "Existing Valheim Joy* action held as the modifier.");
			ControllerQuick1 = config.Bind<string>("Controller", "UseQuickSlot1Action", "JoyMap", "Existing gamepad action pressed with ModifierAction to use quick slot 1. The exact untouched legacy 1.0.0 controller set is read as JoyMap without rewriting the file.");
			ControllerQuick2 = config.Bind<string>("Controller", "UseQuickSlot2Action", "JoyButtonY", "Existing gamepad action pressed with ModifierAction to use quick slot 2.");
			ControllerQuick3 = config.Bind<string>("Controller", "UseQuickSlot3Action", "JoyRBumper", "Existing gamepad action pressed with ModifierAction to use quick slot 3.");
			ControllerSort = config.Bind<string>("Controller", "SortSelectedRowsAction", "JoyButtonA", "Existing gamepad action pressed with ModifierAction to sort while inventory is open.");
			ControllerToggleLock = config.Bind<string>("Controller", "ToggleFocusedSlotLockAction", "JoyButtonB", "Existing gamepad action pressed with ModifierAction to toggle the focused slot lock.");
			VerboseDiagnostics = config.Bind<bool>("Diagnostics", "Verbose", false, "Log bounded reason codes and control routes; never log inventory contents or player metadata.");
		}
	}
	[BepInPlugin("chazman.RunicInventory", "Runic Inventory", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "chazman.RunicInventory";

		public const string Name = "Runic Inventory";

		public const string Version = "1.0.0";

		public const string ModuleId = "runic.inventory";

		public const string ProtocolVersion = "1.0";

		private readonly List<KeybindingRegistration> _bindings = new List<KeybindingRegistration>();

		private readonly KeybindingConflictRegistry _keybindings = new KeybindingConflictRegistry();

		private Harmony _harmony;

		private InventoryRuntime _runtime;

		private bool _configurationSubscribed;

		private bool _inputLayoutSubscribed;

		private bool _shuttingDown;

		internal static Plugin Instance { get; private set; }

		internal static bool RuntimeReady { get; private set; }

		internal InventoryRuntime Runtime => _runtime;

		private void Awake()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			Instance = this;
			Diagnostics.Initialize(((BaseUnityPlugin)this).Logger);
			try
			{
				InventoryConfig.Bind(((BaseUnityPlugin)this).Config);
				((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged;
				_configurationSubscribed = true;
				ZInput.OnInputLayoutChanged += OnInputLayoutChanged;
				_inputLayoutSubscribed = true;
				if (!ValheimContracts.Initialize(out var problem))
				{
					throw new MissingMethodException(problem);
				}
				_runtime = new InventoryRuntime(batch: false);
				_harmony = new Harmony("chazman.RunicInventory");
				_harmony.PatchAll(typeof(Plugin).Assembly);
				RegisterBindings();
				_runtime.Initialize();
				InventoryIntegrationApi.Attach(_runtime);
				RuntimeReady = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Runic Inventory v1.0.0 ready. Native owner-local topology, locks, sort, quick use, equipment relocation, saves, and tombstones remain Valheim-owned.");
				if (Application.isBatchMode)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Batch transport detected: only an exact owning local Player can activate Inventory; a true dedicated server remains inert.");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Runic Inventory startup failed: " + ex));
				ShutdownRuntime();
			}
		}

		private void Update()
		{
			if (!RuntimeReady || _runtime == null)
			{
				return;
			}
			try
			{
				_runtime.Tick();
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Inventory runtime faulted and was disabled.");
				_runtime.FailClosed("runtime.exception");
			}
		}

		private void OnGUI()
		{
			if (!RuntimeReady || _runtime == null)
			{
				return;
			}
			try
			{
				_runtime.Draw();
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Inventory status drawing failed closed.");
			}
		}

		private void OnSettingChanged(object sender, SettingChangedEventArgs arguments)
		{
			if (!RuntimeReady || _runtime == null)
			{
				return;
			}
			try
			{
				_runtime.OnConfigurationChanged();
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Inventory configuration refresh failed closed.");
				_runtime.FailClosed("config.refresh-failed");
			}
			try
			{
				RefreshBindings();
			}
			catch (Exception exception2)
			{
				Diagnostics.Error(exception2, "Inventory keybinding refresh failed.");
			}
		}

		private void OnInputLayoutChanged()
		{
			ControllerChordSession.Reset();
			Diagnostics.Trace("Controller input layout changed; Inventory bindings will be re-resolved.");
		}

		private void OnDestroy()
		{
			ShutdownRuntime();
			Diagnostics.Initialize(null);
			Instance = null;
		}

		private void RegisterBindings()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<bool> enabled = InventoryConfig.Enabled;
			if (enabled != null && enabled.Value)
			{
				RegisterKeyboard("quick-1", "Use quick slot 1", InventoryConfig.Quick1.Value, "gameplay");
				RegisterKeyboard("quick-2", "Use quick slot 2", InventoryConfig.Quick2.Value, "gameplay");
				RegisterKeyboard("quick-3", "Use quick slot 3", InventoryConfig.Quick3.Value, "gameplay");
				RegisterKeyboard("sort", "Sort selected safe inventory rows", InventoryConfig.Sort.Value, "inventory");
				RegisterKeyboard("lock", "Toggle focused inventory slot lock", InventoryConfig.ToggleLock.Value, "inventory");
				ConfigEntry<bool> controllerEnabled = InventoryConfig.ControllerEnabled;
				if (controllerEnabled != null && controllerEnabled.Value)
				{
					string modifier = BoundControllerAction(InventoryConfig.ControllerModifier.Value);
					string quick = BoundControllerAction(InventoryConfig.ControllerQuick1.Value);
					string text = BoundControllerAction(InventoryConfig.ControllerQuick2.Value);
					string text2 = BoundControllerAction(InventoryConfig.ControllerQuick3.Value);
					string text3 = BoundControllerAction(InventoryConfig.ControllerSort.Value);
					string text4 = BoundControllerAction(InventoryConfig.ControllerToggleLock.Value);
					quick = ControllerBindingPolicy.EffectiveQuick1Action(modifier, quick, text, text2, text3, text4, out var _);
					RegisterController("controller-quick-1", "Use quick slot 1", quick, modifier, "gameplay");
					RegisterController("controller-quick-2", "Use quick slot 2", text, modifier, "gameplay");
					RegisterController("controller-quick-3", "Use quick slot 3", text2, modifier, "gameplay");
					RegisterController("controller-sort", "Sort selected safe inventory rows", text3, modifier, "inventory");
					RegisterController("controller-lock", "Toggle focused inventory slot lock", text4, modifier, "inventory");
				}
			}
		}

		private void RefreshBindings()
		{
			DisposeBindings();
			try
			{
				RegisterBindings();
			}
			catch
			{
				DisposeBindings();
				throw;
			}
		}

		private void DisposeBindings()
		{
			for (int num = _bindings.Count - 1; num >= 0; num--)
			{
				try
				{
					_bindings[num].Dispose();
				}
				catch (Exception exception)
				{
					Diagnostics.Error(exception, "Inventory keybinding cleanup failed.");
				}
			}
			_bindings.Clear();
		}

		private unsafe void RegisterKeyboard(string id, string display, KeyboardShortcut shortcut, string context)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (list.Count >= 8)
				{
					throw new InvalidOperationException("A keyboard chord may contain at most eight modifiers.");
				}
				list.Add(((object)(*(KeyCode*)(&modifier))/*cast due to .constrained prefix*/).ToString());
			}
			_bindings.Add(_keybindings.Register(new KeybindingDescriptor("runic.inventory", id, display, new InputChord("keyboard", ((object)((KeyboardShortcut)(ref shortcut)).MainKey/*cast due to .constrained prefix*/).ToString(), list), context)));
		}

		private void RegisterController(string id, string display, string action, string modifier, string context)
		{
			if (action.Length == 0 || modifier.Length == 0)
			{
				return;
			}
			try
			{
				_bindings.Add(_keybindings.Register(new KeybindingDescriptor("runic.inventory", id, display, new InputChord("controller", action, new string[1] { modifier }), context)));
			}
			catch (ArgumentException)
			{
				Diagnostics.Warn("Inventory skipped invalid controller route: " + id + ".");
			}
		}

		private static string BoundControllerAction(string value)
		{
			string text = value ?? string.Empty;
			if (text.Length == 0 || text.Length > 64)
			{
				return string.Empty;
			}
			string text2 = text.Trim();
			if (!text2.StartsWith("Joy", StringComparison.Ordinal))
			{
				return string.Empty;
			}
			for (int i = 0; i < text2.Length; i++)
			{
				if (!char.IsLetterOrDigit(text2[i]) && text2[i] != '_' && text2[i] != '-')
				{
					return string.Empty;
				}
			}
			return text2;
		}

		private void ShutdownRuntime()
		{
			if (_shuttingDown)
			{
				return;
			}
			_shuttingDown = true;
			RuntimeReady = false;
			InventoryRuntime runtime = _runtime;
			InventoryIntegrationApi.Detach(runtime);
			if (_configurationSubscribed)
			{
				((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged;
				_configurationSubscribed = false;
			}
			if (_inputLayoutSubscribed)
			{
				ZInput.OnInputLayoutChanged -= OnInputLayoutChanged;
				_inputLayoutSubscribed = false;
			}
			ControllerChordSession.Reset();
			DisposeBindings();
			try
			{
				runtime?.Dispose();
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Inventory runtime cleanup was incomplete.");
			}
			_runtime = null;
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception exception2)
			{
				Diagnostics.Error(exception2, "Inventory Harmony cleanup was incomplete.");
			}
			_harmony = null;
		}
	}
}
namespace RunicInventory.Integration
{
	internal sealed class ControllerBindingState
	{
		internal const int DefinitionCount = 6;

		internal ButtonDef Modifier { get; }

		internal ButtonDef Quick1 { get; }

		internal ButtonDef Quick2 { get; }

		internal ButtonDef Quick3 { get; }

		internal ButtonDef Sort { get; }

		internal ButtonDef ToggleLock { get; }

		internal string ReasonCode { get; }

		internal bool LegacyQuick1Mapped { get; }

		internal int ValidRouteCount { get; }

		internal bool Ready
		{
			get
			{
				if (Modifier != null)
				{
					return ValidRouteCount > 0;
				}
				return false;
			}
		}

		internal bool AllValid
		{
			get
			{
				if (Modifier != null)
				{
					return ValidRouteCount == 5;
				}
				return false;
			}
		}

		internal ControllerBindingState(ButtonDef modifier, ButtonDef quick1, ButtonDef quick2, ButtonDef quick3, ButtonDef sort, ButtonDef toggleLock, string reasonCode, bool legacyQuick1Mapped)
		{
			Modifier = modifier;
			Quick1 = quick1;
			Quick2 = quick2;
			Quick3 = quick3;
			Sort = sort;
			ToggleLock = toggleLock;
			ReasonCode = reasonCode ?? "controller.invalid";
			LegacyQuick1Mapped = legacyQuick1Mapped;
			ValidRouteCount = ((quick1 != null) ? 1 : 0) + ((quick2 != null) ? 1 : 0) + ((quick3 != null) ? 1 : 0) + ((sort != null) ? 1 : 0) + ((toggleLock != null) ? 1 : 0);
		}

		internal ButtonDef Definition(int index)
		{
			return (ButtonDef)(index switch
			{
				0 => Modifier, 
				1 => Quick1, 
				2 => Quick2, 
				3 => Quick3, 
				4 => Sort, 
				5 => ToggleLock, 
				_ => throw new ArgumentOutOfRangeException("index"), 
			});
		}
	}
	internal static class ControllerBindings
	{
		private static ZInput _instance;

		private static ControllerBindingState _cached;

		internal static ControllerBindingState Resolve()
		{
			if (_cached != null && _instance == ZInput.instance)
			{
				return _cached;
			}
			string text = Name(InventoryConfig.ControllerModifier?.Value);
			string quick = Name(InventoryConfig.ControllerQuick1?.Value);
			string text2 = Name(InventoryConfig.ControllerQuick2?.Value);
			string text3 = Name(InventoryConfig.ControllerQuick3?.Value);
			string text4 = Name(InventoryConfig.ControllerSort?.Value);
			string text5 = Name(InventoryConfig.ControllerToggleLock?.Value);
			quick = ControllerBindingPolicy.EffectiveQuick1Action(text, quick, text2, text3, text4, text5, out var legacyMapped);
			_instance = ZInput.instance;
			if (_instance == null)
			{
				return _cached = new ControllerBindingState(null, null, null, null, null, null, "controller.zinput-unavailable", legacyMapped);
			}
			string path;
			ButtonDef val = ResolveAction(text, out path);
			string[] array = new string[5] { quick, text2, text3, text4, text5 };
			string[] array2 = new string[5];
			ButtonDef[] array3 = (ButtonDef[])(object)new ButtonDef[5];
			for (int i = 0; i < 5; i++)
			{
				array3[i] = ResolveAction(array[i], out array2[i]);
			}
			int num = ControllerBindingPolicy.ValidRouteMask(text, path, array, array2);
			for (int j = 0; j < 5; j++)
			{
				if (!ControllerBindingPolicy.RouteIsValid(num, j))
				{
					array3[j] = null;
				}
			}
			string reasonCode = ((val == null) ? "controller.modifier-invalid" : (num switch
			{
				0 => "controller.no-valid-routes", 
				31 => "ok", 
				_ => "controller.one-or-more-routes-invalid", 
			}));
			return _cached = new ControllerBindingState(val, array3[0], array3[1], array3[2], array3[3], array3[4], reasonCode, legacyMapped);
		}

		internal static void Invalidate()
		{
			_instance = null;
			_cached = null;
		}

		internal static bool ShouldReserveAction(string action)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Invalid comparison between Unknown and I4
			ConfigEntry<bool> controllerEnabled = InventoryConfig.ControllerEnabled;
			if (controllerEnabled == null || !controllerEnabled.Value || string.IsNullOrEmpty(action) || ZInput.instance == null)
			{
				return false;
			}
			ControllerBindingState controllerBindingState = Resolve();
			if (controllerBindingState.Ready && controllerBindingState.Modifier.Held)
			{
				ButtonDef quick = controllerBindingState.Quick1;
				if (quick == null || !quick.Pressed)
				{
					ButtonDef quick2 = controllerBindingState.Quick2;
					if (quick2 == null || !quick2.Pressed)
					{
						ButtonDef quick3 = controllerBindingState.Quick3;
						if (quick3 == null || !quick3.Pressed)
						{
							ButtonDef sort = controllerBindingState.Sort;
							if (sort == null || !sort.Pressed)
							{
								ButtonDef toggleLock = controllerBindingState.ToggleLock;
								if (toggleLock == null || !toggleLock.Pressed)
								{
									goto IL_00a3;
								}
							}
						}
					}
				}
				ButtonDef buttonDef;
				try
				{
					buttonDef = ZInput.instance.GetButtonDef(action);
				}
				catch (Exception)
				{
					return false;
				}
				if (buttonDef == null || (int)buttonDef.Source != 180)
				{
					return false;
				}
				string actionPath;
				try
				{
					actionPath = buttonDef.GetActionPath(true);
				}
				catch (Exception)
				{
					return false;
				}
				if (!SamePath(actionPath, controllerBindingState.Modifier) && !SamePath(actionPath, controllerBindingState.Quick1) && !SamePath(actionPath, controllerBindingState.Quick2) && !SamePath(actionPath, controllerBindingState.Quick3) && !SamePath(actionPath, controllerBindingState.Sort))
				{
					return SamePath(actionPath, controllerBindingState.ToggleLock);
				}
				return true;
			}
			goto IL_00a3;
			IL_00a3:
			return false;
		}

		private static ButtonDef ResolveAction(string action, out string path)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			path = string.Empty;
			if (action.Length == 0 || action.Length > 64 || !action.StartsWith("Joy", StringComparison.Ordinal))
			{
				return null;
			}
			ButtonDef buttonDef;
			try
			{
				buttonDef = ZInput.instance.GetButtonDef(action);
			}
			catch (Exception)
			{
				return null;
			}
			if (buttonDef == null || (int)buttonDef.Source != 180)
			{
				return null;
			}
			try
			{
				path = buttonDef.GetActionPath(true)?.Trim() ?? string.Empty;
			}
			catch (Exception)
			{
				return null;
			}
			if (path.Length != 0)
			{
				return buttonDef;
			}
			return null;
		}

		private static string Name(string value)
		{
			string text = value ?? string.Empty;
			if (text.Length == 0 || text.Length > 64)
			{
				return string.Empty;
			}
			string text2 = text.Trim();
			for (int i = 0; i < text2.Length; i++)
			{
				if (!char.IsLetterOrDigit(text2[i]) && text2[i] != '_' && text2[i] != '-')
				{
					return string.Empty;
				}
			}
			return text2;
		}

		private static bool SamePath(string path, ButtonDef definition)
		{
			if (string.IsNullOrEmpty(path) || definition == null)
			{
				return false;
			}
			try
			{
				return string.Equals(path, definition.GetActionPath(true), StringComparison.Ordinal);
			}
			catch (Exception)
			{
				return false;
			}
		}
	}
	internal static class KeyboardInput
	{
		private static readonly KeyCode[] ModifierKeys;

		internal static bool ShortcutDown(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey, false))
			{
				return false;
			}
			int num = 0;
			int num2 = 0;
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (++num2 > 8)
				{
					return false;
				}
				if ((int)modifier == 0 || !ZInput.GetKey(modifier, false))
				{
					return false;
				}
				int num3 = ModifierIndex(modifier);
				if (num3 >= 0)
				{
					num |= 1 << num3;
				}
			}
			for (int i = 0; i < ModifierKeys.Length; i++)
			{
				if ((num & (1 << i)) == 0 && ZInput.GetKey(ModifierKeys[i], false))
				{
					return false;
				}
			}
			return true;
		}

		internal static bool ShouldReserveVanillaAction(string action)
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			KeyCode val = (KeyCode)(action switch
			{
				"Hotbar1" => 49, 
				"Hotbar2" => 50, 
				"Hotbar3" => 51, 
				"Hotbar4" => 52, 
				"Hotbar5" => 53, 
				"Hotbar6" => 54, 
				"Hotbar7" => 55, 
				"Hotbar8" => 56, 
				_ => 0, 
			});
			if ((int)val == 0)
			{
				return false;
			}
			if (!IsChordFor(val, InventoryConfig.Quick1.Value) && !IsChordFor(val, InventoryConfig.Quick2.Value))
			{
				return IsChordFor(val, InventoryConfig.Quick3.Value);
			}
			return true;
		}

		private static bool IsChordFor(KeyCode key, KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (((KeyboardShortcut)(ref shortcut)).MainKey == key)
			{
				return ShortcutDown(shortcut);
			}
			return false;
		}

		private static int ModifierIndex(KeyCode value)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between I4 and Unknown
			for (int i = 0; i < ModifierKeys.Length; i++)
			{
				if ((int)ModifierKeys[i] == (int)value)
				{
					return i;
				}
			}
			return -1;
		}

		static KeyboardInput()
		{
			KeyCode[] array = new KeyCode[8];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			ModifierKeys = (KeyCode[])(object)array;
		}
	}
	internal static class InputReservation
	{
		internal static bool ShouldSuppress(string action)
		{
			InventoryRuntime inventoryRuntime = Plugin.Instance?.Runtime;
			if (!Plugin.RuntimeReady || inventoryRuntime == null || !inventoryRuntime.AcceptsInput)
			{
				return false;
			}
			if (!ControllerChordSession.ShouldSuppress(action) && !ControllerBindings.ShouldReserveAction(action))
			{
				return KeyboardInput.ShouldReserveVanillaAction(action);
			}
			return true;
		}
	}
	internal static class ControllerInput
	{
		private static ControllerBindingState _loggedBindings;

		internal static void Tick(InventoryRuntime runtime, bool inventoryVisible, bool gameplayInput)
		{
			if (runtime == null)
			{
				return;
			}
			ConfigEntry<bool> controllerEnabled = InventoryConfig.ControllerEnabled;
			if (controllerEnabled == null || !controllerEnabled.Value || ZInput.instance == null)
			{
				return;
			}
			ControllerBindingState controllerBindingState = ControllerBindings.Resolve();
			if (_loggedBindings != controllerBindingState)
			{
				_loggedBindings = controllerBindingState;
				if (controllerBindingState.AllValid)
				{
					Diagnostics.Info(controllerBindingState.LegacyQuick1Mapped ? "Inventory controller chords validated by six unique effective gamepad paths; the exact legacy default Quick 1 route is using JoyMap." : "Inventory controller chords validated by six unique effective gamepad paths.");
				}
				else if (controllerBindingState.Ready)
				{
					Diagnostics.Warn("Inventory controller chords partially available (" + controllerBindingState.ValidRouteCount + "/5 routes): " + controllerBindingState.ReasonCode + ".");
				}
				else
				{
					Diagnostics.Warn("Inventory controller chords disabled: " + controllerBindingState.ReasonCode + ".");
				}
			}
			bool active = ControllerChordSession.Active;
			if (!controllerBindingState.Ready || active || !controllerBindingState.Modifier.Held)
			{
				return;
			}
			if (inventoryVisible)
			{
				ButtonDef toggleLock = controllerBindingState.ToggleLock;
				if (toggleLock != null && toggleLock.Pressed)
				{
					ControllerChordSession.Begin(controllerBindingState);
					runtime.ToggleFocusedLock("controller");
					return;
				}
			}
			if (inventoryVisible)
			{
				ButtonDef sort = controllerBindingState.Sort;
				if (sort != null && sort.Pressed)
				{
					ControllerChordSession.Begin(controllerBindingState);
					runtime.SortSelectedRows("controller");
					return;
				}
			}
			if (!gameplayInput)
			{
				return;
			}
			ButtonDef quick = controllerBindingState.Quick1;
			if (quick != null && quick.Pressed)
			{
				ControllerChordSession.Begin(controllerBindingState);
				runtime.UseQuick(InventoryRoleKind.Quick1, "controller");
				return;
			}
			ButtonDef quick2 = controllerBindingState.Quick2;
			if (quick2 != null && quick2.Pressed)
			{
				ControllerChordSession.Begin(controllerBindingState);
				runtime.UseQuick(InventoryRoleKind.Quick2, "controller");
				return;
			}
			ButtonDef quick3 = controllerBindingState.Quick3;
			if (quick3 != null && quick3.Pressed)
			{
				ControllerChordSession.Begin(controllerBindingState);
				runtime.UseQuick(InventoryRoleKind.Quick3, "controller");
			}
		}

		internal static void ResetLog()
		{
			_loggedBindings = null;
		}
	}
	internal static class ControllerChordSession
	{
		private static ControllerBindingState _bindings;

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

		private static int _releasedFrame = -1;

		internal static bool Active
		{
			get
			{
				UpdateRelease();
				return _bindings != null;
			}
		}

		internal static void Begin(ControllerBindingState bindings)
		{
			if (bindings == null || !bindings.Ready || _bindings != null)
			{
				return;
			}
			_bindings = bindings;
			Paths.Clear();
			for (int i = 0; i < 6; i++)
			{
				ButtonDef obj = bindings.Definition(i);
				string text = ((obj != null) ? obj.GetActionPath(true) : null);
				if (!string.IsNullOrEmpty(text))
				{
					Paths.Add(text);
				}
			}
			_releasedFrame = -1;
		}

		internal static bool ShouldSuppress(string action)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			UpdateRelease();
			if (_bindings == null || ZInput.instance == null || string.IsNullOrEmpty(action))
			{
				return false;
			}
			ButtonDef buttonDef;
			try
			{
				buttonDef = ZInput.instance.GetButtonDef(action);
			}
			catch (Exception)
			{
				return false;
			}
			if (buttonDef == null || (int)buttonDef.Source != 180)
			{
				return false;
			}
			string actionPath;
			try
			{
				actionPath = buttonDef.GetActionPath(true);
			}
			catch (Exception)
			{
				return false;
			}
			if (!string.IsNullOrEmpty(actionPath))
			{
				return Paths.Contains(actionPath);
			}
			return false;
		}

		internal static void Reset()
		{
			_bindings = null;
			Paths.Clear();
			_releasedFrame = -1;
			ControllerBindings.Invalidate();
			ControllerInput.ResetLog();
		}

		private static void UpdateRelease()
		{
			if (_bindings == null)
			{
				return;
			}
			bool flag = false;
			for (int i = 0; i < 6; i++)
			{
				ButtonDef obj = _bindings.Definition(i);
				if (obj != null && obj.Held)
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				_releasedFrame = -1;
			}
			else if (_releasedFrame < 0)
			{
				_releasedFrame = Time.frameCount;
			}
			else if (_releasedFrame != Time.frameCount)
			{
				_bindings = null;
				Paths.Clear();
				_releasedFrame = -1;
			}
		}
	}
	internal static class HarmonyOrderIds
	{
		internal const string Interaction = "chazman.RunicInteraction";

		internal const string Storage = "chazman.RunicStorage";

		internal const string Agriculture = "chazman.RunicAgriculture";
	}
	[HarmonyPatch(typeof(Player), "SetLocalPlayer", new Type[] { })]
	internal static class LocalPlayerPatch
	{
		private static void Postfix(Player __instance)
		{
			try
			{
				Plugin.Instance?.Runtime?.OnLocalPlayerChanged(__instance);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Local-player topology bind failed closed.");
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Load", new Type[] { typeof(ZPackage) })]
	internal static class PlayerLoadPatch
	{
		private static void Prefix(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				Plugin.Instance?.Runtime?.OnPlayerLoadStarted(__instance);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Player-load topology scope failed closed.");
			}
		}

		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				Plugin.Instance?.Runtime?.OnPlayerLoadCompleted(__instance);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Loaded player topology bind failed closed.");
			}
		}

		private static Exception Finalizer(Player __instance, Exception __exception)
		{
			if (__exception == null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return __exception;
			}
			try
			{
				Plugin.Instance?.Runtime?.OnPlayerLoadFaulted(__instance);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Faulted player-load topology cleanup failed closed.");
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Inventory), "FindEmptySlot", new Type[] { typeof(bool) })]
	internal static class FindEmptySlotPatch
	{
		private static bool Prefix(Inventory __instance, bool __0, ref Vector2i __result)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			InventoryRuntime inventoryRuntime = Plugin.Instance?.Runtime;
			if (inventoryRuntime == null)
			{
				return true;
			}
			try
			{
				if (!inventoryRuntime.TryFindEmptySlot(__instance, __0, out var result))
				{
					return true;
				}
				__result = result;
				return false;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Special-row empty-slot routing faulted; vanilla routing won for this call.");
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "FindFreeStackItem", new Type[]
	{
		typeof(string),
		typeof(int),
		typeof(float)
	})]
	internal static class FindFreeStackPatch
	{
		private static void Postfix(Inventory __instance, string __0, int __1, float __2, ref ItemData __result)
		{
			try
			{
				Plugin.Instance?.Runtime?.ReplaceLockedFreeStack(__instance, __0, __1, __2, ref __result);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Locked stack routing faulted; automatic stacking was declined for this call.");
				__result = null;
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[]
	{
		typeof(ItemData),
		typeof(int)
	})]
	internal static class CanAddItemPatch
	{
		private static void Postfix(Inventory __instance, ItemData __0, int __1, ref bool __result)
		{
			try
			{
				Plugin.Instance?.Runtime?.AdjustCanAddItem(__instance, __0, __1, ref __result);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Safe carrying-capacity validation faulted; capacity was declined.");
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "DropItem", new Type[]
	{
		typeof(Inventory),
		typeof(ItemData),
		typeof(int),
		typeof(Vector2i)
	})]
	internal static class InventoryGridDropPatch
	{
		private static bool Prefix(InventoryGrid __instance, Inventory __0, ItemData __1, int __2, Vector2i __3, ref bool __result)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			InventoryRuntime inventoryRuntime = Plugin.Instance?.Runtime;
			if (inventoryRuntime == null)
			{
				return true;
			}
			try
			{
				if (inventoryRuntime.AllowGridDrop(__instance.GetInventory(), __0, __1, __2, __3))
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Inventory grid validation faulted; the requested move was declined.");
				__result = false;
				return false;
			}
		}

		private static void Postfix(InventoryGrid __instance, Vector2i __3, bool __result)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Plugin.Instance?.Runtime?.AfterGridDrop(__instance.GetInventory(), __3, __result);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Equipment-role post-drop handling failed closed.");
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem", new Type[]
	{
		typeof(InventoryGrid),
		typeof(ItemData),
		typeof(Vector2i),
		typeof(Modifier)
	})]
	internal static class InventorySelectedActionPatch
	{
		[HarmonyPriority(800)]
		[HarmonyBefore(new string[] { "chazman.RunicInteraction" })]
		private static bool Prefix(InventoryGrid __0, ItemData __1, Modifier __3)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return Plugin.Instance?.Runtime?.AllowSelectedAction(__0, __1, __3) ?? true;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Locked-slot selection validation faulted; the destructive/move action was declined.");
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "OnRightClick", new Type[] { typeof(UIInputHandler) })]
	internal static class InventoryGridRightClickLockPatch
	{
		[HarmonyPriority(800)]
		private static bool Prefix(InventoryGrid __instance)
		{
			try
			{
				return Plugin.Instance?.Runtime?.TryTogglePointerLock(__instance) != true;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Alt-right-click slot lock failed closed.");
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "DropItem", new Type[]
	{
		typeof(Inventory),
		typeof(ItemData),
		typeof(int)
	})]
	internal static class HumanoidDropItemPatch
	{
		private static bool Prefix(Humanoid __instance, Inventory __0, ItemData __1, ref bool __result)
		{
			try
			{
				if (Plugin.Instance?.Runtime?.AllowItemAction(__instance, __0, __1, "dropping it") ?? true)
				{
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Locked-item drop validation faulted; the drop was declined.");
				__result = false;
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UseItem", new Type[]
	{
		typeof(Inventory),
		typeof(ItemData),
		typeof(bool)
	})]
	internal static class HumanoidUseItemPatch
	{
		private static bool Prefix(Humanoid __instance, Inventory __0, ItemData __1)
		{
			try
			{
				return Plugin.Instance?.Runtime?.AllowItemAction(__instance, __0, __1, "using it") ?? true;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Locked-item use validation faulted; the use was declined.");
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "EquipItem", new Type[]
	{
		typeof(ItemData),
		typeof(bool)
	})]
	internal static class HumanoidEquipItemPatch
	{
		[HarmonyPriority(800)]
		[HarmonyBefore(new string[] { "chazman.RunicInteraction" })]
		private static bool Prefix(Humanoid __instance, ItemData __0, ref bool __result, ref bool __state)
		{
			try
			{
				InventoryRuntime inventoryRuntime = Plugin.Instance?.Runtime;
				if (inventoryRuntime == null || inventoryRuntime.AllowEquip(__instance, __0))
				{
					__state = inventoryRuntime?.BeginEquipmentTransition(__instance, __0) ?? false;
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Locked equipment-target validation faulted; replacement was declined.");
				__result = false;
				return false;
			}
		}

		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicInteraction" })]
		private static void Postfix(Humanoid __instance, ItemData __0, bool __result)
		{
			try
			{
				Plugin.Instance?.Runtime?.OnEquipped(__instance, __0, __result);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Equipment-role relocation failed closed.");
			}
		}

		private static Exception Finalizer(bool __state, Exception __exception)
		{
			try
			{
				Plugin.Instance?.Runtime?.EndEquipmentTransition(__state, __exception);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Equipment transition cleanup failed closed.");
				try
				{
					Plugin.Instance?.Runtime?.FailClosed("equipment.transition-cleanup-faulted");
				}
				catch (Exception exception2)
				{
					Diagnostics.Error(exception2, "Equipment transition fail-closed publication faulted.");
				}
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Humanoid), "Pickup", new Type[]
	{
		typeof(GameObject),
		typeof(bool),
		typeof(bool)
	})]
	internal static class PickupFilterPatch
	{
		[HarmonyPriority(800)]
		[HarmonyBefore(new string[] { "chazman.RunicInteraction" })]
		private static bool Prefix(Humanoid __instance, GameObject __0, ref bool __result, ref EquipmentAdditionState __state)
		{
			try
			{
				InventoryRuntime inventoryRuntime = Plugin.Instance?.Runtime;
				if (inventoryRuntime == null || inventoryRuntime.AllowPickup(__instance, __0))
				{
					__state = inventoryRuntime?.BeginEquipmentAddition(__instance, (!Object.op_Implicit((Object)(object)__0)) ? null : __0.GetComponent<ItemDrop>()?.m_itemData);
					return true;
				}
				__result = false;
				return false;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Pickup filter faulted; vanilla pickup handling won.");
				return true;
			}
		}

		private static void Postfix(bool __result, EquipmentAdditionState __state)
		{
			try
			{
				Plugin.Instance?.Runtime?.CompleteEquipmentAddition(__state, __result);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Picked-up equipment placement failed closed.");
			}
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "GetHoverText", new Type[] { })]
	internal static class ItemDropHoverPatch
	{
		private static void Postfix(ItemDrop __instance, ref string __result)
		{
			try
			{
				Plugin.Instance?.Runtime?.AppendPickupPreview(__instance, ref __result);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Pickup preview failed closed; vanilla hover text was retained.");
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting", new Type[] { typeof(Player) })]
	internal static class InventoryCraftingPatch
	{
		[HarmonyPriority(800)]
		[HarmonyBefore(new string[] { "chazman.RunicCrafting" })]
		private static bool Prefix(InventoryGui __instance, ref EquipmentAdditionState __state)
		{
			try
			{
				InventoryRuntime inventoryRuntime = Plugin.Instance?.Runtime;
				int num;
				if (inventoryRuntime == null)
				{
					num = 1;
				}
				else
				{
					num = (inventoryRuntime.AllowCrafting(__instance) ? 1 : 0);
					if (num == 0)
					{
						goto IL_0036;
					}
				}
				__state = inventoryRuntime?.BeginEquipmentAddition((Humanoid)(object)Player.m_localPlayer);
				goto IL_0036;
				IL_0036:
				return (byte)num != 0;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Locked upgrade/crafting selection validation faulted; the action was declined.");
				return false;
			}
		}

		private static void Postfix(EquipmentAdditionState __state)
		{
			try
			{
				Plugin.Instance?.Runtime?.CompleteEquipmentAddition(__state, succeeded: true);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Crafted equipment placement failed closed.");
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "RepairOneItem")]
	internal static class InventoryRepairAllowancePatch
	{
		[HarmonyPriority(800)]
		[HarmonyBefore(new string[] { "chazman.RunicCrafting" })]
		private static void Prefix(ref bool __state)
		{
			try
			{
				__state = Plugin.Instance?.Runtime?.BeginRepairAllowance() == true;
			}
			catch (Exception exception)
			{
				__state = false;
				Diagnostics.Error(exception, "Repair protection allowance could not start; vanilla repair remains available.");
			}
		}

		private static Exception Finalizer(bool __state, Exception __exception)
		{
			try
			{
				Plugin.Instance?.Runtime?.EndRepairAllowance(__state);
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Repair protection allowance cleanup faulted.");
			}
			return __exception;
		}
	}
	internal static class StationLockGuard
	{
		internal static bool Allow(Humanoid actor, ItemData item, string action, ref bool result, string nativeBoundary = null)
		{
			try
			{
				if (Plugin.Instance?.Runtime?.AllowStationItem(actor, item, action) ?? true)
				{
					return true;
				}
				result = false;
				return false;
			}
			catch (Exception exception)
			{
				Diagnostics.Error(exception, "Locked-item station validation faulted; the station action was declined.");
				result = false;
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(Smelter), "OnAddOre", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class SmelterOreLockPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicSafety" })]
		private static bool Prefix(Humanoid __1, ItemData __2, ref bool __result)
		{
			return StationLockGuard.Allow(__1, __2, "processing it", ref __result, "Smelter.OnAddOre");
		}
	}
	[HarmonyPatch(typeof(Smelter), "OnAddFuel", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class SmelterFuelLockPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicSafety" })]
		private static bool Prefix(Humanoid __1, ItemData __2, ref bool __result)
		{
			return StationLockGuard.Allow(__1, __2, "processing it", ref __result, "Smelter.OnAddFuel");
		}
	}
	[HarmonyPatch(typeof(CookingStation), "CookItem", new Type[]
	{
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class CookingItemLockPatch
	{
		private static bool Prefix(Humanoid __0, ItemData __1, ref bool __result)
		{
			return StationLockGuard.Allow(__0, __1, "cooking it", ref __result, "CookingStation.CookItem");
		}
	}
	[HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class CookingFuelLockPatch
	{
		[HarmonyPriority(400)]
		[HarmonyAfter(new string[] { "chazman.RunicSafety" })]
		[HarmonyBefore(new string[] { "chazman.RunicProduction" })]
		private static bool Prefix(Humanoid __1, ItemData __2, ref bool __result)
		{
			return StationLockGuard.Allow(__1, __2, "processing it", ref __result, "CookingStation.OnAddFuelSwitch");
		}
	}
	[HarmonyPatch(typeof(Fermenter), "AddItem", new Type[]
	{
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class FermenterLockPatch
	{
		[HarmonyPriority(400)]
		[HarmonyAfter(new string[] { "chazman.RunicSafety" })]
		[HarmonyBefore(new string[] { "chazman.RunicProduction" })]
		private static bool Prefix(Humanoid __0, ItemData __1, ref bool __result)
		{
			return StationLockGuard.Allow(__0, __1, "fermenting it", ref __result);
		}
	}
	[HarmonyPatch(typeof(Incinerator), "OnIncinerate", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class IncineratorLockPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicSafety" })]
		private static bool Prefix(Humanoid __1, ItemData __2, ref bool __result)
		{
			return StationLockGuard.Allow(__1, __2, "incinerating it", ref __result);
		}
	}
	[HarmonyPatch(typeof(ItemStand), "UseItem", new Type[]
	{
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class ItemStandLockPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicSafety" })]
		private static bool Prefix(Humanoid __0, ItemData __1, ref bool __result)
		{
			return StationLockGuard.Allow(__0, __1, "displaying it", ref __result, "ItemStand.UseItem");
		}
	}
	[HarmonyPatch(typeof(OfferingBowl), "UseItem", new Type[]
	{
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class OfferingLockPatch
	{
		private static bool Prefix(Humanoid __0, ItemData __1, ref bool __result)
		{
			return StationLockGuard.Allow(__0, __1, "sacrificing it", ref __result, "OfferingBowl.UseItem");
		}
	}
	[HarmonyPatch(typeof(ShieldGenerator), "OnAddFuel", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class ShieldFuelLockPatch
	{
		private static bool Prefix(Humanoid __1, ItemData __2, ref bool __result)
		{
			return StationLockGuard.Allow(__1, __2, "processing it", ref __result, "ShieldGenerator.OnAddFuel");
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetButton", new Type[] { typeof(string) })]
	internal static class ControllerGetButtonPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicStorage", "chazman.RunicAgriculture" })]
		private static bool Prefix(string name, ref bool __result)
		{
			return Suppress(name, ref __result);
		}

		private static bool Suppress(string name, ref bool result)
		{
			if (!InputReservation.ShouldSuppress(name))
			{
				return true;
			}
			result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetButtonDown", new Type[] { typeof(string) })]
	internal static class ControllerGetButtonDownPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicStorage", "chazman.RunicAgriculture" })]
		private static bool Prefix(string name, ref bool __result)
		{
			if (!InputReservation.ShouldSuppress(name))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetButtonUp", new Type[] { typeof(string) })]
	internal static class ControllerGetButtonUpPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicStorage", "chazman.RunicAgriculture" })]
		private static bool Prefix(string name, ref bool __result)
		{
			if (!InputReservation.ShouldSuppress(name))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetButtonPressedTimer", new Type[] { typeof(string) })]
	internal static class ControllerPressedTimerPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicStorage", "chazman.RunicAgriculture" })]
		private static bool Prefix(string name, ref float __result)
		{
			if (!InputReservation.ShouldSuppress(name))
			{
				return true;
			}
			__result = 0f;
			return false;
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetButtonLastPressedTimer", new Type[] { typeof(string) })]
	internal static class ControllerLastPressedTimerPatch
	{
		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "chazman.RunicStorage", "chazman.RunicAgriculture" })]
		private static bool Prefix(string name, ref float __result)
		{
			if (!InputReservation.ShouldSuppress(name))
			{
				return true;
			}
			__result = 0f;
			return false;
		}
	}
	internal sealed class ItemMutationEvidence
	{
		internal ItemData Item { get; }

		internal Vector2i Coordinate { get; }

		internal string Fingerprint { get; }

		internal ItemMutationEvidence(ItemData item, Vector2i coordinate, string fingerprint)
		{
			//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)
			Item = item;
			Coordinate = coordinate;
			Fingerprint = fingerprint;
		}
	}
	internal static class InventoryEvidence
	{
		private sealed class ReferenceComparer<T> : IEqualityComparer<T> where T : class
		{
			internal static readonly ReferenceComparer<T> Instance = new ReferenceComparer<T>();

			public bool Equals(T x, T y)
			{
				return x == y;
			}

			public int GetHashCode(T obj)
			{
				return RuntimeHelpers.GetHashCode(obj);
			}
		}

		internal const int MaximumCustomEntriesPerItem = 64;

		internal const int MaximumCustomStringCharacters = 4096;

		internal const int MaximumAggregateCustomCharacters = 65536;

		internal const int MaximumSerializedBytes = 1048576;

		internal static bool TryCaptureMutation(Inventory inventory, out IReadOnlyList<ItemMutationEvidence> evidence, out string reasonCode)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			evidence = Array.Empty<ItemMutationEvidence>();
			if (inventory == null)
			{
				reasonCode = "evidence.inventory-null";
				return false;
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null || allItems.Count > 128)
			{
				reasonCode = "evidence.item-bound-exceeded";
				return false;
			}
			HashSet<int> hashSet = new HashSet<int>();
			List<ItemMutationEvidence> list = new List<ItemMutationEvidence>(allItems.Count);
			int aggregateCustom = 0;
			foreach (ItemData item in allItems)
			{
				if (item == null || item.m_gridPos.x < 0 || item.m_gridPos.x >= inventory.GetWidth() || item.m_gridPos.y < 0 || item.m_gridPos.y >= inventory.GetHeight() || !hashSet.Add(item.m_gridPos.y * inventory.GetWidth() + item.m_gridPos.x) || !TryFingerprint(item, includePosition: false, ref aggregateCustom, out var fingerprint))
				{
					reasonCode = "evidence.item-invalid";
					return false;
				}
				list.Add(new ItemMutationEvidence(item, item.m_gridPos, fingerprint));
			}
			evidence = list.AsReadOnly();
			reasonCode = "ok";
			return true;
		}

		internal static bool VerifyUnchangedExceptPosition(Inventory inventory, IReadOnlyList<ItemMutationEvidence> before, out string reasonCode)
		{
			if (inventory == null || before == null || inventory.GetAllItems().Count != before.Count)
			{
				reasonCode = "evidence.item-count-changed";
				return false;
			}
			HashSet<ItemData> hashSet = new HashSet<ItemData>(ReferenceComparer<ItemData>.Instance);
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				hashSet.Add(allItem);
			}
			HashSet<int> hashSet2 = new HashSet<int>();
			int aggregateCustom = 0;
			foreach (ItemMutationEvidence item2 in before)
			{
				ItemData item = item2.Item;
				if (!hashSet.Contains(item) || item.m_gridPos.x < 0 || item.m_gridPos.x >= inventory.GetWidth() || item.m_gridPos.y < 0 || item.m_gridPos.y >= inventory.GetHeight() || !hashSet2.Add(item.m_gridPos.y * inventory.GetWidth() + item.m_gridPos.x) || !TryFingerprint(item, includePosition: false, ref aggregateCustom, out var fingerprint) || !string.Equals(fingerprint, item2.Fingerprint, StringComparison.Ordinal))
				{
					reasonCode = "evidence.metadata-or-membership-changed";
					return false;
				}
			}
			reasonCode = "ok";
			return true;
		}

		internal static void RestorePositions(IReadOnlyList<ItemMutationEvidence> evidence)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (evidence == null)
			{
				return;
			}
			foreach (ItemMutationEvidence item in evidence)
			{
				if (item?.Item != null)
				{
					item.Item.m_gridPos = item.Coordinate;
				}
			}
		}

		internal static bool TryFingerprint(ItemData item, bool includePosition, out string fingerprint)
		{
			int aggregateCustom = 0;
			return TryFingerprint(item, includePosition, ref aggregateCustom, out fingerprint);
		}

		internal static bool TryDeterministicSave(Inventory inventory, out string reasonCode)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			try
			{
				ZPackage val = new ZPackage();
				inventory.Save(val);
				byte[] array = val.GetArray();
				if (array == null || array.Length > 1048576)
				{
					reasonCode = "serialization.payload-bound";
					return false;
				}
				ZPackage val2 = new ZPackage();
				inventory.Save(val2);
				byte[] array2 = val2.GetArray();
				if (array2 == null || array2.Length != array.Length)
				{
					reasonCode = "serialization.nondeterministic";
					return false;
				}
				int num = 0;
				for (int i = 0; i < array.Length; i++)
				{
					num |= array[i] ^ array2[i];
				}
				reasonCode = ((num == 0) ? "ok" : "serialization.nondeterministic");
				return num == 0;
			}
			catch (Exception)
			{
				reasonCode = "serialization.failed";
				return false;
			}
		}

		internal static string HashTopology(string value)
		{
			using SHA256 sHA = SHA256.Create();
			byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(value ?? string.Empty));
			StringBuilder stringBuilder = new StringBuilder(64);
			byte[] array2 = array;
			foreach (byte b in array2)
			{
				stringBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture));
			}
			return stringBuilder.ToString();
		}

		private static bool TryFingerprint(ItemData item, bool includePosition, ref int aggregateCustom, out string fingerprint)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected I4, but got Unknown
			fingerprint = string.Empty;
			if (item == null || item.m_shared == null || item.m_stack <= 0)
			{
				return false;
			}
			string text = ValheimContracts.PrefabId(item);
			string text2 = item.m_shared.m_name ?? string.Empty;
			string text3 = item.m_crafterName ?? string.Empty;
			if (text.Length == 0 || text2.Length > 256 || text3.Length > 256)
			{
				return false;
			}
			StringBuilder stringBuilder = new StringBuilder(512);
			Append(stringBuilder, text);
			Append(stringBuilder, text2);
			stringBuilder.Append('|').Append((int)item.m_shared.m_itemType).Append('|')
				.Append(item.m_stack)
				.Append('|')
				.Append(BitConverter.SingleToInt32Bits(item.m_durability))
				.Append('|')
				.Append(item.m_equipped ? 1 : 0)
				.Append('|')
				.Append(item.m_quality)
				.Append('|')
				.Append(item.m_variant)
				.Append('|')
				.Append(item.m_crafterID)
				.Append('|')
				.Append(item.m_worldLevel)
				.Append('|')
				.Append(item.m_pickedUp ? 1 : 0);
			Append(stringBuilder, text3);
			if (includePosition)
			{
				stringBuilder.Append('|').Append(item.m_gridPos.x).Append('|')
					.Append(item.m_gridPos.y);
			}
			int num = item.m_customData?.Count ?? 0;
			if (num > 64)
			{
				return false;
			}
			List<string> list = new List<string>(num);
			if (item.m_customData != null)
			{
				foreach (KeyValuePair<string, string> customDatum in item.m_customData)
				{
					string text4 = customDatum.Key ?? string.Empty;
					string text5 = customDatum.Value ?? string.Empty;
					if (text4.Length > 4096 || text5.Length > 4096)
					{
						return false;
					}
					aggregateCustom += text4.Length + text5.Length;
					if (aggregateCustom > 65536)
					{
						return false;
					}
					list.Add(text4);
				}
				list.Sort(StringComparer.Ordinal);
				foreach (string item2 in list)
				{
					Append(stringBuilder, item2);
					Append(stringBuilder, item.m_customData[item2] ?? string.Empty);
				}
			}
			fingerprint = HashTopology(stringBuilder.ToString());
			return true;
		}

		private static void Append(StringBuilder builder, string value)
		{
			builder.Append('|').Append(value.Length).Append(':')
				.Append(value);
		}
	}
	internal sealed class EquipmentAdditionState
	{
		internal Player Player { get; }

		internal Inventory Inventory { get; }

		internal InventoryRoleKind? ExpectedRole { get; }

		internal IReadOnlyList<ItemData> Before { get; }

		internal EquipmentAdditionState(Player player, Inventory inventory, InventoryRoleKind? expectedRole, IReadOnlyList<ItemData> before)
		{
			Player = player;
			Inventory = inventory;
			ExpectedRole = expectedRole;
			Before = before;
		}
	}
	internal readonly struct StackCapacityKey : IEquatable<StackCapacityKey>
	{
		internal string SharedName { get; }

		internal int Quality { get; }

		internal int WorldLevel { get; }

		internal StackCapacityKey(string sharedName, int quality, int worldLevel)
		{
			SharedName = sharedName ?? string.Empty;
			Quality = quality;
			WorldLevel = worldLevel;
		}

		public bool Equals(StackCapacityKey other)
		{
			if (Quality == other.Quality && WorldLevel == other.WorldLevel)
			{
				return string.Equals(SharedName, other.SharedName, StringComparison.Ordinal);
			}
			return false;
		}

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

		public override int GetHashCode()
		{
			return (((StringComparer.Ordinal.GetHashCode(SharedName) * 397) ^ Quality) * 397) ^ WorldLevel;
		}
	}
	internal sealed class InventoryRuntime : IInventoryTopologyService, IInventoryProtectionService, IInventoryStatusService, IItemProtectionQuery, IDisposable
	{
		private sealed class MutationScope : IDisposable
		{
			private InventoryRuntime _owner;

			internal MutationScope(InventoryRuntime owner)
			{
				_owner = owner;
			}

			public void Dispose()
			{
				InventoryRuntime inventoryRuntime = Interlocked.Exchange(ref _owner, null);
				if (inventoryRuntime != null)
				{
					Interlocked.Exchange(ref inventoryRuntime._mutationActive, 0);
				}
			}
		}

		private const int MaximumProtectionDiagnostics = 32;

		private readonly bool _batch;

		private readonly int _mainThreadId;

		private readonly Dictionary<StackCapacityKey, int> _stackCapacity = new Dictionary<StackCapacityKey, int>();

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

		private readonly object _protectionDiagnosticGate = new object();

		private Player _player;

		private Inventory _inventory;

		private TopologyLayout _layout;

		private PersistedTopologyState _persisted;

		private InventoryTopologySnapshot _snapshot;

		private PickupFilterSet _filters;

		private InventoryAuthorityMode _mode;

		private string _reasonCode = "runtime.not-initialized";

		private string _statusText = "Runic Inventory: waiting for the local player.";

		private long _generation;

		private int _freePickupSlots;

		private float _cachedWeight;

		private bool _topologyActive;

		private bool _playerLoadInProgress;

		private bool _loadMetadataRefreshed;

		private int _equipmentTransitionDepth;

		private int _repairAllowanceDepth;

		private int _mutationActive;

		private bool _equipmentRefreshPending;

		private bool _equipmentTransitionFaulted;

		private bool _disableCleanupPending;

		private bool _rebuilding;

		private bool _disposed;

		private float _nextMessageTime;

		private readonly Rect[] _roleSlotRects = (Rect[])(object)new Rect[8];

		private static readonly string[] RoleLabels = new string[8] { "Helmet", "Chest", "Legs", "Cape", "Utility", "Quick 1", "Quick 2", "Quick 3" };

		public string ProviderId => "runic.inventory";

		internal bool TopologyActive
		{
			get
			{
				if (_topologyActive && !_disposed && _mode == InventoryAuthorityMode.AuthoritativeLocal && IsAuthoritativeLocal(_player))
				{
					return LiveDimensionsMatch();
				}
				return false;
			}
		}

		internal InventoryAuthorityMode Mode => _mode;

		internal bool AcceptsInput => CanEnforceLocks();

		internal InventoryRuntime(bool batch)
		{
			_batch = batch;
			_mainThreadId = Thread.CurrentThread.ManagedThreadId;
			_filters = PickupFilterSet.Parse(InventoryConfig.FilteredPickupItems?.Value ?? string.Empty);
			_mode = (batch ? InventoryAuthorityMode.BatchInert : InventoryAuthorityMode.Unavailable);
			_reasonCode = (batch ? "authority.batch-inert" : "player.not-loaded");
		}

		internal void Initialize()
		{
			if (_batch)
			{
				RebuildStatusOnly();
			}
			else
			{
				Rebind(Player.m_localPlayer, "startup");
			}
		}

		internal void Tick()
		{
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || _batch)
			{
				return;
			}
			if (_player != Player.m_localPlayer)
			{
				Rebind(Player.m_localPlayer, "local-player-changed");
			}
			if (!Object.op_Implicit((Object)(object)_player) || _inventory == null)
			{
				return;
			}
			if (_disableCleanupPending)
			{
				ConfigEntry<bool> enabled = InventoryConfig.Enabled;
				if (enabled != null && enabled.Value)
				{
					_disableCleanupPending = false;
					Rebind(Player.m_localPlayer, "disable-cleanup-cancelled");
				}
				else
				{
					if (!TryCompleteDisableCleanup())
					{
						return;
					}
					Rebind(Player.m_localPlayer, "disable-cleanup-completed");
				}
				if (!Object.op_Implicit((Object)(object)_player) || _inventory == null)
				{
					return;
				}
			}
			if (_layout != null && !LiveDimensionsMatch())
			{
				FailClosed("topology.runtime-dimension-changed");
				return;
			}
			bool flag = IsAuthoritativeLocal(_player);
			if ((_mode == InventoryAuthorityMode.AuthoritativeLocal && !flag) || (_mode == InventoryAuthorityMode.RemoteDedicatedCompatibility && flag))
			{
				Rebind(_player, "authority-changed");
				if (!Object.op_Implicit((Object)(object)_player) || _inventory == null)
				{
					return;
				}
			}
			if (!AcceptsInput)
			{
				return;
			}
			bool flag2 = (Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible();
			if (flag2)
			{
				if (KeyboardInput.ShortcutDown(InventoryConfig.Sort.Value))
				{
					SortSelectedRows("keyboard");
				}
				if (KeyboardInput.ShortcutDown(InventoryConfig.ToggleLock.Value))
				{
					ToggleFocusedLock("keyboard");
				}
			}
			else if (ValheimContracts.PlayerMayTakeInput(_player))
			{
				if (KeyboardInput.ShortcutDown(InventoryConfig.Quick1.Value))
				{
					UseQuick(InventoryRoleKind.Quick1, "keyboard");
				}
				else if (KeyboardInput.ShortcutDown(InventoryConfig.Quick2.Value))
				{
					UseQuick(InventoryRoleKind.Quick2, "keyboard");
				}
				else if (KeyboardInput.ShortcutDown(InventoryConfig.Quick3.Value))
				{
					UseQuick(InventoryRoleKind.Quick3, "keyboard");
				}
			}
			ControllerInput.Tick(this, flag2, !flag2 && ValheimContracts.PlayerMayTakeInput(_player));
		}

		internal void Draw()
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || _batch || (Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible() || ValheimContracts.InventoryModalVisible())
			{
				return;
			}
			if (TopologyActive)
			{
				ConfigEntry<bool> showRoleLabels = InventoryConfig.ShowRoleLabels;
				if (showRoleLabels == null || showRoleLabels.Value)
				{
					DrawRoleOverlay();
				}
				DrawLockedSlotOverlay();
			}
			ConfigEntry<bool> showInventoryStatus = InventoryConfig.ShowInventoryStatus;
			if (showInventoryStatus != null && showInventoryStatus.Value)
			{
				float num = Math.Min(500f, Math.Max(300f, (float)Screen.width - 20f));
				GUI.Box(new Rect(Math.Max(10f, (float)Screen.width - num - 10f), 72f, num, 190f), _statusText);
			}
		}

		private void DrawRoleOverlay()
		{
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Expected O, but got Unknown
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			InventoryGrid val = InventoryGui.instance?.m_playerGrid;
			if (!Object.op_Implicit((Object)(object)val) || _layout == null || !ValheimContracts.TryBottomRowScreenRects(val, _layout.SpecialRow, _roleSlotRects))
			{
				return;
			}
			Color color = GUI.color;
			int depth = GUI.depth;
			try
			{
				GUI.depth = -650;
				Rect val2 = _roleSlotRects[0];
				Rect val3 = _roleSlotRects[_roleSlotRects.Length - 1];
				Rect val4 = default(Rect);
				((Rect)(ref val4))..ctor(((Rect)(ref val2)).xMin - 2f, Math.Min(((Rect)(ref val2)).yMin, ((Rect)(ref val3)).yMin) - 2f, ((Rect)(ref val3)).xMax - ((Rect)(ref val2)).xMin + 4f, Math.Max(((Rect)(ref val2)).yMax, ((Rect)(ref val3)).yMax) - Math.Min(((Rect)(ref val2)).yMin, ((Rect)(ref val3)).yMin) + 4f);
				GUI.color = new Color(0.7f, 0.43f, 0.13f, 0.48f);
				GUI.DrawTexture(new Rect(((Rect)(ref val4)).xMin, ((Rect)(ref val4)).yMin, ((Rect)(ref val4)).width, 1f), (Texture)(object)Texture2D.whiteTexture);
				GUI.DrawTexture(new Rect(((Rect)(ref val4)).xMin, ((Rect)(ref val4)).yMax - 1f, ((Rect)(ref val4)).width, 1f), (Texture)(object)Texture2D.whiteTexture);
				GUI.DrawTexture(new Rect(((Rect)(ref val4)).xMin, ((Rect)(ref val4)).yMin, 1f, ((Rect)(ref val4)).height), (Texture)(object)Texture2D.whiteTexture);
				GUI.DrawTexture(new Rect(((Rect)(ref val4)).xMax - 1f, ((Rect)(ref val4)).yMin, 1f, ((Rect)(ref val4)).height), (Texture)(object)Texture2D.whiteTexture);
				GUIStyle val5 = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)7,
					fontStyle = (FontStyle)1,
					fontSize = Math.Max(8, Math.Min(11, (int)(((Rect)(ref _roleSlotRects[0])).width / 7f))),
					clipping = (TextClipping)1,
					wordWrap = false
				};
				Rect val7 = default(Rect);
				for (int i = 0; i < _roleSlotRects.Length; i++)
				{
					Rect val6 = _roleSlotRects[i];
					GUI.color = new Color(0f, 0f, 0f, 0.7f);
					GUI.DrawTexture(new Rect(((Rect)(ref val6)).x + 1f, ((Rect)(ref val6)).y + 1f, ((Rect)(ref val6)).width - 2f, 17f), (Texture)(object)Texture2D.whiteTexture);
					((Rect)(ref val7))..ctor(((Rect)(ref val6)).x + 2f, ((Rect)(ref val6)).y + 1f, ((Rect)(ref val6)).width - 4f, 16f);
					val5.normal.textColor = new Color(0.05f, 0.03f, 0.01f, 0.92f);
					GUI.Label(new Rect(((Rect)(ref val7)).x + 1f, ((Rect)(ref val7)).y + 1f, ((Rect)(ref val7)).width, ((Rect)(ref val7)).height), RoleLabels[i], val5);
					val5.normal.textColor = new Color(1f, 0.78f, 0.34f, 0.98f);
					GUI.Label(val7, RoleLabels[i], val5);
				}
			}
			finally
			{
				GUI.color = color;
				GUI.depth = depth;
			}
		}

		private void DrawLockedSlotOverlay()
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			InventoryGrid val = InventoryGui.instance?.m_playerGrid;
			if (!Object.op_Implicit((Object)(object)val) || _layout == null || _persisted == null)
			{
				return;
			}
			Color color = GUI.color;
			int depth = GUI.depth;
			try
			{
				GUI.depth = -660;
				GUI.color = new Color(1f, 0.84f, 0.08f, 1f);
				foreach (InventorySlotCoordinate item in _persisted.LockedSlots())
				{
					if (ValheimContracts.TrySlotScreenRect(val, item.X, item.Y, out var slot))
					{
						DrawOutline(new Rect(((Rect)(ref slot)).xMin - 2f, ((Rect)(ref slot)).yMin - 2f, ((Rect)(ref slot)).width + 4f, ((Rect)(ref slot)).height + 4f), 4f);
					}
				}
			}
			finally
			{
				GUI.color = color;
				GUI.depth = depth;
			}
		}

		private static void DrawOutline(Rect rect, float thickness)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMin, ((Rect)(ref rect)).yMin, ((Rect)(ref rect)).width, thickness), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMin, ((Rect)(ref rect)).yMax - thickness, ((Rect)(ref rect)).width, thickness), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMin, ((Rect)(ref rect)).yMin, thickness, ((Rect)(ref rect)).height), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMax - thickness, ((Rect)(ref rect)).yMin, thickness, ((Rect)(ref rect)).height), (Texture)(object)Texture2D.whiteTexture);
		}

		internal void OnConfigurationChanged()
		{
			if (!_disposed)
			{
				if ((_filters = PickupFilterSet.Parse(InventoryConfig.FilteredPickupItems.Value)).Truncated)
				{
					Diagnostics.Warn("Pickup filter exceeded 128 safe unique rules; additional entries were ignored.");
				}
				ControllerBindings.Invalidate();
				ControllerChordSession.Reset();
				ConfigEntry<bool> enabled = InventoryConfig.Enabled;
				if (enabled != null && enabled.Value)
				{
					_disableCleanupPending = false;
				}
				Rebind(Player.m_localPlayer, "configuration-changed");
			}
		}

		internal void OnLocalPlayerChanged(Player player)
		{
			Rebind(player, "set-local-player");
		}

		internal void OnPlayerLoadStarted(Player player)
		{
			if (!_disposed && !((Object)(object)player != (Object)(object)_player) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				_playerLoadInProgress = true;
				_loadMetadataRefreshed = false;
			}
		}

		internal void OnPlayerLoadCompleted(Player player)
		{
			if (!_disposed && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				_playerLoadInProgress = false;
				_loadMetadataRefreshed = false;
				Rebind(player, "player-load-completed");
			}
		}

		internal void OnPlayerLoadFaulted(Player player)
		{
			if (!_disposed && !((Object)(object)player != (Object)(object)_player))
			{
				_playerLoadInProgress = false;
				_loadMetadataRefreshed = false;
				FailClosed("player.load-faulted");
			}
		}

		internal void FailClosed(string reasonCode)
		{
			_repairAllowanceDepth = 0;
			_topologyActive = false;
			_snapshot = null;
			_mode = (_batch ? InventoryAuthorityMode.BatchInert : InventoryAuthorityMode.MigrationSafeCompatibility);
			_reasonCode = BoundReason(reasonCode, "runtime.fail-closed");
			RebuildStatusOnly();
		}

		public bool TryCapture(long playerId, out InventoryTopologySnapshot snapshot, out string failureCode)
		{
			snapshot = null;
			if (_disposed)
			{
				failureCode = "provider.disposed";
				return false;
			}
			if (Thread.CurrentThread.ManagedThreadId != _mainThreadId)
			{
				failureCode = "thread.main-required";
				return false;
			}
			if (!Object.op_Implicit((Object)(object)_player) || playerId <= 0 || playerId != _player.GetPlayerID())
			{
				failureCode = "player.not-local";
				return false;
			}
			if (_layout != null && !LiveDimensionsMatch())
			{
				FailClosed("topology.runtime-dimension-changed");
				failureCode = "topology.runtime-dimension-changed";
				return false;
			}
			bool flag = IsAuthoritativeLocal(_player);
			if ((_mode == InventoryAuthorityMode.AuthoritativeLocal && !flag) || (_mode == InventoryAuthorityMode.RemoteDedicatedCompatibility && flag))
			{
				failureCode = "authority.transition-pending";
				return false;
			}
			if (_snapshot == null || !_snapshot.SerializationVerified)
			{
				RebuildCache("api-capture", verifySerialization: true);
				if (_snapshot == null || !_snapshot.SerializationVerified)
				{
					failureCode = ((_snapshot == null) ? _reasonCode : "serialization.unverified");
					return false;
				}
			}
			snapshot = _snapshot;
			failureCode = "ok";
			return true;
		}

		public bool TryIsLocked(long playerId, InventorySlotCoordinate coordinate, out bool locked, out string failureCode)
		{
			locked = false;
			if (_disposed || Thread.CurrentThread.ManagedThreadId != _mainThreadId)
			{
				failureCode = (_disposed ? "provider.disposed" : "thread.main-required");
				return false;
			}
			if (!Object.op_Implicit((Object)(object)_player) || playerId <= 0 || playerId != _player.GetPlayerID())
			{
				failureCode = "player.not-local";
				return false;
			}
			if (!CanEnforceLocks())
			{
				failureCode = "authority.local-required";
				return false;
			}
			if (_persisted == null || _layout == null || !_layout.InBounds(coordinate) || _persisted.Width != _layout.Width || _persisted.Height != _layout.Height)
			{
				failureCode = "locks.topology-unavailable";
				return false;
			}
			locked = _persisted.IsLocked(coordinate.X, coordinate.Y);
			failureCode = "ok";
			return true;
		}

		public bool TryGetProtection(object nativeItem, out ItemProtectionState state)
		{
			state = ItemProtectionState.Unknown;
			ItemData val = (ItemData)((nativeItem is ItemData) ? nativeItem : null);
			if (val == null)
			{
				TraceProtectionDecision("not-applicable.not-native-item");
				return false;
			}
			if ((InventoryConfig.Enabled != null && !InventoryConfig.Enabled.Value) || _mode == InventoryAuthorityMode.Disabled)
			{
				TraceProtectionDecision("not-applicable.feature-disabled");
				return false;
			}
			if (_disposed)
			{
				TraceProtectionDecision("unknown.provider-disposed");
				return true;
			}
			if (_inventory == null)
			{
				TraceProtectionDecision("unknown.inventory-unavailable");
				return true;
			}
			if (!Object.op_Implicit((Object)(object)_player))
			{
				TraceProtectionDecision("unknown.player-unavailable");
				return true;
			}
			if (Thread.CurrentThread.ManagedThreadId != _mainThreadId)
			{
				TraceProtectionDecision("unknown.thread-main-required");
				return true;
			}
			try
			{
				List<ItemData> allItems = _inventory.GetAllItems();
				switch (ItemProtectionDomain.Evaluate(allItems, val, 128))
				{
				case ItemProtectionDomainEvidence.NotApplicable:
					TraceProtectionDecision("not-applicable.foreign-inventory-item");
					return false;
				default:
					TraceProtectionDecision("unknown.domain-membership-indeterminate");
					return true;
				case ItemProtectionDomainEvidence.ExactCurrentMember:
				{
					if (val.m_shared == null || val.m_stack <= 0)
					{
						TraceProtectionDecision("unknown.domain-item-shape-invalid");
						return true;
					}
					if (!CanEnforceLocks())
					{
						TraceProtectionDecision("unknown.topology-or-authority-inactive");
						return true;
					}
					if (_layout == null || _persisted == null)
					{
						TraceProtectionDecision("unknown.topology-unavailable");
						return true;
					}
					if (!LiveDimensionsMatch())
					{
						TraceProtectionDecision("unknown.dimensions-live-mismatch");
						return true;
					}
					if (_persisted.Width != _layout.Width || _persisted.Height != _layout.Height)
					{
						TraceProtectionDecision("unknown.dimensions-persisted-mismatch");
						return true;
					}
					int x = val.m_gridPos.x;
					int y = val.m_gridPos.y;
					if (x < 0 || x >= _layout.Width || y < 0 || y >= _layout.Height)
					{
						TraceProtectionDecision("unknown.domain-item-coordinate-invalid");
						return true;
					}
					ulong num = 0uL;
					ulong num2 = 0uL;
					for (int i = 0; i < allItems.Count; i++)
					{
						ItemData val2 = allItems[i];
						if (val2 == null || val2.m_shared == null || val2.m_stack <= 0 || val2.m_gridPos.x < 0 || val2.m_gridPos.x >= _layout.Width || val2.m_gridPos.y < 0 || val2.m_gridPos.y >= _layout.Height)
						{
							TraceProtectionDecision("unknown.domain-member-shape-invalid");
							return true;
						}
						int num3 = val2.m_gridPos.y * _layout.Width + val2.m_gridPos.x;
						if (num3 < 64)
						{
							ulong num4 = (ulong)(1L << num3);
							if ((num & num4) != 0L)
							{
								TraceProtectionDecision("unknown.domain-duplicate-coordinate");
								return true;
							}
							num |= num4;
						}
						else
						{
							ulong num5 = (ulong)(1L << num3 - 64);
							if ((num2 & num5) != 0L)
							{
								TraceProtectionDecision("unknown.domain-duplicate-coordinate");
								return true;
							}
							num2 |= num5;
						}
					}
					if (val.m_gridPos.x != x || val.m_gridPos.y != y)
					{
						TraceProtectionDecision("unknown.reference-item-coordinate-mutated");
						return true;
					}
					List<ItemData> allItems2 = _inventory.GetAllItems();
					if (!SameItemReferences(allItems, allItems2))
					{
						TraceProtectionDecision("unknown.reference-membership-list-replaced");
						return true;
					}
					if (_inventory.GetItemAt(x, y) != val)
					{
						TraceProtectionDecision("unknown.reference-coordinate-occupant-mutated");
						return true;
					}
					if (!CanEnforceLocks())
					{
						TraceProtectionDecision("unknown.topology-transition-during-proof");
						return true;
					}
					if (!LiveDimensionsMatch())
					{
						TraceProtectionDecision("unknown.dimensions-transition-during-proof");
						return true;
					}
					state = ((_repairAllowanceDepth > 0) ? ItemProtectionState.Unlocked : ItemProtectionDomain.ClassifyExactMember(y == _layout.SpecialRow, _persisted.IsLocked(x, y)));
					return true;
				}
				}
			}
			catch (Exception exception)
			{
				state = ItemProtectionState.Unknown;
				TraceProtectionDecision("unknown.exception", exception);
				return true;
			}
		}

		public InventoryFeatureStatus Snapshot()
		{
			if (_disposed)
			{
				return new InventoryFeatureStatus(InventoryAuthorityMode.Unavailable, topologyActive: false, "provider.disposed");
			}
			if (Thread.CurrentThread.ManagedThreadId != _mainThreadId)
			{
				return new InventoryFeatureStatus(InventoryAuthorityMode.Unavailable, topologyActive: false, "thread.main-required");
			}
			if (_layout != null && !LiveDimensionsMatch())
			{
				return new InventoryFeatureStatus(InventoryAuthorityMode.MigrationSafeCompatibility, topologyActive: false, "topology.runtime-dimension-changed");
			}
			bool flag = IsAuthoritativeLocal(_player);
			if ((_mode == InventoryAuthorityMode.AuthoritativeLocal && !flag) || (_mode == InventoryAuthorityMode.RemoteDedicatedCompatibility && flag))
			{
				return new InventoryFeatureStatus(InventoryAuthorityMode.MigrationSafeCompatibility, topologyActive: false, "authority.transition-pending");
			}
			return new InventoryFeatureStatus(_mode, TopologyActive, _reasonCode);
		}

		internal bool TryFindEmptySlot(Inventory inventory, bool topFirst, out Vector2i result)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0