Decompiled source of The Inspector Overhaul Mod v1.1.1

TheInspector.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TheInspector")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+716a7a61af29415a5f69791ad6ef0d1b94c1f69e")]
[assembly: AssemblyProduct("TheInspector")]
[assembly: AssemblyTitle("TheInspector")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 TheInspector
{
	internal static class ArrestReactions
	{
		private sealed class FreezeWatch
		{
			internal Vector3 LastPosition;

			internal float NextSampleTime;

			internal int SamplesLeft;
		}

		private const float GawkLookRank = 100f;

		private const int FreezeSampleCount = 6;

		private const float FreezeSampleInterval = 0.5f;

		private const float FreezeDriftTolerance = 0.25f;

		internal static readonly HashSet<Actor> Surrendering = new HashSet<Actor>();

		internal static readonly HashSet<Actor> Gawking = new HashSet<Actor>();

		private static readonly Dictionary<Actor, FreezeWatch> FreezeWatches = new Dictionary<Actor, FreezeWatch>();

		internal static bool IsRedHandedMurderer(NewAIController ai)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			if ((Object)(object)ai == (Object)null)
			{
				return false;
			}
			List<Murder> killerForMurders = ai.killerForMurders;
			if (killerForMurders == null)
			{
				return false;
			}
			Enumerator<Murder> enumerator = killerForMurders.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Murder current = enumerator.Current;
				if (current != null && (int)current.state == 5)
				{
					return true;
				}
			}
			return false;
		}

		internal static bool ShouldSurrender(Actor victim, Actor fromWho)
		{
			if (!InspectorConfig.CivilianReactionsEnabled.Value)
			{
				return false;
			}
			if ((Object)(object)fromWho == (Object)null || !fromWho.isPlayer)
			{
				return false;
			}
			if (InspectorConfig.RedHandedMurderException.Value && IsRedHandedMurderer((victim != null) ? victim.ai : null))
			{
				return false;
			}
			return true;
		}

		internal static void BreakGawk(Actor actor)
		{
			if (!((Object)(object)actor == (Object)null) && Gawking.Remove(actor))
			{
				ClearOrientationOverride(actor);
			}
		}

		private static void ClearOrientationOverride(Actor actor)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			NewAIController val = ((actor != null) ? actor.ai : null);
			if (!((Object)(object)val == (Object)null))
			{
				val.facingActive = false;
				val.faceTransform = null;
				val.faceTransformOffset = Vector3.zero;
				val.lookAtTransform = null;
				val.lookAtTransformRank = 0f;
			}
		}

		internal static void BeginArrest(Actor victim)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)victim == (Object)null)
			{
				return;
			}
			BreakGawk(victim);
			Surrendering.Add(victim);
			PinPath(victim);
			FreezeWatches[victim] = new FreezeWatch
			{
				LastPosition = ((Component)victim).transform.position,
				NextSampleTime = Time.time + 0.5f,
				SamplesLeft = 6
			};
			ApplySurrenderState(victim);
			Player instance = Player.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			CityData instance2 = CityData.Instance;
			List<Citizen> val = ((instance2 != null) ? instance2.citizenDirectory : null);
			if (val == null)
			{
				return;
			}
			float value = InspectorConfig.GawkRadius.Value;
			Enumerator<Citizen> enumerator = val.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Citizen current = enumerator.Current;
				if (!((Object)(object)current == (Object)null) && !((Actor)current).isDead && !((Object)(object)current == (Object)(object)victim) && !Surrendering.Contains((Actor)(object)current) && !Gawking.Contains((Actor)(object)current) && Vector3.Distance(((Component)current).transform.position, ((Component)instance).transform.position) <= value)
				{
					Gawking.Add((Actor)(object)current);
				}
			}
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExDebugLogInterpolatedStringHandler val2 = new BepInExDebugLogInterpolatedStringHandler(52, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("CalebScott.TheInspector");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] Arrest initiated on ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)victim).name);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(Gawking.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" nearby citizen(s) gawking.");
			}
			logger.LogDebug(val2);
		}

		private static void PinPath(Actor actor)
		{
			NewAIController val = ((actor != null) ? actor.ai : null);
			if (!((Object)(object)val == (Object)null))
			{
				NewNode currentNode = actor.currentNode;
				if (currentNode != null && val.currentDestinationNode != currentNode)
				{
					val.SetDestinationNode(currentNode, false);
				}
			}
		}

		private static void FreezeInPlace(Actor actor)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)actor.ai != (Object)null)
			{
				actor.ai.currentDestinationPositon = ((Component)actor).transform.position;
			}
		}

		private static void ApplySurrenderState(Actor victim)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Invalid comparison between Unknown and I4
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Invalid comparison between Unknown and I4
			FreezeInPlace(victim);
			NewAIController ai = victim.ai;
			if ((Object)(object)ai != (Object)null)
			{
				ai.inFleeState = false;
				ai.movementAmount = 0f;
				ai.doIMove = false;
				if ((Object)(object)ai.persuitTarget != (Object)null)
				{
					ai.CancelPersue();
				}
			}
			victim.isRunning = false;
			victim.isMoving = false;
			CitizenAnimationController animationController = victim.animationController;
			if ((Object)(object)animationController != (Object)null)
			{
				if ((int)animationController.armsBoolAnimationState == 11)
				{
					animationController.SetArmsBoolState((ArmsBoolSate)1);
				}
				if ((int)animationController.idleAnimationState != 14)
				{
					animationController.SetIdleAnimationState((IdleAnimationState)14);
				}
			}
		}

		private static void EndSurrender(Actor victim)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			Surrendering.Remove(victim);
			FreezeWatches.Remove(victim);
			CitizenAnimationController animationController = victim.animationController;
			if ((Object)(object)animationController != (Object)null && (int)animationController.idleAnimationState == 14)
			{
				animationController.SetIdleAnimationState((IdleAnimationState)0);
			}
		}

		private static void ApplyGawkState(Actor gawker, Transform playerTransform)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			FreezeInPlace(gawker);
			NewAIController ai = gawker.ai;
			if (!((Object)(object)ai == (Object)null))
			{
				ai.SetLookAtTransform(playerTransform, 100f);
				if ((Object)(object)ai.faceTransform != (Object)(object)playerTransform)
				{
					ai.SetFacingTransform(playerTransform, Vector3.zero);
				}
			}
		}

		private static void SampleFreeze(Actor victim)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			if (FreezeWatches.TryGetValue(victim, out var value) && value.SamplesLeft > 0 && !(Time.time < value.NextSampleTime))
			{
				value.SamplesLeft--;
				value.NextSampleTime = Time.time + 0.5f;
				Vector3 position = ((Component)victim).transform.position;
				float num = Vector3.Distance(position, value.LastPosition);
				value.LastPosition = position;
				NewAIController ai = victim.ai;
				CitizenAnimationController animationController = victim.animationController;
				object obj;
				if (ai == null)
				{
					obj = null;
				}
				else
				{
					NewAIGoal currentGoal = ai.currentGoal;
					obj = ((currentGoal != null) ? currentGoal.name : null);
				}
				if (obj == null)
				{
					obj = "<none>";
				}
				string value2 = (string)obj;
				bool value3 = (Object)(object)ai != (Object)null && ai.currentDestinationNode == victim.currentNode;
				string text = $"[{"CalebScott.TheInspector"}] Surrender hold on {((Object)victim).name}: drift={num:F2}m flee={((ai != null) ? new bool?(ai.inFleeState) : ((bool?)null))} running={victim.isRunning} moving={victim.isMoving} doIMove={((ai != null) ? new bool?(ai.doIMove) : ((bool?)null))} movementAmount={((ai != null) ? new float?(ai.movementAmount) : ((float?)null)):F2} spooked={((ai != null) ? new float?(ai.spooked) : ((float?)null)):F1} nerve={victim.currentNerve:F1} atDest={value3} goal='{value2}' arms={((animationController != null) ? new ArmsBoolSate?(animationController.armsBoolAnimationState) : ((ArmsBoolSate?)null))} idle={((animationController != null) ? new IdleAnimationState?(animationController.idleAnimationState) : ((IdleAnimationState?)null))}";
				if (num > 0.25f)
				{
					Plugin.Logger.LogWarning((object)(text + " -- STILL MOVING"));
				}
				else
				{
					Plugin.Logger.LogDebug((object)text);
				}
			}
		}

		internal static void TickActor(NewAIController ai)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			Human val = ((ai != null) ? ai.human : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (((Actor)val).isDead)
			{
				EndSurrender((Actor)(object)val);
				Gawking.Remove((Actor)(object)val);
				return;
			}
			Player instance = Player.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)instance).transform.position;
			if (Surrendering.Contains((Actor)(object)val))
			{
				if (Vector3.Distance(((Component)val).transform.position, position) > InspectorConfig.SurrenderReleaseDistance.Value)
				{
					EndSurrender((Actor)(object)val);
					return;
				}
				ApplySurrenderState((Actor)(object)val);
				SampleFreeze((Actor)(object)val);
			}
			else if (Gawking.Contains((Actor)(object)val))
			{
				if (Vector3.Distance(((Component)val).transform.position, position) > InspectorConfig.GawkReleaseDistance.Value)
				{
					BreakGawk((Actor)(object)val);
				}
				else
				{
					ApplyGawkState((Actor)(object)val, ((Component)instance).transform);
				}
			}
		}

		internal static bool IsHardFrozen(Actor actor)
		{
			if ((Object)(object)actor == (Object)null)
			{
				return false;
			}
			if (!InspectorConfig.CivilianReactionsEnabled.Value || !InspectorConfig.SurrenderHardFreeze.Value)
			{
				return false;
			}
			return Surrendering.Contains(actor);
		}
	}
	[HarmonyPatch(typeof(Actor), "RecieveDamage")]
	internal static class Actor_RecieveDamage_Patch
	{
		[HarmonyPrefix]
		private static void Prefix(Actor __instance, Actor fromWho, ref bool alertSurrounding)
		{
			if (ArrestReactions.ShouldSurrender(__instance, fromWho))
			{
				alertSurrounding = false;
			}
		}

		[HarmonyPostfix]
		private static void Postfix(Actor __instance, Actor fromWho)
		{
			if (InspectorConfig.CivilianReactionsEnabled.Value)
			{
				ArrestReactions.BreakGawk(__instance);
			}
			if (ArrestReactions.ShouldSurrender(__instance, fromWho))
			{
				ArrestReactions.BeginArrest(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(NewAIController), "SetInCombat")]
	internal static class NewAIController_SetInCombat_Patch
	{
		[HarmonyPrefix]
		private static bool Prefix(NewAIController __instance, bool val)
		{
			if (!val || !InspectorConfig.CivilianReactionsEnabled.Value)
			{
				return true;
			}
			return (Object)(object)__instance.human == (Object)null || !ArrestReactions.Surrendering.Contains((Actor)(object)__instance.human);
		}
	}
	[HarmonyPatch(typeof(CitizenAnimationController), "SetInCombat")]
	internal static class CitizenAnimationController_SetInCombat_Patch
	{
		[HarmonyPrefix]
		private static bool Prefix(CitizenAnimationController __instance, bool val)
		{
			if (!val || !InspectorConfig.CivilianReactionsEnabled.Value)
			{
				return true;
			}
			Actor component = ((Component)__instance).gameObject.GetComponent<Actor>();
			return (Object)(object)component == (Object)null || !ArrestReactions.Surrendering.Contains(component);
		}
	}
	[HarmonyPatch(typeof(NewAIController), "StartAttack")]
	internal static class NewAIController_StartAttack_Patch
	{
		private static readonly Random Roll = new Random();

		[HarmonyPrefix]
		private static bool Prefix(NewAIController __instance, Actor newAttackTarget)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			if (!InspectorConfig.CivilianReactionsEnabled.Value)
			{
				return true;
			}
			if ((Object)(object)newAttackTarget == (Object)null || !newAttackTarget.isPlayer)
			{
				return true;
			}
			if (InspectorConfig.RedHandedMurderException.Value && ArrestReactions.IsRedHandedMurderer(__instance))
			{
				return true;
			}
			if ((!((Object)(object)__instance.human != (Object)null) || !ArrestReactions.Surrendering.Contains((Actor)(object)__instance.human)) && Roll.NextDouble() < (double)InspectorConfig.BystanderFleeChance.Value)
			{
				__instance.inFleeState = true;
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(51, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Bystander flees instead of attacking the player.");
				}
				logger.LogDebug(val);
			}
			__instance.CancelCombat();
			return false;
		}
	}
	[HarmonyPatch(typeof(NewAIController), "MovementUpdate")]
	internal static class NewAIController_MovementUpdate_Patch
	{
		[HarmonyPrefix]
		private static bool Prefix(NewAIController __instance)
		{
			return !ArrestReactions.IsHardFrozen((Actor)(object)__instance.human);
		}

		[HarmonyPostfix]
		private static void Postfix(NewAIController __instance)
		{
			if (!InspectorConfig.CivilianReactionsEnabled.Value)
			{
				return;
			}
			if (!InspectorConfig.RedHandedMurderException.Value || !ArrestReactions.IsRedHandedMurderer(__instance))
			{
				Actor attackTarget = __instance.attackTarget;
				if ((Object)(object)attackTarget != (Object)null && attackTarget.isPlayer)
				{
					__instance.CancelCombat();
				}
			}
			ArrestReactions.TickActor(__instance);
		}
	}
	internal static class GameSession
	{
		internal static string InstanceId
		{
			get
			{
				try
				{
					if ((Object)(object)CityData.Instance == (Object)null)
					{
						return null;
					}
					string currentGameInstanceID = CityData.Instance.GetCurrentGameInstanceID();
					return string.IsNullOrWhiteSpace(currentGameInstanceID) ? null : currentGameInstanceID;
				}
				catch
				{
					return null;
				}
			}
		}

		internal static string StillLoading()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CityConstructor instance = CityConstructor.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					if (instance.loadingOperationActive)
					{
						return $"the loader is still running, state {instance.loadState}";
					}
					if (instance.preSimActive)
					{
						return "the pre-simulation is still running";
					}
					if (!instance.isLoaded)
					{
						return "the city loader has not reported the city as loaded";
					}
				}
			}
			catch
			{
			}
			try
			{
				SessionData instance2 = SessionData.Instance;
				if ((Object)(object)instance2 != (Object)null && !instance2.startedGame)
				{
					return "the session has not started the game yet";
				}
			}
			catch
			{
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(FirstPersonItemController), "OnConsumableFinished")]
	internal static class CigaretteRefillPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(Interactable consumableFinished)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			if (!InventoryConfig.Enabled.Value || !InventoryConfig.InfiniteUseEnabled.Value)
			{
				return true;
			}
			if (consumableFinished == null)
			{
				return true;
			}
			if (!SlotConfig.TrackedSlots.TryGetValue(SlotConfig.LockedItem.Cigarettes, out var value) || value == null)
			{
				return true;
			}
			Interactable interactable = value.GetInteractable();
			if (interactable == null || interactable.id != consumableFinished.id)
			{
				return true;
			}
			try
			{
				float num = (((SoCustomComparison)(object)consumableFinished.preset != (SoCustomComparison)null) ? consumableFinished.preset.consumableAmount : 1f);
				consumableFinished.SetExtraStateValue(num, true);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(37, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Inventory] Cigarette refill failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				logger.LogError(val);
			}
			return false;
		}
	}
	internal static class LockedSlotRefiller
	{
		internal static void RefillIfEmpty(FirstPersonItemController controller, SlotConfig.LockedItem item)
		{
			if (!InventoryConfig.Enabled.Value || !InventoryConfig.InfiniteUseEnabled.Value || !SlotConfig.TrackedSlots.TryGetValue(item, out var value) || value == null || ItemFactory.IsSlotFilled(value))
			{
				return;
			}
			SlotConfig.LockedItemDef lockedItemDef = SlotConfig.Find(item);
			if (lockedItemDef != null)
			{
				Player val;
				try
				{
					val = ((Component)controller).GetComponent<Player>();
				}
				catch
				{
					val = null;
				}
				if (!((Object)(object)val == (Object)null))
				{
					ItemFactory.FillSlot(controller, val, value, lockedItemDef);
				}
			}
		}
	}
	[HarmonyPatch(typeof(FirstPersonItemController), "PlaceDoorWedge")]
	internal static class DoorWedgeRefillPatch
	{
		[HarmonyPostfix]
		private static void Postfix(FirstPersonItemController __instance)
		{
			LockedSlotRefiller.RefillIfEmpty(__instance, SlotConfig.LockedItem.DoorStopper);
		}
	}
	[HarmonyPatch(typeof(FirstPersonItemController), "PlaceCodebreaker")]
	internal static class CodebreakerRefillPatch
	{
		[HarmonyPostfix]
		private static void Postfix(FirstPersonItemController __instance)
		{
			LockedSlotRefiller.RefillIfEmpty(__instance, SlotConfig.LockedItem.Codebreaker);
		}
	}
	internal static class InspectorConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> CivilianReactionsEnabled;

		internal static ConfigEntry<float> BystanderFleeChance;

		internal static ConfigEntry<bool> RedHandedMurderException;

		internal static ConfigEntry<bool> SurrenderHardFreeze;

		internal static ConfigEntry<float> SurrenderReleaseDistance;

		internal static ConfigEntry<float> GawkRadius;

		internal static ConfigEntry<float> GawkReleaseDistance;

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "When true, the player is immune to all illegal-status detection (trespassing, assault, theft, breaking and entering, tampering, vandalism) and is never targeted/investigated by security cameras or sentry turrets.");
			CivilianReactionsEnabled = config.Bind<bool>("CivilianReactions", "Enabled", true, "When true, anyone the player hits surrenders instead of fighting back, and nearby witnesses never attack the player either.");
			BystanderFleeChance = config.Bind<float>("CivilianReactions", "BystanderFleeChance", 0.3f, "Fraction (0-1) of nearby witnesses who flee instead of just watching when the player hits someone.");
			RedHandedMurderException = config.Bind<bool>("CivilianReactions", "RedHandedMurderException", true, "When true, a murderer caught actively committing a murder keeps vanilla fight/flee behavior instead of surrendering.");
			SurrenderHardFreeze = config.Bind<bool>("CivilianReactions", "SurrenderHardFreeze", true, "When true, a surrendering NPC's movement tick is suppressed entirely so they kneel where they stand instead of running off with their arms up. Turn off to fall back to the softer freeze if the hard hold ever looks wrong.");
			SurrenderReleaseDistance = config.Bind<float>("CivilianReactions", "SurrenderReleaseDistance", 10f, "How far away (in meters) the player has to get from a surrendering NPC before they get up and resume normal behavior.");
			GawkRadius = config.Bind<float>("CivilianReactions", "GawkRadius", 15f, "Radius (in meters) around the player, at the moment an arrest is initiated, within which civilians turn to gawk at the player.");
			GawkReleaseDistance = config.Bind<float>("CivilianReactions", "GawkReleaseDistance", 20f, "How far away (in meters) the player has to get from a gawking civilian before they resume normal behavior.");
		}
	}
	internal static class InventoryConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> InfiniteUseEnabled;

		internal static ConfigEntry<int> ModularSlotCount;

		internal static ConfigEntry<bool> SwapInventoryRows;

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("Inventory", "Enabled", true, "Master switch for the inventory overhaul: 9 locked tool slots (keys 1-9) plus a resized modular row.");
			InfiniteUseEnabled = config.Bind<bool>("Inventory", "InfiniteUseEnabled", true, "When true, the 9 locked tool slots can never be dropped, and consumable ones (cigarettes, door stopper, code breaker) refill instantly on use.");
			ModularSlotCount = config.Bind<int>("Inventory", "ModularSlotCount", 6, "Number of free/modular inventory slots (vanilla default is 4).");
			SwapInventoryRows = config.Bind<bool>("Inventory", "SwapInventoryRows", true, "When true, the modular row renders above the locked tool row in the inventory screen instead of below it.");
		}
	}
	[HarmonyPatch(typeof(FirstPersonItemController), "Start")]
	internal static class InventorySetupStartPatch
	{
		[HarmonyPostfix]
		private static void Postfix(FirstPersonItemController __instance)
		{
			InventorySetup.Ensure(__instance);
		}
	}
	[HarmonyPatch(typeof(FirstPersonItemController), "Update")]
	internal static class InventorySetupUpdatePatch
	{
		[HarmonyPostfix]
		private static void Postfix(FirstPersonItemController __instance)
		{
			InventorySetup.Ensure(__instance);
		}
	}
	internal static class InventorySetup
	{
		private const int SettleFrames = 180;

		private const int StableFrames = 150;

		private const int MaxWaitFrames = 1800;

		private const int ResizeDelayFrames = 30;

		private static FirstPersonItemController _boundController;

		private static string _sessionId;

		private static int _frames;

		private static int _sizeRequest;

		private static int _lastSlotCount;

		private static int _stableSince;

		private static int _discrepancyFrames;

		private static bool _setupStarted;

		private static bool _loggedComplete;

		private static bool _loggedDiagnostic;

		internal static void Ensure(FirstPersonItemController controller)
		{
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Expected O, but got Unknown
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Expected O, but got Unknown
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a6: Expected O, but got Unknown
			//IL_0569: Unknown result type (might be due to invalid IL or missing references)
			//IL_0570: Expected O, but got Unknown
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_051e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Expected O, but got Unknown
			//IL_060e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0615: Expected O, but got Unknown
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Expected O, but got Unknown
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			if (!InventoryConfig.Enabled.Value || (Object)(object)controller == (Object)null)
			{
				return;
			}
			Player val;
			try
			{
				val = ((Component)controller).GetComponent<Player>();
			}
			catch
			{
				val = null;
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			string instanceId = GameSession.InstanceId;
			if (instanceId == null)
			{
				return;
			}
			if ((Object)(object)_boundController != (Object)(object)controller || _sessionId != instanceId)
			{
				_boundController = controller;
				_sessionId = instanceId;
				SlotConfig.Reset();
				ItemFactory.ResetSession();
				_frames = 0;
				_sizeRequest = 0;
				_lastSlotCount = -1;
				_stableSince = 0;
				_discrepancyFrames = 0;
				_setupStarted = false;
				_loggedComplete = false;
				_loggedDiagnostic = false;
			}
			if (_frames++ < 180)
			{
				return;
			}
			bool flag = default(bool);
			if (!_setupStarted)
			{
				int num = ((controller.slots != null) ? controller.slots.Count : 0);
				if (num != _lastSlotCount)
				{
					_lastSlotCount = num;
					_stableSince = _frames;
				}
				if (_frames - _stableSince < 150 && _frames < 1800)
				{
					return;
				}
				_setupStarted = true;
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(70, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Inventory] Slot list settled at ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" slots after ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_frames);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" frames; starting setup.");
				}
				logger.LogInfo(val2);
			}
			ItemFactory.LogPresetDumpOnce();
			ItemFactory.CurrentFrame = _frames;
			try
			{
				int num2 = ItemFactory.PurgeOrphanedRuntimeItems(controller, val);
				if (num2 > 0)
				{
					ManualLogSource logger2 = Plugin.Logger;
					BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(64, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[Inventory] Purged ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num2);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" orphaned runtime items from Actor.inventory.");
					}
					logger2.LogWarning(val3);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger3 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Inventory] Purge failed: ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex);
				}
				logger3.LogError(val4);
			}
			int num3 = SlotConfig.ReservedCount();
			int num4 = InventoryConfig.ModularSlotCount.Value + num3;
			try
			{
				int num5 = ItemFactory.CountNonStaticSlots(controller);
				if (num5 != num4)
				{
					if (++_discrepancyFrames >= 30)
					{
						_discrepancyFrames = 0;
						if (_sizeRequest == 0)
						{
							_sizeRequest = num4;
						}
						_sizeRequest += num4 - num5;
						if (_sizeRequest < 1)
						{
							_sizeRequest = 1;
						}
						if (_sizeRequest > 40)
						{
							_sizeRequest = 40;
						}
						controller.SetSlotSize(_sizeRequest);
					}
				}
				else
				{
					_discrepancyFrames = 0;
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource logger4 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(32, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Inventory] SetSlotSize failed: ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex2);
				}
				logger4.LogError(val4);
			}
			StaticSlot[] unwantedNativeStatics = SlotConfig.UnwantedNativeStatics;
			foreach (StaticSlot val5 in unwantedNativeStatics)
			{
				try
				{
					if (ItemFactory.FindStaticSlot(controller, val5) != null)
					{
						controller.RemoveSpecificStaticSlot(val5);
					}
				}
				catch (Exception ex3)
				{
					ManualLogSource logger5 = Plugin.Logger;
					BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(32, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Inventory] Removing '");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<StaticSlot>(val5);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("' failed: ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex3);
					}
					logger5.LogError(val4);
				}
			}
			if (SlotConfig.DeselectSlot == null || !ItemFactory.SlotStillExists(controller, SlotConfig.DeselectSlot))
			{
				SlotConfig.DeselectSlot = ItemFactory.FindHolsterSlot(controller);
			}
			if (SlotConfig.DeselectSlot != null && SlotConfig.DeselectSlot.hotkey != "0")
			{
				SlotConfig.DeselectSlot.hotkey = "0";
			}
			bool flag2 = true;
			SlotConfig.LockedItemDef[] items = SlotConfig.Items;
			foreach (SlotConfig.LockedItemDef lockedItemDef in items)
			{
				try
				{
					if (!EnsureItem(controller, val, lockedItemDef))
					{
						flag2 = false;
					}
				}
				catch (Exception ex4)
				{
					ManualLogSource logger6 = Plugin.Logger;
					BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(33, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Inventory] Setup for '");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<SlotConfig.LockedItem>(lockedItemDef.Item);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("' failed: ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex4);
					}
					logger6.LogError(val4);
				}
			}
			try
			{
				int num6 = ItemFactory.DeduplicateAgainstReserved(controller, val);
				if (num6 > 0)
				{
					ManualLogSource logger7 = Plugin.Logger;
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(77, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Inventory] Cleared ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num6);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" duplicate slot reference(s) restored by the save loader.");
					}
					logger7.LogInfo(val2);
				}
			}
			catch (Exception ex5)
			{
				ManualLogSource logger8 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(27, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Inventory] Dedupe failed: ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex5);
				}
				logger8.LogError(val4);
			}
			if (!flag2 && !_loggedDiagnostic && _frames > 1080)
			{
				_loggedDiagnostic = true;
				Plugin.Logger.LogWarning((object)"[Inventory] Setup incomplete; dumping state.");
				DumpSlots(controller, "incomplete");
				ItemFactory.DumpInventoryList(val);
			}
			if (flag2 && !_loggedComplete)
			{
				_loggedComplete = true;
				ManualLogSource logger9 = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(68, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Inventory] Setup complete: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(SlotConfig.TrackedSlots.Count);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("/");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(SlotConfig.Items.Length);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" tools, nonStatic=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(ItemFactory.CountNonStaticSlots(controller));
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (reserved ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num3);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" + free ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(InventoryConfig.ModularSlotCount.Value);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(").");
				}
				logger9.LogInfo(val2);
				DumpSlots(controller, "post-setup");
				ItemFactory.DumpInventoryList(val);
			}
		}

		private static bool EnsureItem(FirstPersonItemController controller, Player player, SlotConfig.LockedItemDef def)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			SlotConfig.TrackedSlots.TryGetValue(def.Item, out var value);
			if (value != null && !ItemFactory.SlotStillExists(controller, value))
			{
				SlotConfig.Untrack(def.Item, value);
				value = null;
			}
			if (value == null)
			{
				if (def.NativeStatic.HasValue)
				{
					value = ItemFactory.FindStaticSlot(controller, def.NativeStatic.Value) ?? controller.AddSpecificStaticSlot(def.NativeStatic.Value);
				}
				else
				{
					InteractablePreset preset = ItemFactory.ResolvePreset(def);
					value = ItemFactory.FindSlotHoldingPreset(controller, preset, null) ?? ItemFactory.ClaimReservedSlot(controller);
				}
				if (value == null)
				{
					return false;
				}
				value.hotkey = def.Hotkey;
				SlotConfig.Track(def.Item, value);
			}
			if (value.hotkey != def.Hotkey)
			{
				value.hotkey = def.Hotkey;
			}
			if (def.NativeStatic.HasValue)
			{
				return true;
			}
			if (ItemFactory.IsSlotFilled(value))
			{
				return true;
			}
			return ItemFactory.FillSlot(controller, player, value, def);
		}

		internal static void DumpSlots(FirstPersonItemController controller, string label)
		{
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Expected O, but got Unknown
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			bool flag = default(bool);
			try
			{
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(53, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Inventory] --- slot dump [");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(label);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(controller.slots.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" slots, nonStatic=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(ItemFactory.CountNonStaticSlots(controller));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") ---");
				}
				logger.LogInfo(val);
				for (int i = 0; i < controller.slots.Count; i++)
				{
					InventorySlot val2 = controller.slots[i];
					if (val2 == null)
					{
						ManualLogSource logger2 = Plugin.Logger;
						val = new BepInExInfoLogInterpolatedStringHandler(11, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  [");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(i);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] <null>");
						}
						logger2.LogInfo(val);
						continue;
					}
					Interactable interactable = val2.GetInteractable();
					InventorySquareController spawnedSegment = val2.spawnedSegment;
					string text = "no-segment";
					if ((Object)(object)spawnedSegment != (Object)null)
					{
						text = (((Object)(object)((Component)spawnedSegment).transform.parent != (Object)null) ? $"{((Object)((Component)spawnedSegment).transform.parent).name}#{((Component)spawnedSegment).transform.GetSiblingIndex()}" : "no-parent");
					}
					string text2 = ((interactable == null) ? "<lookup null>" : (((SoCustomComparison)(object)interactable.preset == (SoCustomComparison)null) ? "<no preset>" : ((Object)interactable.preset).name));
					string text3 = (SlotConfig.LockedSlots.Contains(val2) ? " RESERVED" : "");
					ManualLogSource logger3 = Plugin.Logger;
					val = new BepInExInfoLogInterpolatedStringHandler(43, 7, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  [");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(i);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] isStatic=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<StaticSlot>(val2.isStatic);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" hotkey='");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(val2.hotkey);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' id=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(val2.interactableID);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" item=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" segment=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text3);
					}
					logger3.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger4 = Plugin.Logger;
				BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(30, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[Inventory] Slot dump failed: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
				}
				logger4.LogWarning(val3);
			}
		}
	}
	internal static class ItemFactory
	{
		private static bool _dumpedPresetNames;

		internal const int RuntimeIdFloor = 100000000;

		private const int MaxTotalGrants = 40;

		private const int MaxGrantsPerItem = 2;

		private const int GrantCooldownFrames = 150;

		private static int _totalGrants;

		private static readonly Dictionary<SlotConfig.LockedItem, int> LastGrantFrame = new Dictionary<SlotConfig.LockedItem, int>();

		private static readonly Dictionary<SlotConfig.LockedItem, int> GrantCount = new Dictionary<SlotConfig.LockedItem, int>();

		private static readonly HashSet<SlotConfig.LockedItem> CapWarned = new HashSet<SlotConfig.LockedItem>();

		internal static int CurrentFrame;

		internal static void LogPresetDumpOnce()
		{
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			if (_dumpedPresetNames)
			{
				return;
			}
			Toolbox instance = Toolbox.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			_dumpedPresetNames = true;
			bool flag = default(bool);
			try
			{
				Dictionary<string, InteractablePreset> objectPresetDictionary = instance.objectPresetDictionary;
				if (objectPresetDictionary == null)
				{
					return;
				}
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(72, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Inventory] objectPresetDictionary has ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(objectPresetDictionary.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" entries. Resolving target items:");
				}
				logger.LogInfo(val);
				SlotConfig.LockedItemDef[] items = SlotConfig.Items;
				foreach (SlotConfig.LockedItemDef lockedItemDef in items)
				{
					if (lockedItemDef.PresetNameCandidates != null)
					{
						InteractablePreset val2 = ResolvePreset(lockedItemDef);
						ManualLogSource logger2 = Plugin.Logger;
						val = new BepInExInfoLogInterpolatedStringHandler(8, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  - ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<SlotConfig.LockedItem>(lockedItemDef.Item);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((SoCustomComparison)(object)val2 != (SoCustomComparison)null) ? ((Object)val2).name : "UNRESOLVED");
						}
						logger2.LogInfo(val);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger3 = Plugin.Logger;
				BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(32, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[Inventory] Preset dump failed: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
				}
				logger3.LogWarning(val3);
			}
		}

		internal static InteractablePreset ResolvePreset(SlotConfig.LockedItemDef def)
		{
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			Toolbox instance = Toolbox.Instance;
			if ((Object)(object)instance == (Object)null || def.PresetNameCandidates == null)
			{
				return null;
			}
			Dictionary<string, InteractablePreset> objectPresetDictionary = instance.objectPresetDictionary;
			if (objectPresetDictionary == null)
			{
				return null;
			}
			string[] presetNameCandidates = def.PresetNameCandidates;
			InteractablePreset val = default(InteractablePreset);
			foreach (string text in presetNameCandidates)
			{
				if (objectPresetDictionary.TryGetValue(text, ref val) && (SoCustomComparison)(object)val != (SoCustomComparison)null)
				{
					return val;
				}
			}
			bool flag = default(bool);
			if (def.FallbackKeywords != null)
			{
				Enumerator<string, InteractablePreset> enumerator = objectPresetDictionary.GetEnumerator();
				while (enumerator.MoveNext())
				{
					KeyValuePair<string, InteractablePreset> current = enumerator.Current;
					string key = current.Key;
					if (key == null)
					{
						continue;
					}
					string text2 = key.ToLowerInvariant();
					string[] fallbackKeywords = def.FallbackKeywords;
					foreach (string value in fallbackKeywords)
					{
						if (text2.Contains(value))
						{
							ManualLogSource logger = Plugin.Logger;
							BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(68, 2, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Inventory] '");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<SlotConfig.LockedItem>(def.Item);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' preset not found by exact name; using fuzzy match '");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(key);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'.");
							}
							logger.LogWarning(val2);
							return current.Value;
						}
					}
				}
			}
			ManualLogSource logger2 = Plugin.Logger;
			BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(74, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[Inventory] Could not resolve a preset for '");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<SlotConfig.LockedItem>(def.Item);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' - that slot will stay empty.");
			}
			logger2.LogError(val3);
			return null;
		}

		internal static bool IsSlotFilled(InventorySlot slot)
		{
			if (slot == null || slot.interactableID == -1)
			{
				return false;
			}
			try
			{
				return slot.GetInteractable() != null;
			}
			catch
			{
				return false;
			}
		}

		internal static InventorySlot FindSlotHoldingId(FirstPersonItemController controller, int id)
		{
			if (((controller != null) ? controller.slots : null) == null)
			{
				return null;
			}
			for (int i = 0; i < controller.slots.Count; i++)
			{
				InventorySlot val = controller.slots[i];
				if (val != null && val.interactableID == id)
				{
					return val;
				}
			}
			return null;
		}

		internal static int DeduplicateAgainstReserved(FirstPersonItemController controller, Player player)
		{
			if (((controller != null) ? controller.slots : null) == null)
			{
				return 0;
			}
			HashSet<int> hashSet = new HashSet<int>();
			foreach (InventorySlot lockedSlot in SlotConfig.LockedSlots)
			{
				if (lockedSlot != null && lockedSlot.interactableID != -1)
				{
					hashSet.Add(lockedSlot.interactableID);
				}
			}
			int num = 0;
			for (int i = 0; i < controller.slots.Count; i++)
			{
				InventorySlot val = controller.slots[i];
				if (val != null && !SlotConfig.LockedSlots.Contains(val) && val != SlotConfig.DeselectSlot)
				{
					bool flag = val.interactableID != -1 && hashSet.Contains(val.interactableID);
					if (flag)
					{
						val.interactableID = -1;
						num++;
					}
					if (!string.IsNullOrEmpty(val.hotkey))
					{
						val.hotkey = "";
					}
					if (flag && (Object)(object)val.spawnedSegment != (Object)null)
					{
						val.spawnedSegment.OnUpdateContent();
					}
				}
			}
			List<Interactable> val2 = ((player != null) ? ((Actor)player).inventory : null);
			if (val2 != null)
			{
				HashSet<int> hashSet2 = new HashSet<int>();
				for (int num2 = val2.Count - 1; num2 >= 0; num2--)
				{
					Interactable val3 = val2[num2];
					if (val3 == null)
					{
						val2.RemoveAt(num2);
					}
					else if (!hashSet2.Add(val3.id))
					{
						val2.RemoveAt(num2);
					}
				}
			}
			return num;
		}

		internal static int PurgeOrphanedRuntimeItems(FirstPersonItemController controller, Player player)
		{
			if ((Object)(object)player == (Object)null || ((controller != null) ? controller.slots : null) == null)
			{
				return 0;
			}
			List<Interactable> inventory = ((Actor)player).inventory;
			if (inventory == null)
			{
				return 0;
			}
			int num = 0;
			for (int num2 = inventory.Count - 1; num2 >= 0; num2--)
			{
				Interactable val = inventory[num2];
				if (val == null)
				{
					inventory.RemoveAt(num2);
					num++;
				}
				else if (val.id >= 100000000 && FindSlotHoldingId(controller, val.id) == null)
				{
					inventory.RemoveAt(num2);
					num++;
				}
			}
			return num;
		}

		internal static InventorySlot FindHolsterSlot(FirstPersonItemController controller)
		{
			return FindStaticSlot(controller, (StaticSlot)1);
		}

		internal static InventorySlot ClaimReservedSlot(FirstPersonItemController controller)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			if (((controller != null) ? controller.slots : null) == null)
			{
				return null;
			}
			for (int num = controller.slots.Count - 1; num >= 0; num--)
			{
				InventorySlot val = controller.slots[num];
				if (val != null && (int)val.isStatic <= 0 && !SlotConfig.LockedSlots.Contains(val) && !IsSlotFilled(val))
				{
					return val;
				}
			}
			return null;
		}

		internal static void DumpInventoryList(Player player)
		{
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				List<Interactable> val = ((player != null) ? ((Actor)player).inventory : null);
				if (val == null)
				{
					Plugin.Logger.LogInfo((object)"[Inventory] Actor.inventory is null.");
					return;
				}
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(44, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Inventory] --- Actor.inventory (");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(val.Count);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" items) ---");
				}
				logger.LogInfo(val2);
				for (int i = 0; i < val.Count; i++)
				{
					Interactable val3 = val[i];
					ManualLogSource logger2 = Plugin.Logger;
					val2 = new BepInExInfoLogInterpolatedStringHandler(19, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("  inv[");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(i);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] id=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>((val3 != null) ? val3.id.ToString() : "null");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" preset=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((SoCustomComparison)(object)((val3 != null) ? val3.preset : null) != (SoCustomComparison)null) ? ((Object)val3.preset).name : "<none>");
					}
					logger2.LogInfo(val2);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger3 = Plugin.Logger;
				BepInExWarningLogInterpolatedStringHandler val4 = new BepInExWarningLogInterpolatedStringHandler(35, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Inventory] Inventory dump failed: ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex);
				}
				logger3.LogWarning(val4);
			}
		}

		internal static bool SlotStillExists(FirstPersonItemController controller, InventorySlot slot)
		{
			if (((controller != null) ? controller.slots : null) == null || slot == null)
			{
				return false;
			}
			for (int i = 0; i < controller.slots.Count; i++)
			{
				if (controller.slots[i] == slot)
				{
					return true;
				}
			}
			return false;
		}

		internal static int CountNonStaticSlots(FirstPersonItemController controller)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			if (((controller != null) ? controller.slots : null) == null)
			{
				return 0;
			}
			int num = 0;
			for (int i = 0; i < controller.slots.Count; i++)
			{
				InventorySlot val = controller.slots[i];
				if (val != null && (int)val.isStatic == 0)
				{
					num++;
				}
			}
			return num;
		}

		internal static InventorySlot FindStaticSlot(FirstPersonItemController controller, StaticSlot staticType)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (((controller != null) ? controller.slots : null) == null)
			{
				return null;
			}
			for (int i = 0; i < controller.slots.Count; i++)
			{
				InventorySlot val = controller.slots[i];
				if (val != null && val.isStatic == staticType)
				{
					return val;
				}
			}
			return null;
		}

		internal static InventorySlot FindSlotHoldingPreset(FirstPersonItemController controller, InteractablePreset preset, InventorySlot exclude)
		{
			if (((controller != null) ? controller.slots : null) == null || (SoCustomComparison)(object)preset == (SoCustomComparison)null)
			{
				return null;
			}
			for (int i = 0; i < controller.slots.Count; i++)
			{
				InventorySlot val = controller.slots[i];
				if (val != null && val != exclude && IsSlotFilled(val))
				{
					Interactable interactable = val.GetInteractable();
					if (interactable != null && (SoCustomComparison)(object)interactable.preset != (SoCustomComparison)null && ((Object)interactable.preset).name == ((Object)preset).name)
					{
						return val;
					}
				}
			}
			return null;
		}

		internal static void ResetSession()
		{
			_totalGrants = 0;
			CurrentFrame = 0;
			LastGrantFrame.Clear();
			GrantCount.Clear();
			CapWarned.Clear();
		}

		private static void RequestGrant(FirstPersonItemController controller, Player player, SlotConfig.LockedItemDef def, InteractablePreset preset)
		{
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Expected O, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Expected O, but got Unknown
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Expected O, but got Unknown
			if (_totalGrants >= 40)
			{
				WarnCapped(def, $"the session-wide grant cap of {40} has been reached");
				return;
			}
			GrantCount.TryGetValue(def.Item, out var value);
			if (value >= 2)
			{
				WarnCapped(def, $"it has already been granted {value} time(s) this session, the per-item cap");
				return;
			}
			LastGrantFrame.TryGetValue(def.Item, out var value2);
			if (value2 != 0 && CurrentFrame - value2 < 150)
			{
				return;
			}
			LastGrantFrame[def.Item] = CurrentFrame;
			GrantCount[def.Item] = value + 1;
			_totalGrants++;
			Interactable val = null;
			bool flag = default(bool);
			try
			{
				InteractableCreator instance = InteractableCreator.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				Vector3 position = ((Component)controller).transform.position;
				val = instance.CreateWorldInteractable(preset, (Human)(object)player, (Human)null, (Human)null, position, Vector3.zero, (List<Passed>)null, (Object)null, "");
				if (val == null)
				{
					ManualLogSource logger = Plugin.Logger;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(54, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[Inventory] '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<SlotConfig.LockedItem>(def.Item);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': CreateWorldInteractable returned null.");
					}
					logger.LogWarning(val2);
					return;
				}
				RegisterInLookups(val);
				bool flag2 = controller.PickUpItem(val, false, false, false, false, false);
				InventorySlot val3 = FindSlotHoldingId(controller, val.id);
				if (val3 != null && IsSlotFilled(val3))
				{
					ManualLogSource logger2 = Plugin.Logger;
					BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(56, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Inventory] '");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<SlotConfig.LockedItem>(def.Item);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("': granted ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(((Object)preset).name);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" (id=");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(val.id);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("); adopt pass will move it.");
					}
					logger2.LogInfo(val4);
					return;
				}
				ManualLogSource logger3 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val5 = new BepInExErrorLogInterpolatedStringHandler(82, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[Inventory] '");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<SlotConfig.LockedItem>(def.Item);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("': grant REJECTED (pickUp=");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<bool>(flag2);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(", landed=");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<bool>(val3 != null);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(", id=");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(val.id);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("). Deleting to avoid clutter.");
				}
				logger3.LogError(val5);
				TryDelete(val);
			}
			catch (Exception ex)
			{
				ManualLogSource logger4 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val5 = new BepInExErrorLogInterpolatedStringHandler(30, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[Inventory] '");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<SlotConfig.LockedItem>(def.Item);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("': grant failed: ");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<Exception>(ex);
				}
				logger4.LogError(val5);
				TryDelete(val);
			}
		}

		private static void WarnCapped(SlotConfig.LockedItemDef def, string why)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			if (CapWarned.Add(def.Item))
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(92, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Inventory] '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<SlotConfig.LockedItem>(def.Item);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': not granted because ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(why);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(". Its slot will stay empty for the rest of this session.");
				}
				logger.LogWarning(val);
			}
		}

		private static void RegisterInLookups(Interactable item)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			try
			{
				CityData instance = CityData.Instance;
				if (!((Object)(object)instance == (Object)null))
				{
					List<Interactable> interactableDirectory = instance.interactableDirectory;
					if (interactableDirectory != null && !interactableDirectory.Contains(item))
					{
						interactableDirectory.Add(item);
					}
					Dictionary<int, Interactable> savableInteractableDictionary = instance.savableInteractableDictionary;
					if (savableInteractableDictionary != null && !savableInteractableDictionary.ContainsKey(item.id))
					{
						savableInteractableDictionary.Add(item.id, item);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Inventory] Lookup registration failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				logger.LogWarning(val);
			}
		}

		private static void TryDelete(Interactable item)
		{
			if (item == null)
			{
				return;
			}
			try
			{
				item.SafeDelete(true);
			}
			catch
			{
			}
		}

		internal static bool FillSlot(FirstPersonItemController controller, Player player, InventorySlot slot, SlotConfig.LockedItemDef def)
		{
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			if (slot == null)
			{
				return false;
			}
			if (IsSlotFilled(slot))
			{
				return true;
			}
			InteractablePreset val = ResolvePreset(def);
			if ((SoCustomComparison)(object)val == (SoCustomComparison)null)
			{
				return false;
			}
			bool flag = default(bool);
			try
			{
				InventorySlot val2 = FindSlotHoldingPreset(controller, val, slot);
				if (val2 != null)
				{
					Interactable interactable = val2.GetInteractable();
					int interactableID = val2.interactableID;
					val2.interactableID = -1;
					if ((Object)(object)val2.spawnedSegment != (Object)null)
					{
						val2.spawnedSegment.OnUpdateContent();
					}
					AttachToSlot(slot, interactable, interactableID);
					if (IsSlotFilled(slot))
					{
						ManualLogSource logger = Plugin.Logger;
						BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(52, 3, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[Inventory] '");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<SlotConfig.LockedItem>(def.Item);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("': adopted ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)val).name);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" (id=");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(interactableID);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(") into its locked slot.");
						}
						logger.LogInfo(val3);
						return true;
					}
					slot.interactableID = -1;
					AttachToSlot(val2, interactable, interactableID);
					ManualLogSource logger2 = Plugin.Logger;
					BepInExWarningLogInterpolatedStringHandler val4 = new BepInExWarningLogInterpolatedStringHandler(73, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[Inventory] '");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<SlotConfig.LockedItem>(def.Item);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("': adopt of id=");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(interactableID);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" was rejected; returned to its original slot.");
					}
					logger2.LogWarning(val4);
					return false;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger3 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val5 = new BepInExErrorLogInterpolatedStringHandler(30, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[Inventory] '");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<SlotConfig.LockedItem>(def.Item);
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("': adopt failed: ");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<Exception>(ex);
				}
				logger3.LogError(val5);
				return false;
			}
			RequestGrant(controller, player, def, val);
			return false;
		}

		private static void AttachToSlot(InventorySlot slot, Interactable item, int id)
		{
			slot.interactableID = id;
			if (item != null)
			{
				slot.SetSegmentContent(item);
			}
			if (slot.interactableID != id)
			{
				slot.interactableID = id;
			}
			if ((Object)(object)slot.spawnedSegment != (Object)null)
			{
				slot.spawnedSegment.OnUpdateContent();
			}
		}
	}
	[HarmonyPatch(typeof(FirstPersonItemController), "EmptySlot")]
	internal static class LockedSlotGuardPatches
	{
		[HarmonyPrefix]
		private static bool Prefix(InventorySlot emptySlot)
		{
			if (!InventoryConfig.Enabled.Value || !InventoryConfig.InfiniteUseEnabled.Value)
			{
				return true;
			}
			if (emptySlot != null && SlotConfig.LockedSlots.Contains(emptySlot))
			{
				return false;
			}
			return true;
		}
	}
	internal static class Office
	{
		internal static NewRoom Room;

		internal static NewBuilding CityHall;

		internal static NewAddress CityHallAddress;

		internal static NewAddress OfficeAddress;

		private static string _originalAddressName;

		private static bool _loggedRename;

		internal static FurnitureLocation Desk;

		internal static Interactable Computer;

		internal static InteractablePreset ComputerPreset;

		internal static SubObject ComputerSlot;

		internal static bool Built;

		private const int MaxBuildAttempts = 3;

		private const int RetryCooldownFrames = 180;

		private static int _buildAttempts;

		private static int _retryAt;

		private static bool _gaveUp;

		private static string _cachedRoomName;

		private static string _cachedRoomNameSource;

		internal static ManualLogSource Log => Plugin.Logger;

		internal static void Reset()
		{
			Room = null;
			CityHall = null;
			CityHallAddress = null;
			OfficeAddress = null;
			_originalAddressName = null;
			_loggedRename = false;
			Desk = null;
			Computer = null;
			ComputerPreset = null;
			ComputerSlot = null;
			Built = false;
			_buildAttempts = 0;
			_retryAt = 0;
			_gaveUp = false;
			_cachedRoomName = null;
			_cachedRoomNameSource = null;
			OfficeBuilder.ResetSession();
		}

		internal static string RoomName()
		{
			string text = OfficeConfig.TitleWord + "\u0001" + (((Object)(object)Player.Instance != (Object)null) ? ((Human)Player.Instance).GetCitizenName() : "");
			if (_cachedRoomName == null || _cachedRoomNameSource != text)
			{
				_cachedRoomName = OfficeConfig.OfficeRoomName();
				_cachedRoomNameSource = text;
			}
			return _cachedRoomName;
		}

		internal static bool IsOffice(NewRoom room)
		{
			return (Object)(object)room != (Object)null && (Object)(object)Room != (Object)null && ((Il2CppObjectBase)room).Pointer == ((Il2CppObjectBase)Room).Pointer;
		}

		internal static bool IsInCityHall(NewRoom room)
		{
			if ((Object)(object)room == (Object)null || (Object)(object)CityHall == (Object)null || (Object)(object)room.building == (Object)null)
			{
				return false;
			}
			return ((Il2CppObjectBase)room.building).Pointer == ((Il2CppObjectBase)CityHall).Pointer;
		}

		internal static void Build(int frame)
		{
			//IL_046d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Expected O, but got Unknown
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Expected O, but got Unknown
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Expected O, but got Unknown
			if (Built || _gaveUp || frame < _retryAt)
			{
				return;
			}
			_retryAt = frame + 180;
			bool flag = default(bool);
			if (_buildAttempts >= 3)
			{
				_gaveUp = true;
				ManualLogSource log = Log;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(87, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Office setup failed ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(3);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" times; giving up for this session rather than retrying forever.");
				}
				log.LogError(val);
				return;
			}
			_buildAttempts++;
			try
			{
				OfficeLocator.Result result = OfficeLocator.Locate();
				if (_buildAttempts == 1 || (Object)(object)result.Office != (Object)null)
				{
					OfficeLocator.LogSurvey(result);
				}
				if ((Object)(object)result.Office == (Object)null)
				{
					ManualLogSource log2 = Log;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(51, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Office setup attempt ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_buildAttempts);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" found no room to convert. ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(result.Failure);
					}
					log2.LogError(val);
					return;
				}
				string text = OfficeLocator.RejectReason(result.Office);
				if (text != null && !result.OfficeWasPinned)
				{
					ManualLogSource log3 = Log;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(116, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Refusing to convert ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(DescribeRoom(result.Office));
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" - ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(". Nothing was modified. Pin a suitable room with OfficeRoomNameContains or RoomIdOverride.");
					}
					log3.LogError(val);
					_gaveUp = true;
					return;
				}
				if (text != null)
				{
					ManualLogSource log4 = Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(98, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("CalebScott.TheInspector");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] The pinned office room would normally be rejected (");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("), but it was chosen by hand, so proceeding.");
					}
					log4.LogWarning(val2);
				}
				CityHall = result.Building;
				CityHallAddress = (((Object)(object)result.LobbyLocation != (Object)null) ? result.LobbyLocation.thisAsAddress : null);
				Room = result.Office;
				if (OfficeConfig.DryRun.Value)
				{
					Built = true;
					ManualLogSource log5 = Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(96, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("CalebScott.TheInspector");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] DryRun is on. Would have converted ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(DescribeRoom(Room));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" into '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(RoomName());
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'. Nothing was modified. Set DryRun=false to apply.");
					}
					log5.LogWarning(val2);
					return;
				}
				OfficeBuilder.ClearPreviousOccupant(Room);
				OfficeBuilder.PlaceDeskAndComputer(Room, result);
				OfficeWindows.Apply(Room, CityHall);
				OfficeBuilder.RegisterForDecorating(Room);
				ApplyRoomIdentity();
				Built = true;
				ManualLogSource log6 = Log;
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(44, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("] Office ready: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(RoomName());
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" (roomID ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(Room.roomID);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("). desk=");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>((Desk != null) ? "yes" : "no");
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" computer=");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>((Computer != null) ? ((Object)Computer.preset).name : "none");
				}
				log6.LogInfo(val3);
			}
			catch (Exception ex)
			{
				ManualLogSource log7 = Log;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(32, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Office setup attempt ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_buildAttempts);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" threw: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log7.LogError(val);
			}
		}

		internal static void Maintain()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			if (!Built || (Object)(object)Room == (Object)null || OfficeConfig.DryRun.Value)
			{
				return;
			}
			try
			{
				ApplyRoomIdentity();
				OfficeBuilder.RegisterForDecorating(Room);
				if (OfficeBuilder.TerminalNeedsAdoption)
				{
					OfficeBuilder.AdoptRealTerminalConfig();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(34, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Office maintenance pass threw: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
		}

		private static void ApplyRoomIdentity()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			if ((Object)(object)Room == (Object)null)
			{
				return;
			}
			string text = RoomName();
			if (Room.name != text)
			{
				Room.name = text;
				if (Room.name != text)
				{
					ManualLogSource log = Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(56, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Room name write rejected: wanted '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("', room reports '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Room.name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'.");
					}
					log.LogWarning(val);
				}
			}
			if (OfficeConfig.NameScope.Value == OfficeNameScope.Address)
			{
				ApplyAddressIdentity(text);
			}
		}

		private static void ApplyAddressIdentity(string wanted)
		{
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Expected O, but got Unknown
			NewAddress val = OfficeAddress;
			if ((Object)(object)val == (Object)null && (Object)(object)Room.gameLocation != (Object)null)
			{
				val = Room.gameLocation.thisAsAddress;
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			OfficeAddress = val;
			bool flag = default(bool);
			try
			{
				Company company = val.company;
				if (company != null && company.name != wanted)
				{
					if (_originalAddressName == null)
					{
						_originalAddressName = company.name;
					}
					company.name = wanted;
					company.shortName = wanted;
				}
				Evidence evidenceEntry = (Evidence)(object)((NewGameLocation)val).evidenceEntry;
				if (evidenceEntry != null && ((CaseComponent)evidenceEntry).name != wanted)
				{
					if (_originalAddressName == null)
					{
						_originalAddressName = ((CaseComponent)evidenceEntry).name;
					}
					((CaseComponent)evidenceEntry).name = wanted;
					evidenceEntry.AddOrSetCustomName((DataKey)0, wanted);
				}
				if (_loggedRename)
				{
					return;
				}
				_loggedRename = true;
				string text = ((val.company != null) ? val.company.name : "<no company>");
				string text2 = ((((NewGameLocation)val).evidenceEntry != null) ? ((CaseComponent)((NewGameLocation)val).evidenceEntry).name : "<no evidence>");
				ManualLogSource log = Log;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(89, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] Renamed the office location from '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(_originalAddressName);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("': company now '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("', evidence now '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text2);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'. Room reports '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Room.GetName());
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'.");
				}
				log.LogInfo(val2);
				if (text != wanted || text2 != wanted)
				{
					ManualLogSource log2 = Log;
					BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(96, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>("CalebScott.TheInspector");
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("] Location rename did not fully stick - wanted '");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(wanted);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("'. The map or door may still show the old name.");
					}
					log2.LogWarning(val3);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Log;
				BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(39, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("] Renaming the office location threw: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				log3.LogWarning(val3);
			}
		}

		internal static string DescribeRoom(NewRoom room)
		{
			if ((Object)(object)room == (Object)null)
			{
				return "<null room>";
			}
			string value = (((SoCustomComparison)(object)room.preset != (SoCustomComparison)null) ? ((Object)room.preset).name : "<no config>");
			string value2 = (((SoCustomComparison)(object)room.roomType != (SoCustomComparison)null) ? ((Object)room.roomType).name : "<no type>");
			int value3 = ((room.individualFurniture != null) ? room.individualFurniture.Count : (-1));
			int value4 = ((room.furniture != null) ? room.furniture.Count : (-1));
			return $"roomID={room.roomID} name='{room.name}' config='{value}' type='{value2}' furniture={value3} clusters={value4}";
		}

		internal static void DumpRoomContents(NewRoom room)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Expected O, but got Unknown
			if ((Object)(object)room == (Object)null)
			{
				return;
			}
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(20, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("--- contents of ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(DescribeRoom(room));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ---");
			}
			log.LogInfo(val);
			List<FurnitureLocation> individualFurniture = room.individualFurniture;
			if (individualFurniture != null)
			{
				for (int i = 0; i < individualFurniture.Count; i++)
				{
					FurnitureLocation val2 = individualFurniture[i];
					if (val2 != null)
					{
						string text = (((SoCustomComparison)(object)val2.furniture != (SoCustomComparison)null) ? ((Object)val2.furniture).name : "<no preset>");
						int num = ((val2.spawnedInteractables != null) ? val2.spawnedInteractables.Count : 0);
						int num2 = ((val2.integratedInteractables != null) ? val2.integratedInteractables.Count : 0);
						ManualLogSource log2 = Log;
						val = new BepInExInfoLogInterpolatedStringHandler(56, 6, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  furniture[");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(i);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] '");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' angle=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(val2.angle);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" userPlaced=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(val2.userPlaced);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" spawned=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" integrated=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num2);
						}
						log2.LogInfo(val);
					}
				}
			}
			List<Human> belongsTo = room.belongsTo;
			if (belongsTo != null && belongsTo.Count > 0)
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int j = 0; j < belongsTo.Count; j++)
				{
					if (!((Object)(object)belongsTo[j] == (Object)null))
					{
						if (stringBuilder.Length > 0)
						{
							stringBuilder.Append(", ");
						}
						stringBuilder.Append(belongsTo[j].GetCitizenName());
					}
				}
				ManualLogSource log3 = Log;
				val = new BepInExInfoLogInterpolatedStringHandler(19, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  room belongs to: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<StringBuilder>(stringBuilder);
				}
				log3.LogInfo(val);
			}
			else
			{
				Log.LogInfo((object)"  room belongs to: nobody");
			}
			foreach (Interactable item in EnumerateWorldObjects(room))
			{
				string text2 = (((SoCustomComparison)(object)item.preset != (SoCustomComparison)null) ? ((Object)item.preset).name : "<no preset>");
				string text3 = (((Object)(object)item.belongsTo != (Object)null) ? item.belongsTo.GetCitizenName() : "-");
				ManualLogSource log4 = Log;
				val = new BepInExInfoLogInterpolatedStringHandler(26, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  object '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' id=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(item.id);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" belongsTo=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text3);
				}
				log4.LogInfo(val);
			}
		}

		internal static List<NewNode> RoomNodes(NewRoom room)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			List<NewNode> list = new List<NewNode>();
			if ((Object)(object)room == (Object)null || room.nodes == null)
			{
				return list;
			}
			try
			{
				Enumerator<NewNode> enumerator = room.nodes.GetEnumerator();
				while (enumerator.MoveNext())
				{
					NewNode current = enumerator.Current;
					if (current != null)
					{
						list.Add(current);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(35, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Could not enumerate room.nodes: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
			return list;
		}

		internal static Vector3 RoomCentre(NewRoom room)
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			List<NewNode> list = RoomNodes(room);
			if (list.Count == 0)
			{
				return Vector3.zero;
			}
			Vector3 val = Vector3.zero;
			for (int i = 0; i < list.Count; i++)
			{
				val += list[i].position;
			}
			return val / (float)list.Count;
		}

		internal static List<Interactable> EnumerateWorldObjects(NewRoom room)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			List<Interactable> list = new List<Interactable>();
			if ((Object)(object)room == (Object)null || room.worldObjects == null)
			{
				return list;
			}
			try
			{
				Enumerator<Interactable> enumerator = room.worldObjects.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Interactable current = enumerator.Current;
					if (current != null)
					{
						list.Add(current);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(42, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Could not enumerate room.worldObjects: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
			return list;
		}
	}
	internal static class OfficeBuilder
	{
		private const int MaxSurplusTerminalDeletes = 8;

		private static string _lastPasswordLog;

		private const int ScanSliceSize = 4000;

		private static int _scanCursor;

		private static bool _terminalAdopted;

		private static bool _loggedAppRules;

		private const int MaxRepairsPerSession = 40;

		private static int _repairs;

		internal static bool TerminalNeedsAdoption => OfficeConfig.PlaceDesk.Value && !_terminalAdopted && Office.Computer != null;

		internal static void ResetSession()
		{
			_scanCursor = 0;
			_terminalAdopted = false;
			_loggedAppRules = false;
			_lastPasswordLog = null;
			_repairs = 0;
			OfficeWindows.ResetSession();
		}

		internal static bool IsAlreadyConverted(NewRoom room)
		{
			List<FurnitureLocation> individualFurniture = room.individualFurniture;
			if (individualFurniture != null)
			{
				for (int i = 0; i < individualFurniture.Count; i++)
				{
					if (individualFurniture[i] != null && individualFurniture[i].userPlaced)
					{
						return true;
					}
				}
			}
			return !string.IsNullOrEmpty(room.name) && room.name.EndsWith("'s Office", StringComparison.OrdinalIgnoreCase);
		}

		internal static void ClearPreviousOccupant(NewRoom room)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			bool flag = default(bool);
			if (!OfficeConfig.ClearExistingContents.Value)
			{
				ManualLogSource log = Office.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(79, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ClearExistingContents is off; leaving the room's original contents in place.");
				}
				log.LogInfo(val);
				return;
			}
			bool value = OfficeConfig.ForceClearOnce.Value;
			if (IsAlreadyConverted(room) && !value)
			{
				ManualLogSource log2 = Office.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(242, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] The office has already been converted in an earlier session; skipping the clear so the desk and anything the player has placed survive. If it still has the previous occupant's furniture in it, set ForceClearOnce=true to clear it once more.");
				}
				log2.LogInfo(val);
				return;
			}
			if (value)
			{
				ManualLogSource log3 = Office.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(91, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ForceClearOnce is set; clearing the office again. Furniture you placed yourself is kept.");
				}
				log3.LogInfo(val);
				ClearForceClearFlag();
			}
			RemovePersonalObjects(room);
			RemoveOccupantFurniture(room);
			TransferRoomOwnership(room);
		}

		private static void ClearForceClearFlag()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			try
			{
				OfficeConfig.ForceClearOnce.Value = false;
				if (OfficeConfig.File != null)
				{
					OfficeConfig.File.Save();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Office.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(133, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CalebScott.TheInspector");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Could not write ForceClearOnce back to the config file (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); set it to false by hand or the office will be re-cleared on every load.");
				}
				log.LogWarning(val);
			}
		}

		private static void RemovePersonalObjects(NewRoom room)
		{
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			HashSet<string> hashSet = ParsePresetNames(OfficeConfig.RemoveObjectPresets.Value);
			if (hashSet.Count == 0)
			{
				return;
			}
			List<Interactable> list = Office.EnumerateWorldObjects(room);
			int num = 0;
			int num2 = 0;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2;
			for (int i = 0; i < list.Count; i++)
			{
				Interactable val = list[i];
				if (val == null || (SoCustomComparison)(object)val.preset == (SoCustomComparison)null || !hashSet.Contains(((Object)val.preset).name.ToLowerInvariant()))
				{
					continue;
				}
				try
				{
					if (!val.IsSafeToDelete(false))
					{
						num2++;
						ManualLogSource log = Office.Log;
						val2 = new BepInExInfoLogInterpolatedStringHandler(107, 3, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("CalebScott.TheInspector");
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] Left '");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)val.preset).name);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' (id ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(val.id);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(") in place - the game reports it isn't safe to delete (it's referenced by a case or window).");
						}
						log.LogInfo(val2);
					}
					else
					{
						val.SafeDelete(false);
						num++;
					}
				}
				catch (Exception ex)
				{
					ManualLogSource log2 = Office.Log;
					BepInExWarningLogInte