Decompiled source of InnangardServerLagFix v1.0.7

plugins/InnangardServerLagFix.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("InnangardServerLagFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("InnangardServerLagFix")]
[assembly: AssemblyTitle("InnangardServerLagFix")]
[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 InnangardServerLagFix
{
	internal static class BedStationManagementTuning
	{
		private sealed class PendingBedAssignment
		{
			internal object Settler;

			internal ZDOID Bed;

			internal float Until;
		}

		private const string StationIgnoreKey = "inn_lagfix_ignore_station";

		private const string StationToggleRpc = "InnLagFix_StationIgnore_104";

		private const string BedAssignRpc = "InnLagFix_BedAssign_104";

		private const string BedAssignForceRpc = "InnLagFix_BedAssignForce_104";

		private const string BedKey = "inn_bed";

		private const string BedClaimKey = "inn_claim";

		private const string BedClaimIdentityKey = "inn_claim_identity";

		private const long BedOwnerMarker = 424242L;

		private const float BedAssignWaitSeconds = 4f;

		private static ManualLogSource _log;

		private static ConfigEntry<KeyCode> _modifier;

		private static Type _settlerType;

		private static Type _restType;

		private static Type _innConfigType;

		private static Type _caretakerJobType;

		private static Type _cookJobType;

		private static Type _frithType;

		private static Type _networkRequestType;

		private static Type[] _stationTypes;

		private static FieldInfo _settlerViewField;

		private static FieldInfo _settlerInstancesField;

		private static PropertyInfo _restProperty;

		private static PropertyInfo _panelNameProperty;

		private static PropertyInfo _stableIdentityProperty;

		private static PropertyInfo _myZdoidProperty;

		private static PropertyInfo _homePositionProperty;

		private static MethodInfo _canManageMethod;

		private static MethodInfo _releaseBedMethod;

		private static MethodInfo _claimBedMethod;

		private static MethodInfo _stopSleepMethod;

		private static FieldInfo _bedSearchRadiusField;

		private static FieldInfo _caretakerTargetField;

		private static FieldInfo _cookTargetField;

		private static FieldInfo _frithInstancesField;

		private static MethodInfo _frithCoversPointMethod;

		private static MethodInfo _frithCanManageMethod;

		private static MethodInfo _networkAuthenticateMethod;

		private static MethodInfo[] _strictLeadershipMethods = Array.Empty<MethodInfo>();

		private static MethodInfo[] _staticLeadershipMethods = Array.Empty<MethodInfo>();

		private static MemberInfo[] _strictLeadershipMembers = Array.Empty<MemberInfo>();

		private static MemberInfo[] _householdMembers = Array.Empty<MemberInfo>();

		private static bool _loggedLeadershipFallback;

		private static object _selectedSettler;

		private static float _selectedUntil;

		private static readonly Dictionary<int, PendingBedAssignment> PendingBeds = new Dictionary<int, PendingBedAssignment>();

		private static readonly HashSet<int> RegisteredStationViews = new HashSet<int>();

		private static bool _loggedBedFailure;

		private static bool _loggedStationFailure;

		private static bool Active
		{
			get
			{
				if (Plugin.Enabled != null)
				{
					return Plugin.Enabled.Value;
				}
				return false;
			}
		}

		internal static void Initialize(ConfigFile config, ManualLogSource log, Harmony harmony)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			_log = log;
			_modifier = config.Bind<KeyCode>("UI", "ResidentStationManagementModifierKey", (KeyCode)306, "Modifier held with Valheim's normal Use/Interact key for Innangard management shortcuts: select a resident for bed reassignment, assign/swap a bed, or toggle an Innangard-operated production station ignored. Default LeftControl + Use. Player use of ignored stations is unchanged.");
			if ((int)_modifier.Value == 308)
			{
				_modifier.Value = (KeyCode)306;
			}
			_settlerType = AccessTools.TypeByName("Innangard.SettlerController");
			_restType = AccessTools.TypeByName("Innangard.SettlerRest");
			_innConfigType = AccessTools.TypeByName("Innangard.InnConfig");
			_caretakerJobType = AccessTools.TypeByName("Innangard.Jobs.CaretakerJob");
			_cookJobType = AccessTools.TypeByName("Innangard.Jobs.CookJob");
			_frithType = AccessTools.TypeByName("Innangard.Frithstone");
			_networkRequestType = AccessTools.TypeByName("Innangard.NetworkRequest");
			if (_settlerType == null || _restType == null)
			{
				_log.LogWarning((object)"[MANAGE] Innangard resident/bed internals not found; bed reassignment disabled.");
			}
			else
			{
				BindBedInternals();
				PatchBedManagement(harmony);
			}
			BindStationInternals();
			PatchStationManagement(harmony);
			_log.LogInfo((object)"[MANAGE] LeftControl+Use (configurable): select resident -> assign/swap bed; operated production station -> toggle ignored by Innangard.");
		}

		internal static void Tick()
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return;
			}
			if (_selectedSettler != null && Time.unscaledTime >= _selectedUntil)
			{
				_selectedSettler = null;
			}
			if (PendingBeds.Count == 0)
			{
				return;
			}
			List<int> list = null;
			foreach (KeyValuePair<int, PendingBedAssignment> pendingBed in PendingBeds)
			{
				PendingBedAssignment value = pendingBed.Value;
				if (value == null || value.Settler == null || Time.unscaledTime >= value.Until)
				{
					if (list == null)
					{
						list = new List<int>();
					}
					list.Add(pendingBed.Key);
					continue;
				}
				ZNetView val = SettlerView(value.Settler);
				if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && TryAssignBedNow(value.Settler, value.Bed, force: false))
				{
					if (list == null)
					{
						list = new List<int>();
					}
					list.Add(pendingBed.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item in list)
			{
				PendingBeds.Remove(item);
			}
		}

		internal static bool IsStationIgnored(ZNetView view)
		{
			if (!Active || (Object)(object)view == (Object)null || !view.IsValid() || !ViewBelongsToSupportedStation(view))
			{
				return false;
			}
			try
			{
				int num;
				if (view.GetZDO() != null)
				{
					num = (view.GetZDO().GetBool("inn_lagfix_ignore_station", false) ? 1 : 0);
					if (num != 0)
					{
						Plugin.ForgetStationLease(view);
					}
				}
				else
				{
					num = 0;
				}
				return (byte)num != 0;
			}
			catch
			{
				return false;
			}
		}

		private static void BindBedInternals()
		{
			_settlerViewField = AccessTools.Field(_settlerType, "_nview");
			_settlerInstancesField = AccessTools.Field(_settlerType, "Instances");
			_restProperty = AccessTools.Property(_settlerType, "Rest");
			_panelNameProperty = AccessTools.Property(_settlerType, "PanelName");
			_stableIdentityProperty = AccessTools.Property(_settlerType, "StableIdentity");
			_myZdoidProperty = AccessTools.Property(_settlerType, "MyZdoid");
			_homePositionProperty = AccessTools.Property(_settlerType, "HomePosition") ?? AccessTools.Property(_settlerType, "Home");
			_canManageMethod = AccessTools.Method(_settlerType, "CanManage", new Type[1] { typeof(long) }, (Type[])null);
			_releaseBedMethod = AccessTools.Method(_restType, "ReleaseBed", Type.EmptyTypes, (Type[])null);
			_claimBedMethod = AccessTools.Method(_restType, "ClaimBed", new Type[3]
			{
				typeof(Bed),
				typeof(float),
				typeof(string)
			}, (Type[])null);
			_stopSleepMethod = AccessTools.Method(_restType, "StopSleep", Type.EmptyTypes, (Type[])null);
			_bedSearchRadiusField = ((_innConfigType != null) ? AccessTools.Field(_innConfigType, "BedSearchRadius") : null);
		}

		private static bool TryPatch(Harmony harmony, MethodInfo original, string label, string prefixName = null, string postfixName = null)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (original == null)
			{
				return false;
			}
			try
			{
				HarmonyMethod val = (string.IsNullOrEmpty(prefixName) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(BedStationManagementTuning), prefixName, (Type[])null));
				HarmonyMethod val2 = (string.IsNullOrEmpty(postfixName) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(BedStationManagementTuning), postfixName, (Type[])null));
				harmony.Patch((MethodBase)original, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return true;
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("[MANAGE] Could not patch " + label + "; that management hook is disabled. " + ex.GetType().Name + ": " + ex.Message));
				return false;
			}
		}

		private static void PatchBedManagement(Harmony harmony)
		{
			MethodInfo methodInfo = AccessTools.Method(_settlerType, "Awake", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(_settlerType, "GetHoverText", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(_settlerType, "Interact", new Type[3]
			{
				typeof(Humanoid),
				typeof(bool),
				typeof(bool)
			}, (Type[])null);
			MethodInfo methodInfo4 = AccessTools.Method(typeof(Bed), "GetHoverText", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo5 = AccessTools.Method(typeof(Bed), "Interact", new Type[3]
			{
				typeof(Humanoid),
				typeof(bool),
				typeof(bool)
			}, (Type[])null);
			if (methodInfo != null)
			{
				TryPatch(harmony, methodInfo, "SettlerController.Awake", null, "SettlerAwakePostfix");
			}
			if (methodInfo2 != null)
			{
				TryPatch(harmony, methodInfo2, "SettlerController.GetHoverText", null, "SettlerHoverPostfix");
			}
			if (methodInfo3 != null)
			{
				TryPatch(harmony, methodInfo3, "SettlerController.Interact", "SettlerInteractPrefix");
			}
			if (methodInfo4 != null)
			{
				TryPatch(harmony, methodInfo4, "Bed.GetHoverText", null, "BedHoverPostfix");
			}
			if (methodInfo5 != null)
			{
				TryPatch(harmony, methodInfo5, "Bed.Interact", "BedInteractPrefix");
			}
			if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo5 == null || _settlerViewField == null || _restProperty == null || _releaseBedMethod == null || _claimBedMethod == null)
			{
				_log.LogWarning((object)"[MANAGE] Some bed-management bindings are missing; bed selection/reassignment may be unavailable.");
			}
		}

		private static void BindStationInternals()
		{
			_stationTypes = new Type[3]
			{
				typeof(CookingStation),
				typeof(Smelter),
				typeof(Fireplace)
			};
			_caretakerTargetField = ((_caretakerJobType != null) ? AccessTools.Field(_caretakerJobType, "_target") : null);
			_cookTargetField = ((_cookJobType != null) ? AccessTools.Field(_cookJobType, "_target") : null);
			if (_frithType != null)
			{
				_frithInstancesField = AccessTools.Field(_frithType, "Instances");
				_frithCoversPointMethod = _frithType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "CoversPoint" && m.GetParameters().Length == 2);
				_frithCanManageMethod = AccessTools.Method(_frithType, "CanManage", new Type[1] { typeof(long) }, (Type[])null);
				BindStrictLeadershipInternals();
			}
			_networkAuthenticateMethod = ((_networkRequestType != null) ? AccessTools.Method(_networkRequestType, "AuthenticatePlayer", new Type[3]
			{
				typeof(long),
				typeof(long),
				typeof(string)
			}, (Type[])null) : null);
			if (_frithInstancesField == null || _frithCoversPointMethod == null || _frithCanManageMethod == null || _networkAuthenticateMethod == null)
			{
				_log.LogWarning((object)"[STATION-IGNORE] Frith permission/auth bindings are incomplete; station toggles will fail closed rather than allow unmanaged edits.");
			}
		}

		private static void PatchStationManagement(Harmony harmony)
		{
			HashSet<MethodInfo> hashSet = new HashSet<MethodInfo>();
			HashSet<MethodInfo> hashSet2 = new HashSet<MethodInfo>();
			if (_stationTypes != null)
			{
				Type[] stationTypes = _stationTypes;
				foreach (Type type in stationTypes)
				{
					if (!(type == null))
					{
						MethodInfo methodInfo = AccessTools.Method(type, "Interact", new Type[3]
						{
							typeof(Humanoid),
							typeof(bool),
							typeof(bool)
						}, (Type[])null);
						if (methodInfo != null && hashSet.Add(methodInfo))
						{
							TryPatch(harmony, methodInfo, type.FullName + ".Interact", "StationInteractPrefix");
						}
						MethodInfo methodInfo2 = AccessTools.Method(type, "GetHoverText", Type.EmptyTypes, (Type[])null);
						if (methodInfo2 != null && hashSet2.Add(methodInfo2))
						{
							TryPatch(harmony, methodInfo2, type.FullName + ".GetHoverText", null, "StationHoverPostfix");
						}
					}
				}
			}
			Type type2 = AccessTools.TypeByName("Switch");
			if (type2 != null)
			{
				MethodInfo methodInfo3 = AccessTools.Method(type2, "Interact", new Type[3]
				{
					typeof(Humanoid),
					typeof(bool),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo3 != null && hashSet.Add(methodInfo3))
				{
					TryPatch(harmony, methodInfo3, "Switch.Interact", "StationInteractPrefix");
				}
				MethodInfo methodInfo4 = AccessTools.Method(type2, "GetHoverText", Type.EmptyTypes, (Type[])null);
				if (methodInfo4 != null && hashSet2.Add(methodInfo4))
				{
					TryPatch(harmony, methodInfo4, "Switch.GetHoverText", null, "StationHoverPostfix");
				}
			}
			MethodInfo methodInfo5 = ((_caretakerJobType != null) ? AccessTools.Method(_caretakerJobType, "TargetStillValid", (Type[])null, (Type[])null) : null);
			if (methodInfo5 != null && _caretakerTargetField != null)
			{
				TryPatch(harmony, methodInfo5, "CaretakerJob.TargetStillValid", null, "CaretakerTargetStillValidPostfix");
			}
			MethodInfo methodInfo6 = ((_cookJobType != null) ? AccessTools.Method(_cookJobType, "StillWorthDoing", Type.EmptyTypes, (Type[])null) : null);
			if (methodInfo6 != null && _cookTargetField != null)
			{
				TryPatch(harmony, methodInfo6, "CookJob.StillWorthDoing", null, "CookStillWorthDoingPostfix");
			}
			MethodInfo methodInfo7 = AccessTools.Method(typeof(ZNetView), "Awake", Type.EmptyTypes, (Type[])null);
			if (methodInfo7 != null)
			{
				TryPatch(harmony, methodInfo7, "ZNetView.Awake station RPC registration", null, "ZNetViewAwakePostfix");
			}
		}

		private static bool ModifierHeld()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (_modifier == null)
			{
				return false;
			}
			KeyCode value = _modifier.Value;
			if ((int)value != 0)
			{
				return Input.GetKey(value);
			}
			return true;
		}

		private unsafe static string ModifierLabel()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			KeyCode val = (KeyCode)((_modifier == null) ? 306 : ((int)_modifier.Value));
			if ((int)val == 0)
			{
				return "E";
			}
			string text = ((object)(*(KeyCode*)(&val))/*cast due to .constrained prefix*/).ToString();
			if (text.StartsWith("Left", StringComparison.Ordinal))
			{
				text = text.Substring(4);
			}
			else if (text.StartsWith("Right", StringComparison.Ordinal))
			{
				text = text.Substring(5);
			}
			if (string.Equals(text, "Control", StringComparison.Ordinal))
			{
				text = "Ctrl";
			}
			return text + "+E";
		}

		private static void SettlerAwakePostfix(object __instance)
		{
			RegisterSettlerRpc(__instance);
		}

		private static void RegisterSettlerRpc(object settler)
		{
			if (settler == null)
			{
				return;
			}
			ZNetView val = SettlerView(settler);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				val.Register<ZDOID>("InnLagFix_BedAssign_104", (Action<long, ZDOID>)delegate(long sender, ZDOID bed)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					HandleBedAssignmentRpc(settler, bed, force: false);
				});
				val.Register<ZDOID>("InnLagFix_BedAssignForce_104", (Action<long, ZDOID>)delegate(long sender, ZDOID bed)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					HandleBedAssignmentRpc(settler, bed, force: true);
				});
			}
			catch (Exception ex)
			{
				if (!_loggedBedFailure)
				{
					_loggedBedFailure = true;
					_log.LogWarning((object)("[BED] Could not register bed-assignment RPC: " + ex.Message));
				}
			}
		}

		private static void SettlerHoverPostfix(object __instance, ref string __result)
		{
			if (Active && __instance != null && CanLocalPlayerManage(__instance))
			{
				__result = __result + "\n[<color=yellow><b>" + ModifierLabel() + "</b></color>] Reassign Bed";
			}
		}

		private static bool SettlerInteractPrefix(object __instance, Humanoid __0, bool __1, ref bool __result)
		{
			if (!Active || __1 || !ModifierHeld() || __instance == null || !IsLocalPlayer(__0))
			{
				return true;
			}
			if (!CanLocalPlayerManage(__instance))
			{
				return true;
			}
			_selectedSettler = __instance;
			_selectedUntil = Time.unscaledTime + 60f;
			Say("Selected " + PanelName(__instance) + " for bed assignment. " + ModifierLabel() + " a bed to assign or swap it.");
			__result = true;
			return false;
		}

		private static void BedHoverPostfix(Bed __instance, ref string __result)
		{
			object obj = ValidSelectedSettler();
			if (Active && obj != null && !((Object)(object)__instance == (Object)null))
			{
				ZNetView val = ViewOf((Component)(object)__instance);
				if (!((Object)(object)val == (Object)null) && val.IsValid() && BedEligibleForInnangard(__instance, val))
				{
					object obj2 = ResidentClaiming(val.GetZDO());
					string text = ((obj2 != null && obj2 != obj) ? ("Swap " + PanelName(obj) + " with " + PanelName(obj2)) : ("Assign to " + PanelName(obj)));
					__result = __result + "\n[<color=yellow><b>" + ModifierLabel() + "</b></color>] " + text;
				}
			}
		}

		private static bool BedInteractPrefix(Bed __instance, Humanoid __0, bool __1, ref bool __result)
		{
			object obj = ValidSelectedSettler();
			if (!Active || obj == null || __1 || !ModifierHeld() || !IsLocalPlayer(__0) || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			ZNetView val = ViewOf((Component)(object)__instance);
			if ((Object)(object)val == (Object)null || !val.IsValid() || !BedEligibleForInnangard(__instance, val))
			{
				Say("That bed cannot be assigned to an Innangard resident.");
				__result = true;
				return false;
			}
			if (!WithinBedRange(obj, __instance))
			{
				Say("That bed is outside " + PanelName(obj) + "'s Innangard bed-search range.");
				__result = true;
				return false;
			}
			RequestBedAssignment(obj, __instance, val);
			_selectedSettler = null;
			__result = true;
			return false;
		}

		private static void RequestBedAssignment(object selected, Bed targetBed, ZNetView targetView)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			ZNetView val = SettlerView(selected);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				Say("Could not find that resident's network view.");
				return;
			}
			ZDO zDO = val.GetZDO();
			ZDO zDO2 = targetView.GetZDO();
			if (zDO == null || zDO2 == null)
			{
				return;
			}
			ZDOID uid = zDO2.m_uid;
			ZDOID zDOID = zDO.GetZDOID("inn_bed");
			if (zDOID == uid)
			{
				Say(PanelName(selected) + " already has that bed.");
				return;
			}
			object obj = ResidentClaiming(zDO2);
			if (obj != null && obj != selected)
			{
				if (zDOID == ZDOID.None)
				{
					Say("That bed belongs to " + PanelName(obj) + ", and " + PanelName(selected) + " has no bed to swap with.");
					return;
				}
				Bed val2 = ResolveBed(zDOID);
				if ((Object)(object)val2 == (Object)null || !WithinBedRange(obj, val2))
				{
					Say("Cannot swap those beds because the current bed is unavailable to " + PanelName(obj) + ".");
					return;
				}
				ZNetView val3 = SettlerView(obj);
				if ((Object)(object)val3 == (Object)null || !val3.IsValid())
				{
					Say("The resident currently assigned to that bed is not available to swap.");
					return;
				}
				val3.InvokeRPC("InnLagFix_BedAssignForce_104", new object[1] { zDOID });
				val.InvokeRPC("InnLagFix_BedAssign_104", new object[1] { uid });
				Say("Swapping beds: " + PanelName(selected) + " <-> " + PanelName(obj) + ".");
			}
			else if (HasForeignBedClaim(zDO2, selected))
			{
				Say("That bed has an Innangard claim whose resident is not currently loaded; it was left unchanged.");
			}
			else
			{
				val.InvokeRPC("InnLagFix_BedAssign_104", new object[1] { uid });
				Say("Reassigning " + PanelName(selected) + " to that bed.");
			}
		}

		private static void HandleBedAssignmentRpc(object settler, ZDOID desiredBed, bool force)
		{
			//IL_000a: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || settler == null || desiredBed == ZDOID.None)
			{
				return;
			}
			ZNetView val = SettlerView(settler);
			if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
			{
				return;
			}
			if (force || TryAssignBedNow(settler, desiredBed, force: false))
			{
				if (force)
				{
					TryAssignBedNow(settler, desiredBed, force: true);
				}
				return;
			}
			object obj = ((settler is Object) ? settler : null);
			int key = ((obj != null) ? ((Object)obj).GetInstanceID() : settler.GetHashCode());
			PendingBeds[key] = new PendingBedAssignment
			{
				Settler = settler,
				Bed = desiredBed,
				Until = Time.unscaledTime + 4f
			};
		}

		private unsafe static bool TryAssignBedNow(object settler, ZDOID desiredBed, bool force)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			Bed val = ResolveBed(desiredBed);
			if (settler == null || (Object)(object)val == (Object)null)
			{
				return false;
			}
			ZNetView val2 = ViewOf((Component)(object)val);
			if ((Object)(object)val2 == (Object)null || !val2.IsValid() || !BedEligibleForInnangard(val, val2) || !WithinBedRange(settler, val))
			{
				return false;
			}
			ZDO zDO = val2.GetZDO();
			if (!force && HasForeignBedClaim(zDO, settler))
			{
				return false;
			}
			object obj = _restProperty?.GetValue(settler, null);
			if (obj == null)
			{
				return false;
			}
			try
			{
				_stopSleepMethod?.Invoke(obj, null);
				_releaseBedMethod.Invoke(obj, null);
				float num = Distance(HomePosition(settler), ((Component)val).transform.position);
				_claimBedMethod.Invoke(obj, new object[3] { val, num, "was reassigned to a bed" });
				ManualLogSource log = _log;
				string[] obj2 = new string[6]
				{
					"[BED] ",
					PanelName(settler),
					" assigned bed ",
					null,
					null,
					null
				};
				ZDOID val3 = desiredBed;
				obj2[3] = ((object)(*(ZDOID*)(&val3))/*cast due to .constrained prefix*/).ToString();
				obj2[4] = (force ? " (swap leg)" : string.Empty);
				obj2[5] = ".";
				log.LogInfo((object)string.Concat(obj2));
				return true;
			}
			catch (Exception ex)
			{
				if (!_loggedBedFailure)
				{
					_loggedBedFailure = true;
					_log.LogWarning((object)("[BED] Bed reassignment failed once; stock bed handling continues. " + ex.GetType().Name + ": " + ex.Message));
				}
				return false;
			}
		}

		private static object ValidSelectedSettler()
		{
			if (_selectedSettler == null || Time.unscaledTime >= _selectedUntil)
			{
				_selectedSettler = null;
				return null;
			}
			object selectedSettler = _selectedSettler;
			Component val = (Component)((selectedSettler is Component) ? selectedSettler : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null || !val.gameObject.activeInHierarchy)
			{
				_selectedSettler = null;
				return null;
			}
			return _selectedSettler;
		}

		private static bool CanLocalPlayerManage(object settler)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (settler == null || (Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			long playerID = localPlayer.GetPlayerID();
			try
			{
				if (_canManageMethod != null)
				{
					object obj = _canManageMethod.Invoke(settler, new object[1] { playerID });
					if (!(obj is bool) || !(bool)obj)
					{
						return false;
					}
				}
			}
			catch
			{
				return false;
			}
			return CanRequesterLeadFrith(FindManagingFrith(HomePosition(settler)), playerID);
		}

		private static bool BedEligibleForInnangard(Bed bed, ZNetView view)
		{
			if ((Object)(object)bed == (Object)null || (Object)(object)view == (Object)null || !view.IsValid())
			{
				return false;
			}
			Piece val = ((Component)bed).GetComponent<Piece>() ?? ((Component)bed).GetComponentInParent<Piece>();
			if ((Object)(object)val != (Object)null && !val.IsPlacedByPlayer())
			{
				return false;
			}
			ZDO zDO = view.GetZDO();
			if (zDO == null)
			{
				return false;
			}
			long num = zDO.GetLong(ZDOVars.s_owner, 0L);
			if (num != 0L)
			{
				return num == 424242;
			}
			return true;
		}

		private static bool WithinBedRange(object settler, Bed bed)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (settler == null || (Object)(object)bed == (Object)null)
			{
				return false;
			}
			float num = 30f;
			try
			{
				if (_bedSearchRadiusField?.GetValue(null) is ConfigEntry<float> val)
				{
					num = Mathf.Max(1f, val.Value);
				}
			}
			catch
			{
			}
			return Distance(HomePosition(settler), ((Component)bed).transform.position) <= num;
		}

		private static object ResidentClaiming(ZDO bedZdo)
		{
			//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)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if (bedZdo == null || _settlerInstancesField == null)
			{
				return null;
			}
			string text = bedZdo.GetString("inn_claim_identity", string.Empty);
			ZDOID zDOID = bedZdo.GetZDOID("inn_claim");
			if (string.IsNullOrEmpty(text) && zDOID == ZDOID.None)
			{
				return null;
			}
			if (!(_settlerInstancesField.GetValue(null) is IEnumerable enumerable))
			{
				return null;
			}
			foreach (object item in enumerable)
			{
				if (item == null)
				{
					continue;
				}
				if (!string.IsNullOrEmpty(text))
				{
					if (_stableIdentityProperty?.GetValue(item, null) as string == text)
					{
						return item;
					}
				}
				else if (_myZdoidProperty != null)
				{
					object value = _myZdoidProperty.GetValue(item, null);
					if (value is ZDOID && (ZDOID)value == zDOID)
					{
						return item;
					}
				}
			}
			return null;
		}

		private static bool HasForeignBedClaim(ZDO bedZdo, object settler)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			if (bedZdo == null)
			{
				return true;
			}
			string text = bedZdo.GetString("inn_claim_identity", string.Empty);
			if (!string.IsNullOrEmpty(text))
			{
				string text2 = _stableIdentityProperty?.GetValue(settler, null) as string;
				if (!string.IsNullOrEmpty(text2))
				{
					return text != text2;
				}
				return true;
			}
			ZDOID zDOID = bedZdo.GetZDOID("inn_claim");
			if (zDOID == ZDOID.None)
			{
				return false;
			}
			if (_myZdoidProperty == null)
			{
				return true;
			}
			object value = _myZdoidProperty.GetValue(settler, null);
			if (value is ZDOID)
			{
				return (ZDOID)value != zDOID;
			}
			return true;
		}

		private static Bed ResolveBed(ZDOID id)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (id == ZDOID.None || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			GameObject val = ZNetScene.instance.FindInstance(id);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			return val.GetComponent<Bed>() ?? val.GetComponentInChildren<Bed>(true);
		}

		private static ZNetView SettlerView(object settler)
		{
			if (settler == null)
			{
				return null;
			}
			try
			{
				object? obj = _settlerViewField?.GetValue(settler);
				ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			catch
			{
			}
			Component val2 = (Component)((settler is Component) ? settler : null);
			if (!((Object)(object)val2 != (Object)null))
			{
				return null;
			}
			return val2.GetComponent<ZNetView>() ?? val2.GetComponentInParent<ZNetView>();
		}

		private static string PanelName(object settler)
		{
			try
			{
				string text = _panelNameProperty?.GetValue(settler, null) as string;
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			catch
			{
			}
			object obj2 = ((settler is Component) ? settler : null);
			object obj3;
			if (obj2 == null)
			{
				obj3 = null;
			}
			else
			{
				GameObject gameObject = ((Component)obj2).gameObject;
				obj3 = ((gameObject != null) ? ((Object)gameObject).name : null);
			}
			if (obj3 == null)
			{
				obj3 = "resident";
			}
			return (string)obj3;
		}

		private static Vector3 HomePosition(object settler)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				object obj = _homePositionProperty?.GetValue(settler, null);
				if (obj is Vector3)
				{
					return (Vector3)obj;
				}
			}
			catch
			{
			}
			object obj3 = ((settler is Component) ? settler : null);
			if (obj3 == null)
			{
				return Vector3.zero;
			}
			return ((Component)obj3).transform.position;
		}

		private static float Distance(Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			float num = a.x - b.x;
			float num2 = a.z - b.z;
			return Mathf.Sqrt(num * num + num2 * num2);
		}

		private static bool IsLocalPlayer(Humanoid user)
		{
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val != (Object)null)
			{
				return (Object)(object)val == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

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

		private static void ZNetViewAwakePostfix(ZNetView __instance)
		{
			RegisterStationRpc(__instance);
		}

		private static void RegisterStationRpc(ZNetView view)
		{
			if ((Object)(object)view == (Object)null || !ViewBelongsToSupportedStation(view))
			{
				return;
			}
			int instanceID = ((Object)view).GetInstanceID();
			if (!RegisteredStationViews.Add(instanceID))
			{
				return;
			}
			try
			{
				view.Register<long, bool>("InnLagFix_StationIgnore_104", (Action<long, long, bool>)delegate(long sender, long requesterId, bool ignored)
				{
					ApplyStationToggle(view, sender, requesterId, ignored);
				});
			}
			catch (Exception ex)
			{
				RegisteredStationViews.Remove(instanceID);
				if (!_loggedStationFailure)
				{
					_loggedStationFailure = true;
					_log.LogWarning((object)("[STATION-IGNORE] Could not register station toggle RPC: " + ex.Message));
				}
			}
		}

		private static bool StationInteractPrefix(object __instance, Humanoid __0, bool __1, ref bool __result)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || __1 || !ModifierHeld() || !IsLocalPlayer(__0))
			{
				return true;
			}
			Component val = (Component)((__instance is Component) ? __instance : null);
			ZNetView val2 = ViewOf(val);
			if ((Object)(object)val2 == (Object)null || !val2.IsValid() || !ViewBelongsToSupportedStation(val2))
			{
				return true;
			}
			if (!PrivateArea.CheckAccess(val.transform.position, 0f, false, false))
			{
				return true;
			}
			if (!CanLocalPlayerManageStation(val2))
			{
				return true;
			}
			bool flag = !IsStationIgnored(val2);
			RequestStationIgnored(val2, flag);
			Say(StationName(val) + (flag ? " will now be ignored by Innangard." : " is available to Innangard again."));
			__result = true;
			return false;
		}

		private static void StationHoverPostfix(object __instance, ref string __result)
		{
			if (!Active)
			{
				return;
			}
			ZNetView val = ViewOf((Component)((__instance is Component) ? __instance : null));
			if (!((Object)(object)val == (Object)null) && val.IsValid() && ViewBelongsToSupportedStation(val) && CanLocalPlayerManageStation(val))
			{
				bool flag = IsStationIgnored(val);
				__result = __result + "\n[<color=yellow><b>" + ModifierLabel() + "</b></color>] " + (flag ? "Use Station" : "Ignore Station");
				if (flag)
				{
					__result += "\n<color=#d99a76>Ignored by Innangard</color>";
				}
			}
		}

		private static void ApplyStationToggle(ZNetView view, long sender, long requesterId, bool ignored)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)view == (Object)null || !view.IsValid() || !view.IsOwner())
			{
				return;
			}
			try
			{
				if (!AuthenticateRequester(sender, requesterId) || !CanRequesterManageStation(view, requesterId))
				{
					_log.LogWarning((object)("[STATION-IGNORE] Rejected unmanaged station toggle for requester=" + requesterId + "."));
					return;
				}
				ZDO zDO = view.GetZDO();
				if (zDO != null)
				{
					zDO.Set("inn_lagfix_ignore_station", ignored);
					if (ignored)
					{
						zDO.Set("inn_station_claim", ZDOID.None);
						zDO.Set("inn_station_claim_until", 0L);
					}
					Plugin.ForgetStationLease(view);
					_log.LogInfo((object)("[STATION-IGNORE] " + StationName(view) + " ignored=" + ignored + " by " + requesterId + "."));
				}
			}
			catch (Exception ex)
			{
				if (!_loggedStationFailure)
				{
					_loggedStationFailure = true;
					_log.LogWarning((object)("[STATION-IGNORE] Toggle failed once: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		private static void CaretakerTargetStillValidPostfix(object __instance, ref bool __result)
		{
			if (Active && __result && __instance != null && !(_caretakerTargetField == null))
			{
				object? value = _caretakerTargetField.GetValue(__instance);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if ((Object)(object)val != (Object)null && IsStationIgnored(ViewOf((Component)(object)val.transform)))
				{
					__result = false;
				}
			}
		}

		private static void CookStillWorthDoingPostfix(object __instance, ref bool __result)
		{
			if (Active && __result && __instance != null && !(_cookTargetField == null))
			{
				object? value = _cookTargetField.GetValue(__instance);
				Component val = (Component)((value is Component) ? value : null);
				if ((Object)(object)val != (Object)null && IsStationIgnored(ViewOf(val)))
				{
					__result = false;
				}
			}
		}

		internal static bool IsSupportedStation(ZNetView view)
		{
			return ViewBelongsToSupportedStation(view);
		}

		internal static ZNetView GetSupportedStationView(Component component)
		{
			ZNetView val = ViewOf(component);
			if (!ViewBelongsToSupportedStation(val))
			{
				return null;
			}
			return val;
		}

		internal static Component GetSupportedStationComponent(ZNetView view)
		{
			if ((Object)(object)view == (Object)null || !ViewBelongsToSupportedStation(view) || _stationTypes == null)
			{
				return null;
			}
			Type[] stationTypes = _stationTypes;
			foreach (Type type in stationTypes)
			{
				if (!(type == null))
				{
					Component component = ((Component)view).GetComponent(type);
					if ((Object)(object)component != (Object)null)
					{
						return component;
					}
					Component componentInParent = ((Component)view).GetComponentInParent(type);
					if ((Object)(object)componentInParent != (Object)null)
					{
						return componentInParent;
					}
					Component componentInChildren = ((Component)view).GetComponentInChildren(type, true);
					if ((Object)(object)componentInChildren != (Object)null)
					{
						return componentInChildren;
					}
				}
			}
			return null;
		}

		internal static void RequestStationIgnored(ZNetView view, bool ignored)
		{
			if (Active && !((Object)(object)view == (Object)null) && view.IsValid() && ViewBelongsToSupportedStation(view))
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && CanLocalPlayerManageStation(view))
				{
					RegisterStationRpc(view);
					view.InvokeRPC("InnLagFix_StationIgnore_104", new object[2]
					{
						localPlayer.GetPlayerID(),
						ignored
					});
				}
			}
		}

		internal static bool CanLocalPlayerManageStation(ZNetView view)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return CanRequesterManageStation(view, localPlayer.GetPlayerID());
			}
			return false;
		}

		private static bool AuthenticateRequester(long sender, long requesterId)
		{
			if (_networkAuthenticateMethod == null || requesterId == 0L)
			{
				return false;
			}
			try
			{
				object obj = _networkAuthenticateMethod.Invoke(null, new object[3] { sender, requesterId, "station ignore toggle" });
				return obj is bool && (bool)obj;
			}
			catch
			{
				return false;
			}
		}

		private static bool CanRequesterManageStation(ZNetView view, long requesterId)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (requesterId == 0L || (Object)(object)view == (Object)null || !view.IsValid())
			{
				return false;
			}
			Component supportedStationComponent = GetSupportedStationComponent(view);
			if ((Object)(object)supportedStationComponent == (Object)null)
			{
				return false;
			}
			Piece val = supportedStationComponent.GetComponent<Piece>() ?? supportedStationComponent.GetComponentInParent<Piece>();
			if ((Object)(object)val == (Object)null || !val.IsPlacedByPlayer())
			{
				return false;
			}
			object obj = FindManagingFrith(supportedStationComponent.transform.position);
			if (obj == null || _frithCanManageMethod == null)
			{
				return false;
			}
			try
			{
				object obj2 = _frithCanManageMethod.Invoke(obj, new object[1] { requesterId });
				if (!(obj2 is bool) || !(bool)obj2)
				{
					return false;
				}
				return CanRequesterLeadFrith(obj, requesterId);
			}
			catch
			{
				return false;
			}
		}

		internal static bool CanLocalPlayerStrictlyManageFrith(object frith)
		{
			Player localPlayer = Player.m_localPlayer;
			if (frith == null || (Object)(object)localPlayer == (Object)null || _frithCanManageMethod == null)
			{
				return false;
			}
			long playerID = localPlayer.GetPlayerID();
			try
			{
				object obj = _frithCanManageMethod.Invoke(frith, new object[1] { playerID });
				return obj is bool && (bool)obj && CanRequesterLeadFrith(frith, playerID);
			}
			catch
			{
				return false;
			}
		}

		private static void BindStrictLeadershipInternals()
		{
			if (_frithType == null)
			{
				return;
			}
			_strictLeadershipMethods = (from m in _frithType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where m.ReturnType == typeof(bool) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(long) && m.Name != "CanManage" && LeadershipName(m.Name)
				select m).ToArray();
			List<MethodInfo> list = new List<MethodInfo>();
			try
			{
				Type[] types = _frithType.Assembly.GetTypes();
				foreach (Type type in types)
				{
					if (type == null || type.Namespace == null || !type.Namespace.StartsWith("Innangard", StringComparison.Ordinal))
					{
						continue;
					}
					MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo methodInfo in methods)
					{
						if (!(methodInfo.ReturnType != typeof(bool)) && LeadershipName(methodInfo.Name))
						{
							ParameterInfo[] parameters = methodInfo.GetParameters();
							if (parameters.Length == 2 && parameters.Any((ParameterInfo p) => p.ParameterType == typeof(long)) && parameters.Any((ParameterInfo p) => p.ParameterType == _frithType || p.ParameterType == typeof(ZDO) || p.ParameterType == typeof(ZNetView)))
							{
								list.Add(methodInfo);
							}
						}
					}
				}
			}
			catch (ReflectionTypeLoadException ex)
			{
				Type[] types = ex.Types ?? Array.Empty<Type>();
				foreach (Type type2 in types)
				{
					if (type2 == null || type2.Namespace == null || !type2.Namespace.StartsWith("Innangard", StringComparison.Ordinal))
					{
						continue;
					}
					MethodInfo[] methods = type2.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo methodInfo2 in methods)
					{
						ParameterInfo[] parameters2 = methodInfo2.GetParameters();
						if (methodInfo2.ReturnType == typeof(bool) && LeadershipName(methodInfo2.Name) && parameters2.Length == 2 && parameters2.Any((ParameterInfo p) => p.ParameterType == typeof(long)) && parameters2.Any((ParameterInfo p) => p.ParameterType == _frithType || p.ParameterType == typeof(ZDO) || p.ParameterType == typeof(ZNetView)))
						{
							list.Add(methodInfo2);
						}
					}
				}
			}
			_staticLeadershipMethods = list.Distinct().ToArray();
			List<MemberInfo> list2 = new List<MemberInfo>();
			List<MemberInfo> list3 = new List<MemberInfo>();
			FieldInfo[] fields = _frithType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (LeadershipName(fieldInfo.Name))
				{
					list2.Add(fieldInfo);
				}
				else if (HouseholdName(fieldInfo.Name) || HouseholdName(fieldInfo.FieldType.Name))
				{
					list3.Add(fieldInfo);
				}
			}
			PropertyInfo[] properties = _frithType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (propertyInfo.GetIndexParameters().Length == 0 && !(propertyInfo.GetGetMethod(nonPublic: true) == null))
				{
					if (LeadershipName(propertyInfo.Name))
					{
						list2.Add(propertyInfo);
					}
					else if (HouseholdName(propertyInfo.Name) || HouseholdName(propertyInfo.PropertyType.Name))
					{
						list3.Add(propertyInfo);
					}
				}
			}
			_strictLeadershipMembers = list2.ToArray();
			_householdMembers = list3.ToArray();
			string text = ((_strictLeadershipMethods.Length == 0) ? "none" : string.Join(", ", _strictLeadershipMethods.Select((MethodInfo m) => m.Name).Distinct().ToArray()));
			string text2 = ((_staticLeadershipMethods.Length == 0) ? "none" : string.Join(", ", _staticLeadershipMethods.Select((MethodInfo m) => m.DeclaringType.Name + "." + m.Name).Distinct().ToArray()));
			string text3 = ((_strictLeadershipMembers.Length == 0) ? "none" : string.Join(", ", _strictLeadershipMembers.Select((MemberInfo m) => m.Name).Distinct().ToArray()));
			_log.LogInfo((object)("[MANAGE-PERM] Strict Household leadership binding: methods=" + text + "; static=" + text2 + "; members=" + text3 + ". Founder fallback uses the Frithstone Piece creator."));
		}

		private static bool LeadershipName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			string text = name.ToLowerInvariant();
			if (!text.Contains("leader") && !text.Contains("founder"))
			{
				return text.Contains("creator");
			}
			return true;
		}

		private static bool HouseholdName(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				return name.IndexOf("household", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static bool CanRequesterLeadFrith(object frith, long requesterId)
		{
			if (frith == null || requesterId == 0L)
			{
				return false;
			}
			Component val = (Component)((frith is Component) ? frith : null);
			if ((Object)(object)val != (Object)null)
			{
				Piece val2 = val.GetComponent<Piece>() ?? val.GetComponentInParent<Piece>();
				if ((Object)(object)val2 != (Object)null && val2.GetCreator() == requesterId)
				{
					return true;
				}
			}
			MethodInfo[] strictLeadershipMethods = _strictLeadershipMethods;
			foreach (MethodInfo methodInfo in strictLeadershipMethods)
			{
				try
				{
					object obj = methodInfo.Invoke(frith, new object[1] { requesterId });
					if (obj is bool && (bool)obj)
					{
						return true;
					}
				}
				catch
				{
				}
			}
			strictLeadershipMethods = _staticLeadershipMethods;
			foreach (MethodInfo methodInfo2 in strictLeadershipMethods)
			{
				try
				{
					object[] array = BuildStaticLeadershipArgs(methodInfo2, frith, requesterId);
					if (array != null)
					{
						object obj3 = methodInfo2.Invoke(null, array);
						if (obj3 is bool && (bool)obj3)
						{
							return true;
						}
					}
				}
				catch
				{
				}
			}
			MemberInfo[] strictLeadershipMembers = _strictLeadershipMembers;
			foreach (MemberInfo member in strictLeadershipMembers)
			{
				try
				{
					if (ValueContainsPlayerId(ReadMember(frith, member), requesterId, 0))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			strictLeadershipMembers = _householdMembers;
			foreach (MemberInfo member2 in strictLeadershipMembers)
			{
				try
				{
					if (HouseholdContainsLeader(ReadMember(frith, member2), requesterId, 0))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			if (!_loggedLeadershipFallback)
			{
				_loggedLeadershipFallback = true;
				_log.LogWarning((object)"[MANAGE-PERM] No Household Leader match was found for a non-founder request; management denied (fail closed). SharedAccess/ward membership alone is never enough.");
			}
			return false;
		}

		private static object[] BuildStaticLeadershipArgs(MethodInfo method, object frith, long requesterId)
		{
			if (method == null || frith == null)
			{
				return null;
			}
			ParameterInfo[] parameters = method.GetParameters();
			if (parameters.Length != 2)
			{
				return null;
			}
			Component val = (Component)((frith is Component) ? frith : null);
			ZNetView val2 = (((Object)(object)val != (Object)null) ? (val.GetComponent<ZNetView>() ?? val.GetComponentInParent<ZNetView>()) : null);
			ZDO val3 = (((Object)(object)val2 != (Object)null && val2.IsValid()) ? val2.GetZDO() : null);
			object[] array = new object[2];
			for (int i = 0; i < parameters.Length; i++)
			{
				Type parameterType = parameters[i].ParameterType;
				if (parameterType == typeof(long))
				{
					array[i] = requesterId;
					continue;
				}
				if (parameterType.IsInstanceOfType(frith))
				{
					array[i] = frith;
					continue;
				}
				if (parameterType == typeof(ZNetView))
				{
					array[i] = val2;
					continue;
				}
				if (parameterType == typeof(ZDO))
				{
					array[i] = val3;
					continue;
				}
				return null;
			}
			return array;
		}

		private static object ReadMember(object instance, MemberInfo member)
		{
			FieldInfo fieldInfo = member as FieldInfo;
			if (fieldInfo != null)
			{
				return fieldInfo.GetValue(instance);
			}
			PropertyInfo propertyInfo = member as PropertyInfo;
			if (!(propertyInfo != null))
			{
				return null;
			}
			return propertyInfo.GetValue(instance, null);
		}

		private static bool HouseholdContainsLeader(object household, long requesterId, int depth)
		{
			if (household == null || depth > 2)
			{
				return false;
			}
			IEnumerable enumerable = household as IEnumerable;
			if (!(household is string) && enumerable != null)
			{
				foreach (object item in enumerable)
				{
					if (HouseholdEntryIsLeader(item, requesterId))
					{
						return true;
					}
				}
			}
			Type type = household.GetType();
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				object value = fieldInfo.GetValue(household);
				if (LeadershipName(fieldInfo.Name) && ValueContainsPlayerId(value, requesterId, 0))
				{
					return true;
				}
				if (HouseholdName(fieldInfo.Name) && value != household && HouseholdContainsLeader(value, requesterId, depth + 1))
				{
					return true;
				}
			}
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (propertyInfo.GetIndexParameters().Length != 0 || propertyInfo.GetGetMethod(nonPublic: true) == null)
				{
					continue;
				}
				try
				{
					object value2 = propertyInfo.GetValue(household, null);
					if (LeadershipName(propertyInfo.Name) && ValueContainsPlayerId(value2, requesterId, 0))
					{
						return true;
					}
					if (HouseholdName(propertyInfo.Name) && value2 != household && HouseholdContainsLeader(value2, requesterId, depth + 1))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return HouseholdEntryIsLeader(household, requesterId);
		}

		private static bool HouseholdEntryIsLeader(object entry, long requesterId)
		{
			if (entry == null)
			{
				return false;
			}
			Type type = entry.GetType();
			bool flag = false;
			bool flag2 = false;
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				object value;
				try
				{
					value = fieldInfo.GetValue(entry);
				}
				catch
				{
					continue;
				}
				string text = fieldInfo.Name.ToLowerInvariant();
				if (LeadershipName(text))
				{
					if (value is bool)
					{
						flag |= (bool)value;
					}
					else if (ValueContainsPlayerId(value, requesterId, 0))
					{
						return true;
					}
				}
				if (text.Contains("player") || text.Contains("id"))
				{
					flag2 |= ValueContainsPlayerId(value, requesterId, 0);
				}
			}
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (propertyInfo.GetIndexParameters().Length != 0 || propertyInfo.GetGetMethod(nonPublic: true) == null)
				{
					continue;
				}
				object value2;
				try
				{
					value2 = propertyInfo.GetValue(entry, null);
				}
				catch
				{
					continue;
				}
				string text2 = propertyInfo.Name.ToLowerInvariant();
				if (LeadershipName(text2))
				{
					if (value2 is bool)
					{
						flag |= (bool)value2;
					}
					else if (ValueContainsPlayerId(value2, requesterId, 0))
					{
						return true;
					}
				}
				if (text2.Contains("player") || text2.Contains("id"))
				{
					flag2 |= ValueContainsPlayerId(value2, requesterId, 0);
				}
			}
			return flag && flag2;
		}

		private static bool ValueContainsPlayerId(object value, long requesterId, int depth)
		{
			if (value == null || depth > 2)
			{
				return false;
			}
			if (value is long)
			{
				return (long)value == requesterId;
			}
			if (value is int)
			{
				return (int)value == requesterId;
			}
			if (value is ulong)
			{
				return (ulong)value == (ulong)requesterId;
			}
			if (value is string text)
			{
				if (long.TryParse(text.Trim(), out var result))
				{
					return result == requesterId;
				}
				char[] separator = new char[9] { ',', ';', '|', ' ', '\t', '\r', '\n', ':', '=' };
				string[] array = text.Split(separator, StringSplitOptions.RemoveEmptyEntries);
				for (int i = 0; i < array.Length; i++)
				{
					if (long.TryParse(array[i], out result) && result == requesterId)
					{
						return true;
					}
				}
				return false;
			}
			if (value is IEnumerable enumerable)
			{
				foreach (object item in enumerable)
				{
					if (ValueContainsPlayerId(item, requesterId, depth + 1))
					{
						return true;
					}
				}
				return false;
			}
			Type type = value.GetType();
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				string text2 = fieldInfo.Name.ToLowerInvariant();
				if ((text2.Contains("player") || text2.Contains("id") || LeadershipName(text2)) && ValueContainsPlayerId(fieldInfo.GetValue(value), requesterId, depth + 1))
				{
					return true;
				}
			}
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (propertyInfo.GetIndexParameters().Length != 0 || propertyInfo.GetGetMethod(nonPublic: true) == null)
				{
					continue;
				}
				string text3 = propertyInfo.Name.ToLowerInvariant();
				if (!text3.Contains("player") && !text3.Contains("id") && !LeadershipName(text3))
				{
					continue;
				}
				try
				{
					if (ValueContainsPlayerId(propertyInfo.GetValue(value, null), requesterId, depth + 1))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static object FindManagingFrith(Vector3 position)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (_frithInstancesField == null || _frithCoversPointMethod == null)
			{
				return null;
			}
			if (!(_frithInstancesField.GetValue(null) is IEnumerable enumerable))
			{
				return null;
			}
			object result = null;
			float num = float.MaxValue;
			foreach (object item in enumerable)
			{
				Component val = (Component)((item is Component) ? item : null);
				if ((Object)(object)val == (Object)null || !val.gameObject.activeInHierarchy)
				{
					continue;
				}
				try
				{
					object obj = _frithCoversPointMethod.Invoke(item, new object[2] { position, 18f });
					if (!(obj is bool) || !(bool)obj)
					{
						continue;
					}
					goto IL_00b3;
				}
				catch
				{
				}
				continue;
				IL_00b3:
				float num2 = Vector3.Distance(val.transform.position, position);
				if (num2 < num)
				{
					num = num2;
					result = item;
				}
			}
			return result;
		}

		private static bool ViewBelongsToSupportedStation(ZNetView view)
		{
			if ((Object)(object)view == (Object)null || _stationTypes == null)
			{
				return false;
			}
			Type[] stationTypes = _stationTypes;
			foreach (Type type in stationTypes)
			{
				if (!(type == null) && ((Object)(object)((Component)view).GetComponent(type) != (Object)null || (Object)(object)((Component)view).GetComponentInParent(type) != (Object)null || (Object)(object)((Component)view).GetComponentInChildren(type, true) != (Object)null))
				{
					return true;
				}
			}
			return false;
		}

		private static ZNetView ViewOf(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			return component.GetComponent<ZNetView>() ?? component.GetComponentInParent<ZNetView>() ?? component.GetComponentInChildren<ZNetView>(true);
		}

		private static string StationName(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return "Station";
			}
			Piece val = component.GetComponent<Piece>() ?? component.GetComponentInParent<Piece>();
			if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(val.m_name))
			{
				return val.m_name;
			}
			if (!((Object)(object)component.gameObject != (Object)null))
			{
				return "Station";
			}
			return ((Object)component.gameObject).name;
		}

		private static string StationName(ZNetView view)
		{
			return StationName((Component)(object)view);
		}
	}
	internal static class BetterOrganisationIntegration
	{
		private static ConfigEntry<bool> _enabled;

		private static Harmony _harmony;

		private static bool _present;

		private static bool _rulesInstalled;

		private static bool _uiInstalled;

		private static float _nextRefresh;

		internal static ManualLogSource Log { get; private set; }

		internal static bool Active
		{
			get
			{
				if (Plugin.Enabled != null && Plugin.Enabled.Value && _present && _enabled != null)
				{
					return _enabled.Value;
				}
				return false;
			}
		}

		internal static void Initialize(ConfigFile config, ManualLogSource log, Harmony harmony)
		{
			Log = log;
			_harmony = harmony;
			_enabled = config.Bind<bool>("Better Organisation", "IntegrateWithInnangard", true, "When Better Organisation is installed, use its category/item destination rules for Innangard sorting and replace Innangard's redundant chest-rules material picker (Shift+E by default) on BO-managed chests with an Open Better Organisation button.");
			_present = AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => string.Equals(a.GetName().Name, "ChestCategories", StringComparison.OrdinalIgnoreCase));
			if (!_present)
			{
				Log.LogInfo((object)"[BO] Better Organisation not installed; BO-specific Innangard integration skipped.");
				return;
			}
			BetterOrganisationRules.Bind();
			BetterOrganisationDrawerPriority.Initialize(harmony);
			InstallPatches();
			BetterOrganisationRules.Refresh(forceSummary: true);
		}

		internal static void Tick()
		{
			if (Active && !(Time.unscaledTime < _nextRefresh))
			{
				_nextRefresh = Time.unscaledTime + 0.5f;
				InstallPatches();
				BetterOrganisationRules.Refresh(forceSummary: false);
			}
		}

		internal static void Shutdown()
		{
			if (_present)
			{
				BetterOrganisationRules.RestoreAll();
			}
		}

		private static void InstallPatches()
		{
			if (_harmony != null && Active)
			{
				if (!_rulesInstalled)
				{
					_rulesInstalled = BetterOrganisationRules.Install(_harmony);
				}
				if (!_uiInstalled)
				{
					_uiInstalled = BetterOrganisationChestPanelCompat.Install(_harmony);
				}
			}
		}

		internal static string Root(Exception e)
		{
			while (e is TargetInvocationException && e.InnerException != null)
			{
				e = e.InnerException;
			}
			if (e != null)
			{
				return e.ToString();
			}
			return "unknown error";
		}
	}
	internal static class BetterOrganisationDrawerPriority
	{
		private sealed class Query
		{
			internal Vector3 Centre;

			internal float Radius;

			internal float Seen;

			internal List<object> Targets = new List<object>();
		}

		private static readonly List<Query> Recent = new List<Query>();

		private static MethodInfo _findTargets;

		private static PropertyInfo _home;

		private static PropertyInfo _scanRadius;

		private static PropertyInfo _targetValid;

		private static PropertyInfo _targetView;

		private static MethodInfo _itemTemplate;

		private static MethodInfo _externalTryGetReal;

		private static MethodInfo _externalGetFreeSpace;

		private static bool _installed;

		internal static void Initialize(Harmony harmony)
		{
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			if (_installed || harmony == null)
			{
				return;
			}
			Type type = AccessTools.TypeByName("Innangard.SettlerController");
			Type type2 = AccessTools.TypeByName("Innangard.ItemDrawerBridge");
			if (!(type == null) && !(type2 == null))
			{
				_findTargets = AccessTools.Method(type2, "FindTargets", (Type[])null, (Type[])null);
				_home = AccessTools.Property(type, "Home");
				_scanRadius = AccessTools.Property(type, "SettlementScanRadius");
				Type nestedType = type2.GetNestedType("Target", BindingFlags.Public | BindingFlags.NonPublic);
				if (nestedType != null)
				{
					_targetValid = AccessTools.Property(nestedType, "IsValid");
					_targetView = AccessTools.Property(nestedType, "View");
					_itemTemplate = AccessTools.Method(nestedType, "ItemTemplate", (Type[])null, (Type[])null);
				}
				Type type3 = AccessTools.TypeByName("InnangardBetrValheimDrawerBridge.Bridge");
				if (type3 != null)
				{
					_externalTryGetReal = AccessTools.Method(type3, "TryGetReal", (Type[])null, (Type[])null);
					_externalGetFreeSpace = AccessTools.Method(type3, "GetFreeSpace", (Type[])null, (Type[])null);
				}
				if (_findTargets == null || _home == null || _scanRadius == null || _targetValid == null || _itemTemplate == null)
				{
					BetterOrganisationIntegration.Log.LogWarning((object)"[BO] Could not bind Innangard drawer scan context; BO rules still work but transient drawer-first fallback protection is unavailable.");
					return;
				}
				harmony.Patch((MethodBase)_findTargets, (HarmonyMethod)null, new HarmonyMethod(typeof(BetterOrganisationDrawerPriority), "FindTargetsPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_installed = true;
				BetterOrganisationIntegration.Log.LogInfo((object)"[BO] Drawer-first destination guard now follows Innangard's own recent ItemDrawerBridge.FindTargets scans.");
			}
		}

		private static void FindTargetsPostfix(object __0, object __result)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (__0 == null)
			{
				return;
			}
			try
			{
				Vector3 centre = (Vector3)_home.GetValue(__0, null);
				float radius = Convert.ToSingle(_scanRadius.GetValue(__0, null));
				List<object> list = new List<object>();
				if (__result is IEnumerable enumerable)
				{
					foreach (object item in enumerable)
					{
						if (item != null)
						{
							list.Add(item);
						}
					}
				}
				float now = Time.unscaledTime;
				Recent.RemoveAll((Query q) => q == null || now - q.Seen > 3f);
				Query query = Recent.FirstOrDefault((Query q) => Vector3.Distance(q.Centre, centre) < 1f && Mathf.Abs(q.Radius - radius) < 1f);
				if (query == null)
				{
					query = new Query();
					Recent.Add(query);
				}
				query.Centre = centre;
				query.Radius = radius;
				query.Seen = now;
				query.Targets = list;
				while (Recent.Count > 8)
				{
					Recent.Remove(Recent.OrderBy((Query q) => q.Seen).First());
				}
			}
			catch (Exception e)
			{
				BetterOrganisationIntegration.Log.LogWarning((object)("[BO] Could not remember Innangard drawer scan: " + BetterOrganisationIntegration.Root(e)));
			}
		}

		internal static bool MatchingDrawerBeforeBo(Container chest, string sharedName)
		{
			if (!_installed || (Object)(object)chest == (Object)null || string.IsNullOrEmpty(sharedName))
			{
				return false;
			}
			float now = Time.unscaledTime;
			Query query = (from q in Recent
				where q != null && now - q.Seen <= 2f && Vector3.Distance(((Component)chest).transform.position, q.Centre) <= q.Radius + 10f
				orderby Vector3.Distance(((Component)chest).transform.position, q.Centre)
				select q).FirstOrDefault();
			if (query == null)
			{
				return false;
			}
			foreach (object target in query.Targets)
			{
				if (UsableMatchingTarget(target, sharedName))
				{
					return true;
				}
			}
			return false;
		}

		private static bool UsableMatchingTarget(object target, string sharedName)
		{
			try
			{
				object value = _targetValid.GetValue(target, null);
				if (!(value is bool) || !(bool)value)
				{
					return false;
				}
				object? obj = _itemTemplate.Invoke(target, null);
				ItemData val = (ItemData)((obj is ItemData) ? obj : null);
				if (val?.m_shared == null || !string.Equals(val.m_shared.m_name, sharedName, StringComparison.Ordinal))
				{
					return false;
				}
				if (_externalTryGetReal != null && _externalGetFreeSpace != null && _targetView != null)
				{
					object? value2 = _targetView.GetValue(target, null);
					ZNetView val2 = (ZNetView)((value2 is ZNetView) ? value2 : null);
					if ((Object)(object)val2 != (Object)null)
					{
						object[] array = new object[2] { val2, null };
						object obj2 = _externalTryGetReal.Invoke(null, array);
						if (obj2 is bool && (bool)obj2 && array[1] != null)
						{
							return Convert.ToInt32(_externalGetFreeSpace.Invoke(null, new object[1] { array[1] })) > 0;
						}
					}
				}
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class BetterOrganisationChestPanelCompat
	{
		private const BindingFlags InstanceAny = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags StaticAny = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const string CompatObjectName = "pho_bo_compat_note";

		private const string CompatButtonObjectName = "pho_bo_compat_button";

		private const string CompatText = "Override: Storage Rules managed by Better Organisation";

		private const string CompatButtonText = "Open Better Organisation";

		[ThreadStatic]
		private static bool _inPanelRead;

		private static bool _installed;

		private static bool _reportedMissing;

		private static bool _reportedSuppression;

		private static FieldInfo _container;

		private static FieldInfo _picking;

		private static FieldInfo _column;

		private static FieldInfo _grid;

		private static FieldInfo _choices;

		private static FieldInfo _mineHelp;

		private static FieldInfo _origin;

		private static FieldInfo _byHand;

		private static FieldInfo _slack;

		private static FieldInfo _remeasureFlag;

		private static MethodInfo _remeasure;

		private static MethodInfo _resize;

		private static PropertyInfo _boUiInstance;

		private static PropertyInfo _boGui;

		private static MethodInfo _boToggleEditor;

		internal static bool InPanelRead => _inPanelRead;

		internal static bool Install(Harmony harmony)
		{
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Expected O, but got Unknown
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e9: Expected O, but got Unknown
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Expected O, but got Unknown
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_0441: Expected O, but got Unknown
			//IL_0455: Unknown result type (might be due to invalid IL or missing references)
			//IL_0463: Expected O, but got Unknown
			if (_installed)
			{
				return true;
			}
			if (!BetterOrganisationRules.IsAvailable)
			{
				return false;
			}
			Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, "Innangard", StringComparison.OrdinalIgnoreCase));
			Type type = assembly?.GetType("Innangard.ChestSortPanel", throwOnError: false);
			if (type == null)
			{
				if (!_reportedMissing && assembly != null)
				{
					_reportedMissing = true;
					BetterOrganisationIntegration.Log.LogWarning((object)"[BO UI] Innangard.ChestSortPanel was not found; chest-rules picker suppression is unavailable.");
				}
				return false;
			}
			MethodInfo method = type.GetMethod("Open", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Container) }, null);
			MethodInfo method2 = type.GetMethod("Refresh", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			MethodInfo methodInfo = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo m)
			{
				if (m.Name != "BuildChoices")
				{
					return false;
				}
				ParameterInfo[] parameters = m.GetParameters();
				return parameters.Length == 2 && typeof(Container).IsAssignableFrom(parameters[0].ParameterType);
			});
			MethodInfo methodInfo2 = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "Populate" && m.GetParameters().Length == 1 && m.ReturnType == typeof(void));
			_container = type.GetField("_container", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_picking = type.GetField("_picking", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_column = type.GetField("_column", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_grid = type.GetField("_grid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_choices = type.GetField("_choices", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_mineHelp = type.GetField("_mineHelp", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_origin = type.GetField("_origin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_byHand = type.GetField("_byHand", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_slack = type.GetField("_slack", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_remeasureFlag = type.GetField("_remeasure", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_remeasure = type.GetMethod("Remeasure", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			_resize = type.GetMethod("Resize", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			Type? obj = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, "ChestCategories", StringComparison.OrdinalIgnoreCase))?.GetType("ChestCategories.UI.ModUi", throwOnError: false);
			_boUiInstance = obj?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			_boGui = obj?.GetProperty("Gui", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_boToggleEditor = obj?.GetMethod("ToggleEditor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Container) }, null);
			if (method == null || method2 == null || methodInfo == null || methodInfo2 == null || _container == null || _picking == null || _column == null || _mineHelp == null)
			{
				if (!_reportedMissing)
				{
					_reportedMissing = true;
					BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Innangard 0.1.9 chest-rules panel binding incomplete: " + $"Open={method != null} Refresh={method2 != null} BuildChoices={methodInfo != null} " + $"Populate={methodInfo2 != null} container={_container != null} picking={_picking != null} column={_column != null} mineHelp={_mineHelp != null}."));
				}
				return false;
			}
			HarmonyMethod val = new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "PanelScopePrefix", (Type[])null);
			HarmonyMethod val2 = new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "PanelScopePostfix", (Type[])null);
			HarmonyMethod val3 = new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "PanelScopeFinalizer", (Type[])null);
			harmony.Patch((MethodBase)method, val, val2, (HarmonyMethod)null, val3, (HarmonyMethod)null);
			harmony.Patch((MethodBase)method2, val, val2, (HarmonyMethod)null, val3, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "BuildChoicesPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(BetterOrganisationChestPanelCompat), "PopulatePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_installed = true;
			BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Bound Innangard.ChestSortPanel Open/Refresh/BuildChoices/Populate.");
			BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] BO-managed Innangard chest-rules panels keep intake/private controls and replace only the material picker with a Better Organisation storage-rules shortcut.");
			if (_boUiInstance != null && _boToggleEditor != null)
			{
				BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Better Organisation category editor shortcut bound.");
			}
			else
			{
				BetterOrganisationIntegration.Log.LogWarning((object)"[BO UI] Better Organisation category editor shortcut was not found; the compatibility heading will still be shown.");
			}
			return true;
		}

		private static void PanelScopePrefix()
		{
			_inPanelRead = true;
		}

		private static void PanelScopePostfix(object __instance)
		{
			_inPanelRead = false;
			Apply(__instance);
		}

		private static Exception PanelScopeFinalizer(Exception __exception)
		{
			_inPanelRead = false;
			return __exception;
		}

		private static bool BuildChoicesPrefix(Container __0)
		{
			return !BetterOrganisationRules.IsManaged(__0);
		}

		private static bool PopulatePrefix(object __instance)
		{
			if (!BetterOrganisationRules.IsManaged(GetContainer(__instance)))
			{
				return true;
			}
			ClearPickerRows(__instance);
			return false;
		}

		private static Container GetContainer(object panel)
		{
			try
			{
				return (Container)((panel != null) ? /*isinst with value type is only supported in some contexts*/: null);
			}
			catch
			{
				return null;
			}
		}

		private static void ClearPickerRows(object panel)
		{
			try
			{
				object? obj = _grid?.GetValue(panel);
				RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					for (int num = ((Transform)val).childCount - 1; num >= 0; num--)
					{
						Object.Destroy((Object)(object)((Component)((Transform)val).GetChild(num)).gameObject);
					}
				}
				(_choices?.GetValue(panel) as IList)?.Clear();
			}
			catch (Exception e)
			{
				BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Could not clear Innangard's old material rows: " + BetterOrganisationIntegration.Root(e)));
			}
		}

		private static void Apply(object panel)
		{
			if (panel == null)
			{
				return;
			}
			try
			{
				Container container = GetContainer(panel);
				bool flag = BetterOrganisationRules.IsManaged(container);
				object? value = _picking.GetValue(panel);
				RectTransform val = (RectTransform)((value is RectTransform) ? value : null);
				object? value2 = _column.GetValue(panel);
				RectTransform val2 = (RectTransform)((value2 is RectTransform) ? value2 : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					return;
				}
				GameObject val3 = FindCompatObject(val2, "pho_bo_compat_note");
				GameObject val4 = FindCompatObject(val2, "pho_bo_compat_button");
				bool flag2 = false;
				if (flag)
				{
					if (((Component)val).gameObject.activeSelf)
					{
						((Component)val).gameObject.SetActive(false);
						flag2 = true;
					}
					if ((Object)(object)val3 == (Object)null)
					{
						val3 = CreateCompatNote(panel, val2, val);
						flag2 = (Object)(object)val3 != (Object)null;
					}
					if ((Object)(object)val4 == (Object)null && _boUiInstance != null && _boToggleEditor != null)
					{
						val4 = CreateCompatButton(panel, val2, val, container);
						flag2 = (Object)(object)val4 != (Object)null;
					}
					if ((Object)(object)val3 != (Object)null)
					{
						if (!val3.activeSelf)
						{
							val3.SetActive(true);
							flag2 = true;
						}
						int siblingIndex = ((Transform)val).GetSiblingIndex();
						if (val3.transform.GetSiblingIndex() != siblingIndex)
						{
							val3.transform.SetSiblingIndex(siblingIndex);
							flag2 = true;
						}
					}
					if ((Object)(object)val4 != (Object)null)
					{
						BetterOrganisationEditorButtonAction component = val4.GetComponent<BetterOrganisationEditorButtonAction>();
						if ((Object)(object)component != (Object)null)
						{
							component.Target = container;
							component.InnangardPanel = panel;
						}
						if (!val4.activeSelf)
						{
							val4.SetActive(true);
							flag2 = true;
						}
						int num = (((Object)(object)val3 != (Object)null) ? Math.Min(val3.transform.GetSiblingIndex() + 1, Math.Max(0, ((Transform)val2).childCount - 1)) : ((Transform)val).GetSiblingIndex());
						if (val4.transform.GetSiblingIndex() != num)
						{
							val4.transform.SetSiblingIndex(num);
							flag2 = true;
						}
					}
					ClearPickerRows(panel);
					SetSlackFlexible(panel, 1f);
					if (!_reportedSuppression)
					{
						_reportedSuppression = true;
						BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Suppressed the Innangard chest-rules Search/material list for a Better Organisation-managed chest.");
					}
				}
				else
				{
					if ((Object)(object)val3 != (Object)null && val3.activeSelf)
					{
						val3.SetActive(false);
						flag2 = true;
					}
					if ((Object)(object)val4 != (Object)null && val4.activeSelf)
					{
						val4.SetActive(false);
						flag2 = true;
					}
				}
				if (flag2)
				{
					if (_remeasureFlag != null)
					{
						_remeasureFlag.SetValue(panel, true);
					}
					_remeasure?.Invoke(panel, null);
					_resize?.Invoke(panel, null);
				}
			}
			catch (Exception e)
			{
				BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Could not apply chest-rules material-picker compatibility layout: " + BetterOrganisationIntegration.Root(e)));
			}
		}

		private static GameObject FindCompatObject(RectTransform column, string name)
		{
			for (int i = 0; i < ((Transform)column).childCount; i++)
			{
				Transform child = ((Transform)column).GetChild(i);
				if ((Object)(object)child != (Object)null && (Object)(object)((Component)child).gameObject != (Object)null && ((Object)((Component)child).gameObject).name == name)
				{
					return ((Component)child).gameObject;
				}
			}
			return null;
		}

		private static GameObject CreateCompatNote(object panel, RectTransform column, RectTransform picking)
		{
			object? obj = _origin?.GetValue(panel);
			Component val = (Component)((obj is Component) ? obj : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null)
			{
				object? obj2 = _mineHelp?.GetValue(panel);
				val = (Component)((obj2 is Component) ? obj2 : null);
			}
			if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null)
			{
				return null;
			}
			GameObject obj3 = Object.Instantiate<GameObject>(val.gameObject);
			((Object)obj3).name = "pho_bo_compat_note";
			obj3.transform.SetParent((Transform)(object)column, false);
			obj3.transform.SetSiblingIndex(((Transform)picking).GetSiblingIndex());
			Component component = obj3.GetComponent(((object)val).GetType());
			SetText(component, "Override: Storage Rules managed by Better Organisation");
			SetNumericProperty(component, "fontSize", 20);
			obj3.SetActive(true);
			return obj3;
		}

		private static GameObject CreateCompatButton(object panel, RectTransform column, RectTransform picking, Container container)
		{
			object? obj = _byHand?.GetValue(panel);
			Component val = (Component)((obj is Component) ? obj : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val.gameObject);
			((Object)val2).name = "pho_bo_compat_button";
			val2.transform.SetParent((Transform)(object)column, false);
			val2.transform.SetSiblingIndex(((Transform)picking).GetSiblingIndex());
			SetFirstChildText(val2, "Open Better Organisation");
			Component component = val2.GetComponent(((object)val).GetType());
			object obj2 = ((object)component)?.GetType().GetProperty("onClick", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(component, null);
			if (obj2 == null)
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			obj2.GetType().GetMethod("RemoveAllListeners", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null)?.Invoke(obj2, null);
			BetterOrganisationEditorButtonAction betterOrganisationEditorButtonAction = val2.AddComponent<BetterOrganisationEditorButtonAction>();
			betterOrganisationEditorButtonAction.Target = container;
			betterOrganisationEditorButtonAction.InnangardPanel = panel;
			MethodInfo method = typeof(BetterOrganisationEditorButtonAction).GetMethod("Click", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			MethodInfo methodInfo = obj2.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "AddListener" && m.GetParameters().Length == 1);
			if (method == null || methodInfo == null)
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			Delegate obj3 = Delegate.CreateDelegate(methodInfo.GetParameters()[0].ParameterType, betterOrganisationEditorButtonAction, method);
			methodInfo.Invoke(obj2, new object[1] { obj3 });
			val2.SetActive(true);
			return val2;
		}

		private static void SetFirstChildText(GameObject root, string value)
		{
			if (!((Object)(object)root == (Object)null))
			{
				Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
				for (int i = 0; i < componentsInChildren.Length && !SetText(componentsInChildren[i], value); i++)
				{
				}
			}
		}

		private static bool SetText(Component component, string value)
		{
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			try
			{
				PropertyInfo property = ((object)component).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property == null || !property.CanWrite || property.PropertyType != typeof(string))
				{
					return false;
				}
				property.SetValue(component, value, null);
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static void SetNumericProperty(Component component, string name, int value)
		{
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			try
			{
				PropertyInfo property = ((object)component).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(property == null) && property.CanWrite)
				{
					if (property.PropertyType == typeof(int))
					{
						property.SetValue(component, value, null);
					}
					else if (property.PropertyType == typeof(float))
					{
						property.SetValue(component, (float)value, null);
					}
				}
			}
			catch
			{
			}
		}

		internal static void CloseInnangardPanel(object panel)
		{
			if (panel == null)
			{
				return;
			}
			try
			{
				Type type = panel.GetType();
				MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => (m.Name == "Close" || m.Name == "Hide" || m.Name == "Dismiss") && m.GetParameters().Length == 0 && m.ReturnType == typeof(void));
				if (methodInfo != null)
				{
					methodInfo.Invoke(panel, null);
					BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Closed Innangard chest-rules panel before opening Better Organisation.");
					return;
				}
				string[] array = new string[4] { "m_panel", "_panel", "_root", "m_root" };
				foreach (string name in array)
				{
					object obj = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(panel);
					GameObject val = (GameObject)((obj is GameObject) ? obj : null);
					if (val != null)
					{
						val.SetActive(false);
						BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Closed Innangard chest-rules panel before opening Better Organisation.");
						return;
					}
					Component val2 = (Component)((obj is Component) ? obj : null);
					if (val2 != null && (Object)(object)val2.gameObject != (Object)null)
					{
						val2.gameObject.SetActive(false);
						BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Closed Innangard chest-rules panel before opening Better Organisation.");
						return;
					}
				}
				Component val3 = (Component)((panel is Component) ? panel : null);
				if (val3 != null && (Object)(object)val3.gameObject != (Object)null)
				{
					val3.gameObject.SetActive(false);
					BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Closed Innangard chest-rules panel before opening Better Organisation.");
				}
				else
				{
					BetterOrganisationIntegration.Log.LogWarning((object)"[BO UI] Could not find Innangard's panel root to close it.");
				}
			}
			catch (Exception e)
			{
				BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Could not close Innangard chest-rules panel: " + BetterOrganisationIntegration.Root(e)));
			}
		}

		internal static void OpenBetterOrganisationEditor(Container container)
		{
			if ((Object)(object)container == (Object)null || _boUiInstance == null || _boToggleEditor == null)
			{
				return;
			}
			try
			{
				object value = _boUiInstance.GetValue(null, null);
				if (value == null)
				{
					BetterOrganisationIntegration.Log.LogWarning((object)"[BO UI] Better Organisation UI is not ready yet.");
					return;
				}
				bool flag = false;
				MethodInfo method = typeof(InventoryGui).GetMethod("IsVisible", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (method != null)
				{
					flag = (bool)method.Invoke(null, null);
				}
				if (!flag)
				{
					object obj = _boGui?.GetValue(value, null);
					(obj?.GetType().GetMethod("Show", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
					{
						typeof(Container),
						typeof(int)
					}, null))?.Invoke(obj, new object[2] { null, 1 });
				}
				_boToggleEditor.Invoke(value, new object[1] { container });
				BetterOrganisationIntegration.Log.LogInfo((object)"[BO UI] Opened Better Organisation storage rules for the current chest.");
			}
			catch (Exception e)
			{
				BetterOrganisationIntegration.Log.LogWarning((object)("[BO UI] Could not open Better Organisation storage rules: " + BetterOrganisationIntegration.Root(e)));
			}
		}

		private static void SetSlackFlexible(object panel, float value)
		{
			try
			{
				object obj = _slack?.GetValue(panel);
				(obj?.GetType().GetProperty("flexibleHeight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.SetValue(obj, value, null);
			}
			catch
			{
			}
		}
	}
	internal sealed class BetterOrganisationEditorButtonAction : MonoBehaviour
	{
		internal Container Target;

		internal object InnangardPanel;

		public void Click()
		{
			BetterOrganisationChestPanelCompat.CloseInnangardPanel(InnangardPanel);
			BetterOrganisationChestPanelCompat.OpenBetterOrganisationEditor(Target);
		}
	}
	internal static class BetterOrganisationRules
	{
		private sealed class RuleCache
		{
			internal string Signature;

			internal bool HasAnyRule;

			internal HashSet<string> Accepted;
		}

		private sealed class RuleSnapshot
		{
			internal bool HasLinks;

			internal bool AcceptsEverything;

			internal bool AcceptsStash = true;

			internal readonly HashSet<string> Include = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

			internal readonly HashSet<string> Exclude = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

			internal bool HasAnyRule
			{
				get
				{
					if (!HasLinks && !AcceptsEverything && AcceptsStash && Include.Count <= 0)
					{
						return Exclude.Count > 0;
					}
					return true;
				}
			}
		}

		private const BindingFlags Any = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const string MirrorKey = "pho_bo_inn_mirror";

		private const string BackupConfiguredKey = "pho_bo_inn_b_cfg";

		private const string BackupKindsKey = "pho_bo_inn_b_kinds";

		private const string BackupItemsKey = "pho_bo_inn_b_items";

		private const string BackupLegacyKindKey = "pho_bo_inn_b_legacy";

		private static Assembly _assembly;

		private static Type _storeType;

		private static Type _configType;

		private static Type _categoryServiceType;

		private static Type _categoryType;

		private static Type _groupType;

		private static MethodInfo _getConfig;

		private static MethodInfo _getCategory;

		private static PropertyInfo _hasLinks;

		private static PropertyInfo _links;

		private static PropertyInfo _includeItems;

		private static PropertyInfo _excludeItems;

		private static PropertyInfo _acceptsEverything;

		private static PropertyInfo _acceptsStash;

		private static MethodInfo _isLinkedCategory;

		private static MethodInfo _isLinkedGroup;

		private static PropertyInfo _categoryGroup;

		private static PropertyInfo _categoryId;

		private static PropertyInfo _groupId;

		private static MethodInfo _serializeConfig;

		private static readonly Dictionary<int, RuleCache> RuleCaches = new Dictionary<int, RuleCache>();

		private static bool _bound;

		private static bool _reportedUnavailable;

		private static bool _installed;

		private static bool _reportedMissing;

		private static int _lastActive = -1;

		internal static bool IsAvailable => _bound;

		internal static bool Install(Harmony harmony)
		{
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Expected O, but got Unknown
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Expected O, but got Unknown
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Expected O, but got Unknown
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Expected O, but got Unknown
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Expected O, but got Unknown
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Expected O, but got Unknown
			if (!_bound)
			{
				return false;
			}
			if (_installed)
			{
				return true;
			}
			Type type = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, "Innangard", StringComparison.OrdinalIgnoreCase))?.GetType("Innangard.ChestSortRules", throwOnError: false);
			if (type == null)
			{
				return false;
			}
			BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			Type[] types = new Type[1] { typeof(Container) };
			MethodInfo method = type.GetMethod("IsConfigured", bindingAttr, null, types, null);
			MethodInfo method2 = type.GetMethod("KindsOf", bindingAttr, null, types, null);
			MethodInfo method3 = type.GetMethod("ReadItems", bindingAttr, null, types, null);
			Type[] types2 = new Type[2]
			{
				typeof(Container),
				typeof(string)
			};
			MethodInfo method4 = type.GetMethod("Accepts", bindingAttr, null, types2, null);
			MethodInfo method5 = type.GetMethod("Precision", bindingAttr, null, types2, null);
			MethodInfo method6 = type.GetMethod("IsSortable", bindingAttr, null, new Type[1] { typeof(ItemData) }, null);
			if (method == null || method.ReturnType != typeof(bool) || method2 == null || method2.ReturnType != typeof(int) || method3 == null || method3.ReturnType != typeof(HashSet<string>) || method4 == null || method4.ReturnType != typeof(bool) || method5 == null || method5.ReturnType != typeof(int))
			{
				if (!_reportedMissing)
				{
					_reportedMissing = true;
					BetterOrganisationIntegration.Log.LogError((object)"[BO] Innangard chest rule methods changed; local BO matching is unavailable.");
				}
				return false;
			}
			harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(BetterOrganisationRules), "ConfiguredPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)method2, new HarmonyMethod(typeof(BetterOrganisationRules), "KindsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)method3, new HarmonyMethod(typeof(BetterOrganisationRules), "ItemsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)method4, new HarmonyMethod(typeof(BetterOrganisationRules), "AcceptsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)method5, new HarmonyMethod(typeof(BetterOrganisationRules), "PrecisionPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			if (method6 != null && method6.ReturnType == typeof(bool))
			{
				harmony.Patch((MethodBase)method6, (HarmonyMethod)null, new HarmonyMethod(typeof(BetterOrganisationRules), "SortablePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				BetterOrganisationIntegration.Log.LogInfo((object)"[BO] BO-explicit destination items are eligible for caretaker chest sorting even when Innangard's native item-type whitelist excludes them; loose-ground pickup remains unchanged.");
			}
			else
			{
				BetterOrganisationIntegration.Log.LogWarning((object)"[BO] Innangard ChestSortRules.IsSortable(ItemData) was not found; BO-explicit nonstandard item types will keep Innangard's native sorting restriction.");
			}
			_installed = true;
			BetterOrganisationIntegration.Log.LogInfo((object)"[BO] Innangard now reads BO category/item rules locally; no extra rule list is written to chests.");
			return true;
		}

		private static bool ConfiguredPrefix(Container __0, ref bool __result)
		{
			if (!TryGetAccepted(__0, out var _))
			{
				return true;
			}
			__result = true;
			return false;
		}

		private static bool KindsPrefix(Container __0, ref int __result)
		{
			if (!TryGetAccepted(__0, out var _))
			{
				return true;
			}
			__result = 0;
			return false;
		}

		private static bool ItemsPrefix(Container __0, ref HashSet<string> __result)
		{
			if (!TryGetAccepted(__0, out var accepted))
			{
				return true;
			}
			if (BetterOrganisationChestPanelCompat.InPanelRead)
			{
				__result = new HashSet<string>(StringComparer.Ordinal) { "__pho_bo_managed__" };
				return false;
			}
			__result = new HashSet<string>(accepted, StringComparer.Ordinal);
			return false;
		}

		private static bool AcceptsPrefix(Container __0, string __1, ref bool __result)
		{
			if (TryGetAccepted(__0, out var accepted))
			{
				__result = !string.IsNullOrEmpty(__1) && accepted.Contains(__1);
				return false;
			}
			if (!HasNativeExplicitRule(__0) && AnyManagedChestAccepts(__1))
			{
				__result = false;
				return false;
			}
			return true;
		}

		private static bool PrecisionPrefix(Container __0, string __1, ref int __result)
		{
			if (!TryGetAccepted(__0, out var accepted))
			{
				if (!HasNativeExplicitRule(__0) && AnyManagedChestAccepts(__1))
				{
					__result = int.MaxValue;
					return false;
				}
				return true;
			}
			if (string.IsNullOrEmpty(__1) || !accepted.Contains(__1))
			{
				__result = int.MaxValue;
				return false;
			}
			if (BetterOrganisationDrawerPriority.MatchingDrawerBeforeBo(__0, __1))
			{
				__result = int.MaxValue;
				return false;
			}
			__result = 0;
			return false;
		}

		private static void SortablePostfix(ItemData __0, ref bool __result)
		{
			if (!__result && BetterOrganisationIntegration.Active && __0?.m_shared != null && !__0.m_shared.m_questItem && !__0.m_equipped)
			{
				string name = __0.m_shared.m_name;
				if (!string.IsNullOrEmpty(name) && AnyManagedChestAccepts(name))
				{
					__result = true;
				}
			}
		}

		private static bool AnyManagedChestAccepts(string sharedName)
		{
			if (!_installed || !_bound || string.IsNullOrEmpty(sharedName))
			{
				return false;
			}
			foreach (RuleCache value in RuleCaches.Values)
			{
				if (value != null && value.HasAnyRule && value.Accepted != null && value.Accepted.Contains(sharedName))
				{
					return true;
				}
			}
			return false;
		}

		private static bool HasNativeExplicitRule(Container container)
		{
			try
			{
				ZNetView containerView = GetContainerView(container);
				if ((Object)(object)containerView == (Object)null || !containerView.IsValid())
				{
					return false;
				}
				ZDO zDO = containerView.GetZDO();
				if (zDO == null)
				{
					return false;
				}
				if (zDO.GetBool("inn_sort_configured", false))
				{
					return true;
				}
				if (zDO.GetInt("inn_sort_kinds", 0) != 0)
				{
					return true;
				}
				return zDO.GetInt("inn_chest_sort_kind", 0) != 0;
			}
			catch
			{
				return false;
			}
		}

		internal static bool IsManaged(Container container)
		{
			HashSet<string> accepted;
			return TryGetAccepted(container, out accepted);
		}

		private static bool TryGetAccepted(Container container, out HashSet<string> accepted)
		{
			accepted = null;
			if (!BetterOrganisationIntegration.Active || !_installed || !_bound || (Object)(object)ObjectDB.instance == (Object)null || (Object)(object)container == (Object)null)
			{
				return false;
			}
			ZNetView containerView = GetContainerView(container);
			if ((Object)(object)containerView == (Object)null || !containerView.IsValid() || containerView.GetZDO() == null)
			{
				return false;
			}
			int instanceID = ((Object)containerView).GetInstanceID();
			if (!RuleCaches.TryGetValue(instanceID, out var value))
			{
				value = RefreshCac