Decompiled source of TheControlRoomFix v1.1.0

ControlRoomFix.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
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 Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using UnityEngine;

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

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ControlRoomFix
{
	[HarmonyPatch(typeof(CitizenCreator), "StartLoading")]
	internal static class CitizenGenerationPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (!Plugin.EnableCityHallGenerationFix.Value)
			{
				return;
			}
			try
			{
				CityHallGenerationFix.Apply();
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(50, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not prepare duplicate City Hall generation: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				logSource.LogError(val);
			}
		}
	}
	internal static class CityHallGenerationFix
	{
		private const string CityHallName = "CityHall";

		private static CompanyPreset? rememberedPreset;

		private static int originalMinimum;

		private static int originalMaximum;

		internal static void Apply()
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			CityData instance = CityData.Instance;
			if (((instance != null) ? instance.addressDirectory : null) == null)
			{
				Plugin.LogSource.LogWarning((object)"City Hall generation fix skipped because addresses are not ready.");
				return;
			}
			CompanyPreset val = null;
			int num = 0;
			for (int i = 0; i < instance.addressDirectory.Count; i++)
			{
				NewAddress val2 = instance.addressDirectory[i];
				if (IsCityHallCompanyAddress(val2))
				{
					num++;
					if (val == null)
					{
						val = val2.addressPreset.company;
					}
				}
			}
			if ((SoCustomComparison)(object)val == (SoCustomComparison)null || num == 0)
			{
				Plugin.LogSource.LogInfo((object)"City Hall generation fix found no eligible City Hall company addresses.");
				return;
			}
			RememberOriginalLimits(val);
			int num2 = Math.Max(originalMinimum, num);
			int num3 = Math.Max(originalMaximum, num);
			val.minimumNumber = num2;
			val.maximumNumber = num3;
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(92, 6, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("City Hall generation fix found ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" eligible addresses; ");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("'");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ControlRoomScanner.PresetName((Object)(object)val));
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' company limits ");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("changed from ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(originalMinimum);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("..");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(originalMaximum);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" to ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num2);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("..");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num3);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
			}
			logSource.LogInfo(val3);
		}

		internal static void LogResult()
		{
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			CityData instance = CityData.Instance;
			if (((instance != null) ? instance.addressDirectory : null) == null)
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < instance.addressDirectory.Count; i++)
			{
				NewAddress val = instance.addressDirectory[i];
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					NewBuilding building = ((NewGameLocation)val).building;
					obj = ((building != null) ? building.preset : null);
				}
				if ((SoCustomComparison)obj != (SoCustomComparison)null && ControlRoomScanner.PresetName((Object)(object)((NewGameLocation)val).building.preset).Equals("CityHall", StringComparison.OrdinalIgnoreCase))
				{
					hashSet.Add(((NewGameLocation)val).building.buildingID);
				}
				if (IsCityHallCompanyAddress(val))
				{
					num++;
					Company company = val.company;
					if ((SoCustomComparison)(object)((company != null) ? company.preset : null) != (SoCustomComparison)null && ControlRoomScanner.PresetName((Object)(object)company.preset).Equals("CityHall", StringComparison.OrdinalIgnoreCase))
					{
						num2++;
					}
				}
			}
			string text = ((num > 0 && num2 == num) ? "OK" : "BROKEN");
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(83, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] City Hall generation: buildings=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(hashSet.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("eligibleCompanyAddresses=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("assignedCompanies=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num2);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
			}
			logSource.LogInfo(val2);
		}

		private static bool IsCityHallCompanyAddress(NewAddress? address)
		{
			object obj;
			if (address == null)
			{
				obj = null;
			}
			else
			{
				NewBuilding building = ((NewGameLocation)address).building;
				obj = ((building != null) ? building.preset : null);
			}
			if ((SoCustomComparison)obj != (SoCustomComparison)null && ControlRoomScanner.PresetName((Object)(object)((NewGameLocation)address).building.preset).Equals("CityHall", StringComparison.OrdinalIgnoreCase))
			{
				AddressPreset addressPreset = address.addressPreset;
				if ((SoCustomComparison)(object)((addressPreset != null) ? addressPreset.company : null) != (SoCustomComparison)null)
				{
					return ControlRoomScanner.PresetName((Object)(object)address.addressPreset.company).Equals("CityHall", StringComparison.OrdinalIgnoreCase);
				}
			}
			return false;
		}

		private static void RememberOriginalLimits(CompanyPreset preset)
		{
			if (!((SoCustomComparison)(object)rememberedPreset == (SoCustomComparison)(object)preset))
			{
				rememberedPreset = preset;
				originalMinimum = preset.minimumNumber;
				originalMaximum = preset.maximumNumber;
			}
		}
	}
	[HarmonyPatch(typeof(InteriorCreator), "StartLoading")]
	internal static class InteriorGenerationPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			if (Plugin.DumpInteractablePipeline.Value)
			{
				InteractableCreationTrace.Phase = "interior-start";
				VanillaInteractableApiProbe.LogCityConstructorState();
				Plugin.LogSource.LogInfo((object)"[probe] InteriorCreator.StartLoading prefix; this is generateInteriors. Watch for later LoadObjects / CreateInteractables traces.");
			}
			if (!Plugin.EnableGenerationFix.Value)
			{
				return;
			}
			try
			{
				ControlRoomGenerationFix.Apply();
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(52, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not prepare ControlRoom furniture generation: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				logSource.LogError(val);
			}
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			if (Plugin.DumpInteractablePipeline.Value)
			{
				InteractableCreationTrace.Phase = "interior-end";
				Plugin.LogSource.LogInfo((object)"[probe] InteriorCreator.StartLoading postfix; interiors finished. The next vanilla object-load stage should follow if this is a new city.");
				VanillaInteractableApiProbe.LogCityConstructorState();
			}
		}
	}
	internal static class ControlRoomGenerationFix
	{
		private const string ControlRoomClassName = "ControlRoom";

		internal static void Apply()
		{
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			Toolbox instance = Toolbox.Instance;
			if (((instance != null) ? instance.allFurnitureClusters : null) == null)
			{
				Plugin.LogSource.LogWarning((object)"ControlRoom generation fix skipped because furniture presets are not ready.");
				return;
			}
			int num = 0;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val5;
			for (int i = 0; i < Toolbox.Instance.allFurnitureClusters.Count; i++)
			{
				FurnitureCluster val = Toolbox.Instance.allFurnitureClusters[i];
				if ((SoCustomComparison)(object)val == (SoCustomComparison)null || !val.skipIfNoAddressInhabitants || !TryGetControlRoomClass(val, out RoomClassPreset controlRoomClass) || (SoCustomComparison)(object)controlRoomClass == (SoCustomComparison)null)
				{
					continue;
				}
				FurnitureCluster val2 = val;
				if (val2.dontSkipNoInhabitantsIfIn == null)
				{
					List<RoomClassPreset> val3 = (val2.dontSkipNoInhabitantsIfIn = new List<RoomClassPreset>());
				}
				if (!ContainsRoomClass(val.dontSkipNoInhabitantsIfIn, "ControlRoom"))
				{
					val.dontSkipNoInhabitantsIfIn.Add(controlRoomClass);
					num++;
					ManualLogSource logSource = Plugin.LogSource;
					val5 = new BepInExInfoLogInterpolatedStringHandler(46, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("ControlRoom generation fix enabled cluster ");
						((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("'");
						((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<string>(ControlRoomScanner.PresetName((Object)(object)val));
						((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("'.");
					}
					logSource.LogInfo(val5);
				}
			}
			ManualLogSource logSource2 = Plugin.LogSource;
			val5 = new BepInExInfoLogInterpolatedStringHandler(56, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("ControlRoom generation fix prepared ");
				((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" furniture clusters.");
			}
			logSource2.LogInfo(val5);
		}

		private static bool TryGetControlRoomClass(FurnitureCluster cluster, out RoomClassPreset? controlRoomClass)
		{
			controlRoomClass = null;
			if (cluster.allowedRoomFilters == null)
			{
				return false;
			}
			for (int i = 0; i < cluster.allowedRoomFilters.Count; i++)
			{
				RoomTypeFilter obj = cluster.allowedRoomFilters[i];
				List<RoomClassPreset> val = ((obj != null) ? obj.roomClasses : null);
				if (val == null)
				{
					continue;
				}
				for (int j = 0; j < val.Count; j++)
				{
					RoomClassPreset val2 = val[j];
					if ((SoCustomComparison)(object)val2 != (SoCustomComparison)null && ControlRoomScanner.PresetName((Object)(object)val2).Equals("ControlRoom", StringComparison.OrdinalIgnoreCase))
					{
						controlRoomClass = val2;
						return true;
					}
				}
			}
			return false;
		}

		private static bool ContainsRoomClass(List<RoomClassPreset> classes, string className)
		{
			for (int i = 0; i < classes.Count; i++)
			{
				RoomClassPreset val = classes[i];
				if ((SoCustomComparison)(object)val != (SoCustomComparison)null && ControlRoomScanner.PresetName((Object)(object)val).Equals(className, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class ControlRoomScanner
	{
		private static readonly string[] EssentialNameParts = new string[6] { "crunch", "computer", "blueprint", "buildingplan", "residentfile", "residentrecord" };

		internal static void Run()
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			if (!IsCityReady())
			{
				Plugin.LogSource.LogWarning((object)"Skipped control-room scan because city loading or pre-simulation is still active.");
				return;
			}
			int num = 0;
			int num2 = 0;
			RoomConfiguration val = null;
			Enumerator<int, NewRoom> enumerator = CityData.Instance.roomDictionary.GetEnumerator();
			while (enumerator.MoveNext())
			{
				NewRoom value = enumerator.Current.Value;
				if (!((SoCustomComparison)(object)((value != null) ? value.preset : null) == (SoCustomComparison)null) && !(PresetName((Object)(object)value.preset) != "ControlRoom"))
				{
					num++;
					if (val == null)
					{
						val = value.preset;
					}
					if (LogRoom(value))
					{
						num2++;
					}
				}
			}
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(60, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Control-room scan complete: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num2);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("/");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" rooms lack essential contents.");
			}
			logSource.LogInfo(val2);
			if (Plugin.DumpEligiblePresets.Value && (SoCustomComparison)(object)val != (SoCustomComparison)null)
			{
				VanillaPresetScanner.Dump(val);
			}
		}

		private static bool IsCityReady()
		{
			if ((Object)(object)CityData.Instance != (Object)null && (Object)(object)CityConstructor.Instance != (Object)null && !CityConstructor.Instance.loadingOperationActive && !CityConstructor.Instance.preSimActive && CityConstructor.Instance.isLoaded && (Object)(object)SessionData.Instance != (Object)null)
			{
				return SessionData.Instance.startedGame;
			}
			return false;
		}

		private static bool LogRoom(NewRoom room)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Expected O, but got Unknown
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Expected O, but got Unknown
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			bool hasMicroCruncher = false;
			bool hasBlueprints = false;
			if (room.individualFurniture != null)
			{
				for (int i = 0; i < room.individualFurniture.Count; i++)
				{
					FurnitureLocation val = room.individualFurniture[i];
					if (!((SoCustomComparison)(object)((val != null) ? val.furniture : null) == (SoCustomComparison)null))
					{
						string item = PresetName((Object)(object)val.furniture);
						list.Add(item);
						AddInteractables(val.integratedInteractables, list2, ref hasMicroCruncher, ref hasBlueprints);
						AddInteractables(val.spawnedInteractables, list2, ref hasMicroCruncher, ref hasBlueprints);
					}
				}
			}
			if (room.worldObjects != null)
			{
				Enumerator<Interactable> enumerator = room.worldObjects.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Interactable current = enumerator.Current;
					if (!((SoCustomComparison)(object)((current != null) ? current.preset : null) == (SoCustomComparison)null))
					{
						list2.Add(PresetName((Object)(object)current.preset));
					}
				}
			}
			bool num = hasMicroCruncher && hasBlueprints;
			string text = (num ? "OK" : "BROKEN");
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(57, 6, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] ControlRoom roomID=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(room.roomID);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" name='");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(room.name);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("nodes=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(room.nodes?.Count ?? 0);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("furniture=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(list.Count);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" objects=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(list2.Count);
			}
			logSource.LogInfo(val2);
			LogScanCompany(room);
			ManualLogSource logSource2 = Plugin.LogSource;
			val2 = new BepInExInfoLogInterpolatedStringHandler(13, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("  furniture: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(JoinNames(list));
			}
			logSource2.LogInfo(val2);
			ManualLogSource logSource3 = Plugin.LogSource;
			val2 = new BepInExInfoLogInterpolatedStringHandler(11, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("  objects: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(JoinNames(list2));
			}
			logSource3.LogInfo(val2);
			return !num;
		}

		private static void LogScanCompany(NewRoom room)
		{
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			string text = "null";
			try
			{
				text = room.roomID.ToString();
			}
			catch
			{
				text = "null";
			}
			string text2 = "null";
			string text3 = "null";
			string text4 = "null";
			string text5 = "null";
			NewAddress val = null;
			try
			{
				val = (((Object)(object)room.gameLocation != (Object)null) ? ((Il2CppObjectBase)room.gameLocation).TryCast<NewAddress>() : null);
			}
			catch
			{
				val = null;
			}
			Company val2 = null;
			if ((Object)(object)val != (Object)null)
			{
				try
				{
					val2 = val.company;
				}
				catch
				{
					val2 = null;
				}
			}
			if (val2 != null)
			{
				try
				{
					text2 = val2.name ?? "null";
				}
				catch
				{
					text2 = "null";
				}
				try
				{
					text3 = val2.companyID.ToString();
				}
				catch
				{
					text3 = "null";
				}
				List<Occupation> val3 = null;
				try
				{
					val3 = val2.companyRoster;
				}
				catch
				{
					val3 = null;
				}
				if (val3 != null)
				{
					try
					{
						text4 = val3.Count.ToString();
					}
					catch
					{
						text4 = "null";
					}
				}
				try
				{
					text5 = val2.GetNumberOfFilledJobs().ToString();
				}
				catch
				{
					text5 = "null";
				}
			}
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(40, 5, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[scan] room=");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" company=");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text2);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" id=");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text3);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("posts=");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text4);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" filled=");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text5);
			}
			logSource.LogInfo(val4);
		}

		private static void AddInteractables(List<Interactable>? interactables, List<string> names, ref bool hasMicroCruncher, ref bool hasBlueprints)
		{
			if (interactables == null)
			{
				return;
			}
			for (int i = 0; i < interactables.Count; i++)
			{
				Interactable val = interactables[i];
				if (!((SoCustomComparison)(object)((val != null) ? val.preset : null) == (SoCustomComparison)null))
				{
					string text = PresetName((Object)(object)val.preset);
					names.Add(text);
					if (text == "MicroCruncher")
					{
						hasMicroCruncher = true;
					}
					if (text == "Blueprints")
					{
						hasBlueprints = true;
					}
				}
			}
		}

		private static bool IsEssential(string name)
		{
			string text = name.Replace("_", "").Replace(" ", "");
			for (int i = 0; i < EssentialNameParts.Length; i++)
			{
				if (text.IndexOf(EssentialNameParts[i], StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static string JoinNames(List<string> names)
		{
			if (names.Count == 0)
			{
				return "<none>";
			}
			names.Sort(StringComparer.OrdinalIgnoreCase);
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < names.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(", ");
				}
				stringBuilder.Append(names[i]);
			}
			return stringBuilder.ToString();
		}

		internal static string PresetName(Object preset)
		{
			if (!(preset != (Object)null))
			{
				return "<null>";
			}
			return preset.name ?? "<unnamed>";
		}
	}
	internal static class ExistingCityRepair
	{
		private static readonly string[] RequiredClusterNames = new string[3] { "DeskAgainstWall", "Shelf", "WallClock" };

		private static readonly string[] FilingCabinetClusterNames = new string[2] { "FilingCabinetTall", "FilingCabinetShort" };

		internal static void Run()
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			if ((Object)(object)GenerationController.Instance == (Object)null || (Object)(object)Toolbox.Instance == (Object)null)
			{
				Plugin.LogSource.LogWarning((object)"Existing-city repair skipped because generation systems are not ready.");
				return;
			}
			ControlRoomGenerationFix.Apply();
			int num = 0;
			Enumerator<int, NewRoom> enumerator = CityData.Instance.roomDictionary.GetEnumerator();
			while (enumerator.MoveNext())
			{
				NewRoom value = enumerator.Current.Value;
				if ((SoCustomComparison)(object)((value != null) ? value.preset : null) == (SoCustomComparison)null || !ControlRoomScanner.PresetName((Object)(object)value.preset).Equals("ControlRoom", StringComparison.OrdinalIgnoreCase) || HasMicroCruncher(value))
				{
					continue;
				}
				CreateMissingDeskInteractables(value);
				int num2 = 0;
				for (int i = 0; i < RequiredClusterNames.Length; i++)
				{
					if (TryAddMissingCluster(value, RequiredClusterNames[i]))
					{
						num2++;
					}
				}
				if (TryAddOneFilingCabinet(value))
				{
					num2++;
				}
				if (num2 > 0)
				{
					num++;
				}
			}
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Existing-city ControlRoom repair changed ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" rooms.");
			}
			logSource.LogInfo(val);
		}

		private static bool TryAddOneFilingCabinet(NewRoom room)
		{
			if (HasAnyFilingCabinet(room))
			{
				return false;
			}
			for (int i = 0; i < FilingCabinetClusterNames.Length; i++)
			{
				if (TryAddMissingCluster(room, FilingCabinetClusterNames[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static bool HasAnyFilingCabinet(NewRoom room)
		{
			for (int i = 0; i < FilingCabinetClusterNames.Length; i++)
			{
				if (HasCluster(room, FilingCabinetClusterNames[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static bool TryAddMissingCluster(NewRoom room, string clusterName)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Expected O, but got Unknown
			if (HasCluster(room, clusterName))
			{
				return false;
			}
			FurnitureCluster val = FindCluster(clusterName);
			bool flag = default(bool);
			if ((SoCustomComparison)(object)val == (SoCustomComparison)null)
			{
				ManualLogSource logSource = Plugin.LogSource;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(46, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Cannot repair room ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(room.roomID);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": cluster '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(clusterName);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' was not found.");
				}
				logSource.LogWarning(val2);
				return false;
			}
			bool flag2 = false;
			FurnitureClusterLocation bestFurnitureClusterLocation = GenerationController.Instance.GetBestFurnitureClusterLocation(room, val, false, false);
			if (bestFurnitureClusterLocation == null && clusterName == "DeskAgainstWall")
			{
				flag2 = true;
				bestFurnitureClusterLocation = GenerationController.Instance.GetBestFurnitureClusterLocation(room, val, false, true);
			}
			if (bestFurnitureClusterLocation == null)
			{
				ManualLogSource logSource2 = Plugin.LogSource;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(38, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("No valid '");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(clusterName);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' placement in ControlRoom ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(room.roomID);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
				}
				logSource2.LogWarning(val2);
				return false;
			}
			LogChosenFurniture(room, clusterName, bestFurnitureClusterLocation, "before-prefer");
			if (clusterName == "DeskAgainstWall")
			{
				PreferDeskPresetWithMicroCruncher(bestFurnitureClusterLocation);
			}
			ManualLogSource logSource3 = Plugin.LogSource;
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(62, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[repair-before-add] ControlRoom ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(room.roomID);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" cluster='");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(clusterName);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' ");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ignoreLimitations=");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<bool>(flag2);
			}
			logSource3.LogInfo(val3);
			room.AddFurniture(bestFurnitureClusterLocation, true, true, true, flag2, (DesignStylePreset)null);
			CreateInteractables(room, bestFurnitureClusterLocation);
			LogChosenFurniture(room, clusterName, bestFurnitureClusterLocation, "after-add");
			ManualLogSource logSource4 = Plugin.LogSource;
			val3 = new BepInExInfoLogInterpolatedStringHandler(25, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Added '");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(clusterName);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' to ControlRoom ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(room.roomID);
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(flag2 ? " using fallback placement" : "");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
			}
			logSource4.LogInfo(val3);
			return true;
		}

		private static void CreateInteractables(NewRoom room, FurnitureClusterLocation clusterLocation)
		{
			if (clusterLocation.clusterList == null)
			{
				return;
			}
			NewGameLocation gameLocation = room.gameLocation;
			NewAddress address = (NewAddress)(object)((gameLocation is NewAddress) ? gameLocation : null);
			for (int i = 0; i < clusterLocation.clusterList.Count; i++)
			{
				FurnitureLocation val = clusterLocation.clusterList[i];
				if (val != null)
				{
					CreateInteractables(val, address);
					SpawnedLayerFill.FillSpawnedLayer(val, room.roomID);
				}
			}
		}

		private static void CreateMissingDeskInteractables(NewRoom room)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			if (room.individualFurniture == null)
			{
				return;
			}
			NewGameLocation gameLocation = room.gameLocation;
			NewAddress address = (NewAddress)(object)((gameLocation is NewAddress) ? gameLocation : null);
			bool flag = default(bool);
			for (int i = 0; i < room.individualFurniture.Count; i++)
			{
				FurnitureLocation val = room.individualFurniture[i];
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					FurnitureClusterLocation cluster = val.cluster;
					obj = ((cluster != null) ? cluster.cluster : null);
				}
				if (!((SoCustomComparison)obj == (SoCustomComparison)null) && ControlRoomScanner.PresetName((Object)(object)val.cluster.cluster).Equals("DeskAgainstWall", StringComparison.OrdinalIgnoreCase) && !ContainsMicroCruncher(val.integratedInteractables) && (val.integratedInteractables?.Count ?? 0) <= 0)
				{
					Plugin.LogSource.LogInfo((object)($"[repair-before-existing-desk] ControlRoom {room.roomID} " + FurnitureInteractableAudit.Describe(val)));
					CreateInteractables(val, address);
					SpawnedLayerFill.FillSpawnedLayer(val, room.roomID);
					ManualLogSource logSource = Plugin.LogSource;
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(51, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Created missing desk interactables in ControlRoom ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(room.roomID);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
					}
					logSource.LogInfo(val2);
				}
			}
		}

		private static void CreateInteractables(FurnitureLocation furniture, NewAddress? address)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			if ((Object)(object)address != (Object)null)
			{
				furniture.AssignOwner(address, false);
			}
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(23, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[repair-before-create] ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(FurnitureInteractableAudit.Describe(furniture));
			}
			logSource.LogInfo(val);
			furniture.CreateInteractables();
			furniture.UpdateIntegratedObjectOwnership();
			furniture.SpawnObject(true);
			ManualLogSource logSource2 = Plugin.LogSource;
			val = new BepInExInfoLogInterpolatedStringHandler(22, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[repair-after-create] ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(FurnitureInteractableAudit.Describe(furniture));
			}
			logSource2.LogInfo(val);
			if (Plugin.TryAlternateInteractableOrdering.Value && !FurnitureInteractableAudit.HasIntegratedInstances(furniture))
			{
				TryAlternateInteractableOrdering(furniture);
			}
		}

		private static void TryAlternateInteractableOrdering(FurnitureLocation furniture)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Expected O, but got Unknown
			Plugin.LogSource.LogInfo((object)"[repair-order-probe] current AssignOwner -> CreateInteractables -> UpdateIntegratedObjectOwnership -> SpawnObject left integrated=0; trying SpawnObject -> CreateInteractables.");
			furniture.SpawnObject(true);
			furniture.CreateInteractables();
			furniture.UpdateIntegratedObjectOwnership();
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[repair-after-spawn-first] ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(FurnitureInteractableAudit.Describe(furniture));
			}
			logSource.LogInfo(val);
			if (FurnitureInteractableAudit.HasIntegratedInstances(furniture))
			{
				return;
			}
			int value = FurnitureInteractableAudit.PresetDefinitionCount(furniture.furniture);
			Plugin.LogSource.LogInfo((object)("[repair-order-probe] spawn-first still integrated=0; " + $"presetIntegrated={value}. Invoking parameterless " + "FurnitureLocation methods whose names mention interactables."));
			foreach (MethodInfo item in VanillaInteractableApiProbe.ParameterlessInteractableMethods(furniture))
			{
				if (item.Name.Equals("CreateInteractables", StringComparison.Ordinal) || item.Name.Equals("SpawnObject", StringComparison.Ordinal) || item.Name.Equals("UpdateIntegratedObjectOwnership", StringComparison.Ordinal))
				{
					continue;
				}
				try
				{
					InteractableCreationTrace.Phase = "repair-invoke-" + item.Name;
					item.Invoke(furniture, Array.Empty<object>());
					Plugin.LogSource.LogInfo((object)("[repair-after-invoke " + item.Name + "] " + FurnitureInteractableAudit.Describe(furniture)));
				}
				catch (Exception ex)
				{
					ManualLogSource logSource2 = Plugin.LogSource;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(30, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[repair-order-probe] ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(item.Name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" failed: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					logSource2.LogWarning(val2);
				}
				if (FurnitureInteractableAudit.HasIntegratedInstances(furniture))
				{
					ManualLogSource logSource3 = Plugin.LogSource;
					val = new BepInExInfoLogInterpolatedStringHandler(56, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[repair-order-probe] ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" produced integrated interactables.");
					}
					logSource3.LogInfo(val);
					return;
				}
			}
			InteractableCreationTrace.Phase = "repair";
		}

		private static void LogChosenFurniture(NewRoom room, string clusterName, FurnitureClusterLocation location, string phase)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			if (location.clusterList == null)
			{
				Plugin.LogSource.LogInfo((object)($"[repair-chosen {phase}] ControlRoom {room.roomID} cluster='{clusterName}' " + "clusterList=<none>"));
				return;
			}
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[repair-chosen ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(phase);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ControlRoom ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(room.roomID);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" cluster='");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(clusterName);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("pieces=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(location.clusterList.Count);
			}
			logSource.LogInfo(val);
			for (int i = 0; i < location.clusterList.Count; i++)
			{
				FurnitureLocation val2 = location.clusterList[i];
				if (val2 != null)
				{
					ManualLogSource logSource2 = Plugin.LogSource;
					val = new BepInExInfoLogInterpolatedStringHandler(19, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[repair-chosen ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(phase);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]   ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(FurnitureInteractableAudit.Describe(val2));
					}
					logSource2.LogInfo(val);
					if (clusterName == "DeskAgainstWall" && (SoCustomComparison)(object)val2.furniture != (SoCustomComparison)null && !FurnitureInteractableAudit.PresetDefines(val2.furniture, "MicroCruncher"))
					{
						Plugin.LogSource.LogWarning((object)($"[repair-chosen {phase}] DeskAgainstWall selected furniture '{ControlRoomScanner.PresetName((Object)(object)val2.furniture)}' " + "with no MicroCruncher preset definition."));
					}
				}
			}
		}

		private static void PreferDeskPresetWithMicroCruncher(FurnitureClusterLocation location)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			if (!Plugin.PreferWorkingDeskPreset.Value || location.clusterList == null)
			{
				return;
			}
			FurniturePreset val = WorkingReferenceAudit.FindDeskPresetWithMicroCruncher();
			if ((SoCustomComparison)(object)val == (SoCustomComparison)null)
			{
				Plugin.LogSource.LogWarning((object)"[repair-prefer] no Toolbox furniture preset defines a MicroCruncher.");
				return;
			}
			Plugin.LogSource.LogInfo((object)("[repair-prefer] candidate " + FurnitureInteractableAudit.DescribeFurniturePreset(val)));
			bool flag = default(bool);
			for (int i = 0; i < location.clusterList.Count; i++)
			{
				FurnitureLocation val2 = location.clusterList[i];
				if (val2 != null && !FurnitureInteractableAudit.PresetDefines(val2.furniture, "MicroCruncher"))
				{
					string text = (((SoCustomComparison)(object)val2.furniture != (SoCustomComparison)null) ? ControlRoomScanner.PresetName((Object)(object)val2.furniture) : "<null>");
					val2.furniture = val;
					ManualLogSource logSource = Plugin.LogSource;
					BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(66, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[repair-prefer] replaced furniture '");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' with ");
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("'");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ControlRoomScanner.PresetName((Object)(object)val));
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' before AddFurniture.");
					}
					logSource.LogInfo(val3);
				}
			}
		}

		private static FurnitureCluster? FindCluster(string name)
		{
			for (int i = 0; i < Toolbox.Instance.allFurnitureClusters.Count; i++)
			{
				FurnitureCluster val = Toolbox.Instance.allFurnitureClusters[i];
				if ((SoCustomComparison)(object)val != (SoCustomComparison)null && ControlRoomScanner.PresetName((Object)(object)val).Equals(name, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		private static bool HasCluster(NewRoom room, string clusterName)
		{
			if (room.individualFurniture == null)
			{
				return false;
			}
			for (int i = 0; i < room.individualFurniture.Count; i++)
			{
				FurnitureLocation obj = room.individualFurniture[i];
				object obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					FurnitureClusterLocation cluster = obj.cluster;
					obj2 = ((cluster != null) ? cluster.cluster : null);
				}
				FurnitureCluster val = (FurnitureCluster)obj2;
				if ((SoCustomComparison)(object)val != (SoCustomComparison)null && ControlRoomScanner.PresetName((Object)(object)val).Equals(clusterName, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static bool HasMicroCruncher(NewRoom room)
		{
			if (room.individualFurniture == null)
			{
				return false;
			}
			for (int i = 0; i < room.individualFurniture.Count; i++)
			{
				FurnitureLocation val = room.individualFurniture[i];
				if (val != null && (ContainsMicroCruncher(val.integratedInteractables) || ContainsMicroCruncher(val.spawnedInteractables)))
				{
					return true;
				}
			}
			return false;
		}

		private static bool ContainsMicroCruncher(List<Interactable>? interactables)
		{
			if (interactables == null)
			{
				return false;
			}
			for (int i = 0; i < interactables.Count; i++)
			{
				Interactable val = interactables[i];
				if ((SoCustomComparison)(object)((val != null) ? val.preset : null) != (SoCustomComparison)null && ControlRoomScanner.PresetName((Object)(object)val.preset).Equals("MicroCruncher", StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class FurnitureInteractableAudit
	{
		internal static void LogControlRooms(string phase)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			CityData instance = CityData.Instance;
			bool flag = default(bool);
			if (((instance != null) ? instance.roomDictionary : null) == null)
			{
				ManualLogSource logSource = Plugin.LogSource;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(60, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Interactable audit '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(phase);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' skipped because the city is not ready.");
				}
				logSource.LogWarning(val);
				return;
			}
			int num = 0;
			int num2 = 0;
			Enumerator<int, NewRoom> enumerator = CityData.Instance.roomDictionary.GetEnumerator();
			ManualLogSource logSource2 = Plugin.LogSource;
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(27, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("=== Interactable audit ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(phase);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ===");
			}
			logSource2.LogInfo(val2);
			while (enumerator.MoveNext())
			{
				NewRoom value = enumerator.Current.Value;
				if (!((SoCustomComparison)(object)((value != null) ? value.preset : null) == (SoCustomComparison)null) && ControlRoomScanner.PresetName((Object)(object)value.preset).Equals("ControlRoom", StringComparison.OrdinalIgnoreCase))
				{
					num++;
					num2 += LogRoom(value, phase);
				}
			}
			ManualLogSource logSource3 = Plugin.LogSource;
			val2 = new BepInExInfoLogInterpolatedStringHandler(56, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("=== Interactable audit ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(phase);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" complete: rooms=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("furniture=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num2);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ===");
			}
			logSource3.LogInfo(val2);
		}

		internal static int LogRoom(NewRoom room, string phase)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (room.individualFurniture == null)
			{
				ManualLogSource logSource = Plugin.LogSource;
				val = new BepInExInfoLogInterpolatedStringHandler(39, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(phase);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ControlRoom roomID=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(room.roomID);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" furniture=<none>");
				}
				logSource.LogInfo(val);
				return 0;
			}
			ManualLogSource logSource2 = Plugin.LogSource;
			val = new BepInExInfoLogInterpolatedStringHandler(33, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(phase);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ControlRoom roomID=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(room.roomID);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("furniture=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(room.individualFurniture.Count);
			}
			logSource2.LogInfo(val);
			for (int i = 0; i < room.individualFurniture.Count; i++)
			{
				FurnitureLocation val2 = room.individualFurniture[i];
				if (val2 != null)
				{
					ManualLogSource logSource3 = Plugin.LogSource;
					val = new BepInExInfoLogInterpolatedStringHandler(5, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(phase);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]   ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Describe(val2));
					}
					logSource3.LogInfo(val);
				}
			}
			return room.individualFurniture.Count;
		}

		internal static string Describe(FurnitureLocation location)
		{
			string value = (((SoCustomComparison)(object)location.furniture != (SoCustomComparison)null) ? ControlRoomScanner.PresetName((Object)(object)location.furniture) : "<null>");
			FurnitureClusterLocation cluster = location.cluster;
			string value2 = (((SoCustomComparison)(object)((cluster != null) ? cluster.cluster : null) != (SoCustomComparison)null) ? ControlRoomScanner.PresetName((Object)(object)location.cluster.cluster) : "<none>");
			return $"id={ReadId(location)} furniture='{value}' cluster='{value2}' presetIntegrated={DescribePresetDefinitions(location.furniture)} locationIntegrated={DescribeInteractables(location.integratedInteractables)} locationSpawned={DescribeInteractables(location.spawnedInteractables)}";
		}

		internal static bool HasIntegratedInstances(FurnitureLocation location)
		{
			return (location.integratedInteractables?.Count ?? 0) > 0;
		}

		internal static int PresetDefinitionCount(object? furniture)
		{
			return CountIl2CppList(ReadMember(furniture, "integratedInteractables"));
		}

		internal static bool PresetDefines(object? furniture, string namePart)
		{
			List<string> list = NamesFromUnknownList(ReadMember(furniture, "integratedInteractables"));
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].IndexOf(namePart, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		internal static string DescribeFurniturePreset(object? furniture)
		{
			Object val = (Object)((furniture is Object) ? furniture : null);
			string text = ((val != null) ? ControlRoomScanner.PresetName(val) : "<null>");
			return "furniture='" + text + "' presetIntegrated=" + DescribePresetDefinitions(furniture);
		}

		internal static string DescribePresetDefinitions(object? furniture)
		{
			if (furniture == null)
			{
				return "0[]";
			}
			List<string> list = NamesFromUnknownList(ReadMember(furniture, "integratedInteractables"));
			int value = CountIl2CppList(ReadMember(furniture, "subObjects"));
			return $"{list.Count}[{JoinNames(list)}] subObjects={value}";
		}

		private static string DescribeInteractables(List<Interactable>? interactables)
		{
			List<string> list = new List<string>();
			if (interactables != null)
			{
				for (int i = 0; i < interactables.Count; i++)
				{
					Interactable val = interactables[i];
					list.Add(((SoCustomComparison)(object)((val != null) ? val.preset : null) != (SoCustomComparison)null) ? ControlRoomScanner.PresetName((Object)(object)val.preset) : "<null>");
				}
			}
			return $"{list.Count}[{JoinNames(list)}]";
		}

		private static List<string> NamesFromUnknownList(object? list)
		{
			List<string> list2 = new List<string>();
			int num = CountIl2CppList(list);
			for (int i = 0; i < num; i++)
			{
				list2.Add(NameFromUnknownItem(IndexIl2CppList(list, i)));
			}
			return list2;
		}

		private static string NameFromUnknownItem(object? item)
		{
			if (item == null)
			{
				return "<null>";
			}
			object? obj = ReadMember(item, "preset");
			Object val = (Object)((obj is Object) ? obj : null);
			if (val != null)
			{
				return ControlRoomScanner.PresetName(val);
			}
			Object val2 = (Object)((item is Object) ? item : null);
			if (val2 != null)
			{
				return ControlRoomScanner.PresetName(val2);
			}
			return item.GetType().Name;
		}

		private static object? ReadMember(object? target, string name)
		{
			if (target == null)
			{
				return null;
			}
			Type type = target.GetType();
			PropertyInfo property = type.GetProperty(name);
			if (property != null)
			{
				return property.GetValue(target);
			}
			return type.GetField(name)?.GetValue(target);
		}

		private static int CountIl2CppList(object? list)
		{
			if (list == null)
			{
				return 0;
			}
			object obj = ReadMember(list, "Count");
			if (obj is int)
			{
				return (int)obj;
			}
			return 0;
		}

		private static object? IndexIl2CppList(object? list, int index)
		{
			return list?.GetType().GetProperty("Item")?.GetValue(list, new object[1] { index });
		}

		private static string ReadId(FurnitureLocation location)
		{
			string[] array = new string[4] { "id", "furnitureID", "furnID", "idnt" };
			foreach (string text in array)
			{
				object obj = ReadMember(location, text);
				if (obj != null)
				{
					return $"{text}={obj}";
				}
			}
			return "id=<unknown>";
		}

		private static string JoinNames(List<string> names)
		{
			if (names.Count == 0)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < names.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.Append(names[i]);
			}
			return stringBuilder.ToString();
		}
	}
	[HarmonyPatch(typeof(MurderController), "OnStartGame")]
	internal static class GameStartedPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Expected O, but got Unknown
			if (Plugin.DumpInteractablePipeline.Value)
			{
				InteractableCreationTrace.Phase = "before-repair";
				VanillaInteractableApiProbe.LogCityConstructorState();
				WorkingReferenceAudit.LogReferences();
				FurnitureInteractableAudit.LogControlRooms("before-repair");
			}
			bool flag = default(bool);
			if (Plugin.RepairExistingControlRooms.Value)
			{
				try
				{
					InteractableCreationTrace.Phase = "repair";
					ExistingCityRepair.Run();
				}
				catch (Exception ex)
				{
					ManualLogSource logSource = Plugin.LogSource;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(41, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Existing-city ControlRoom repair failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					logSource.LogError(val);
				}
			}
			if (Plugin.HireForVacantControlRooms.Value)
			{
				try
				{
					VacantPostHiring.Run();
				}
				catch (Exception ex2)
				{
					ManualLogSource logSource2 = Plugin.LogSource;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(35, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Vacant control-room hiring failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex2);
					}
					logSource2.LogError(val);
				}
			}
			if (Plugin.DumpInteractablePipeline.Value)
			{
				InteractableCreationTrace.Phase = "after-repair";
				FurnitureInteractableAudit.LogControlRooms("after-repair");
			}
			try
			{
				InteractableCreationTrace.Phase = "roster";
				ResidentRosterCompleter.Run();
			}
			catch (Exception ex3)
			{
				ManualLogSource logSource3 = Plugin.LogSource;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ResidentRoster one-drawer limit failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex3);
				}
				logSource3.LogError(val);
			}
			try
			{
				InteractableCreationTrace.Phase = "scan";
				ControlRoomScanner.Run();
				CityHallGenerationFix.LogResult();
			}
			catch (Exception ex4)
			{
				ManualLogSource logSource4 = Plugin.LogSource;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Post-generation diagnostic pass failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex4);
				}
				logSource4.LogError(val);
			}
			InteractableCreationTrace.Phase = "post-start";
		}
	}
	internal static class InteractableCreationTrace
	{
		internal static string Phase { get; set; } = "startup";

		public static void Postfix(object __instance, MethodBase __originalMethod)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			if (Plugin.DumpInteractablePipeline.Value && !(__originalMethod == null))
			{
				string text = __originalMethod.DeclaringType?.Name ?? "<unknown>";
				FurnitureLocation val = (FurnitureLocation)((__instance is FurnitureLocation) ? __instance : null);
				string text2 = ((val != null) ? FurnitureInteractableAudit.Describe(val) : (__instance?.ToString() ?? "<static>"));
				ManualLogSource logSource = Plugin.LogSource;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(17, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[trace] ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(__originalMethod.Name);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" phase=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Phase);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text2);
				}
				logSource.LogInfo(val2);
			}
		}
	}
	[BepInPlugin("sm3gm.sod.controlroomfix", "Control Room Fix", "1.1.0")]
	public sealed class Plugin : BasePlugin
	{
		public const string PluginGuid = "sm3gm.sod.controlroomfix";

		public const string PluginName = "Control Room Fix";

		public const string PluginVersion = "1.1.0";

		internal static ManualLogSource LogSource { get; private set; }

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

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

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

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

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

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

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

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

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

		public override void Load()
		{
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Expected O, but got Unknown
			LogSource = ((BasePlugin)this).Log;
			EnableGenerationFix = ((BasePlugin)this).Config.Bind<bool>("Fixes", "EnableControlRoomGenerationFix", true, "Allow functional furniture to generate in otherwise uninhabited ControlRoom addresses.");
			RepairExistingControlRooms = ((BasePlugin)this).Config.Bind<bool>("Fixes", "RepairExistingControlRooms", true, "Add missing vanilla functional clusters when an existing broken city is loaded.");
			HireForVacantControlRooms = ((BasePlugin)this).Config.Bind<bool>("Fixes", "HireForVacantControlRooms", true, "Give a control room's company one employee when all its posts are vacant, so its computer has a login. Re-applied on every load; nothing is saved.");
			EnableCityHallGenerationFix = ((BasePlugin)this).Config.Bind<bool>("Fixes", "EnableDuplicateCityHallLimitExperiment", false, "Experimental: raise CityHall company limits to eligible address count.");
			CompleteResidentRosters = ((BasePlugin)this).Config.Bind<bool>("Fixes", "CompleteResidentRosters", false, "Optional extra: add every building inhabitant to one ControlRoom ResidentRoster drawer. Extra drawers are emptied either way so files are not duplicated. Default off (vanilla-like partial folders).");
			DumpEligiblePresets = ((BasePlugin)this).Config.Bind<bool>("Diagnostics", "DumpEligiblePresets", false, "Log furniture clusters and presets eligible for ControlRoom rooms.");
			DumpInteractablePipeline = ((BasePlugin)this).Config.Bind<bool>("Diagnostics", "DumpInteractablePipeline", false, "Log vanilla furniture/interactable APIs and before/after repair counts.");
			TryAlternateInteractableOrdering = ((BasePlugin)this).Config.Bind<bool>("Fixes", "TryAlternateInteractableOrdering", true, "If CreateInteractables leaves integrated=0, try SpawnObject-first and other parameterless interactable methods.");
			PreferWorkingDeskPreset = ((BasePlugin)this).Config.Bind<bool>("Fixes", "PreferWorkingDeskPreset", true, "If DeskAgainstWall picks a furniture preset with no MicroCruncher, assign a Toolbox desk preset that defines one.");
			Harmony.CreateAndPatchAll(typeof(GameStartedPatch), "sm3gm.sod.controlroomfix");
			Harmony.CreateAndPatchAll(typeof(InteriorGenerationPatch), "sm3gm.sod.controlroomfix");
			Harmony.CreateAndPatchAll(typeof(CitizenGenerationPatch), "sm3gm.sod.controlroomfix");
			bool flag = default(bool);
			if (DumpInteractablePipeline.Value)
			{
				try
				{
					VanillaInteractableApiProbe.DumpAndTrace();
				}
				catch (Exception ex)
				{
					ManualLogSource logSource = LogSource;
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(39, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Vanilla interactable API probe failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					logSource.LogError(val);
				}
			}
			ManualLogSource logSource2 = LogSource;
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(144, 7, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("Control Room Fix");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.1.0");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded; fixes: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ControlRoom generation=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(EnableGenerationFix.Value ? "enabled" : "disabled");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("existing ControlRooms=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(RepairExistingControlRooms.Value ? "enabled" : "disabled");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("complete resident rosters=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(CompleteResidentRosters.Value ? "enabled" : "disabled");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("duplicate City Hall=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(EnableCityHallGenerationFix.Value ? "enabled" : "disabled");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("interactable pipeline dump=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(DumpInteractablePipeline.Value ? "enabled" : "disabled");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
			}
			logSource2.LogInfo(val2);
		}
	}
	internal static class ResidentRosterCompleter
	{
		internal static void Run()
		{
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Expected O, but got Unknown
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Expected O, but got Unknown
			CityData instance = CityData.Instance;
			if (((instance != null) ? instance.roomDictionary : null) == null)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			Enumerator<int, NewRoom> enumerator = CityData.Instance.roomDictionary.GetEnumerator();
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val3;
			while (enumerator.MoveNext())
			{
				NewRoom value = enumerator.Current.Value;
				if ((SoCustomComparison)(object)((value != null) ? value.preset : null) == (SoCustomComparison)null || !ControlRoomScanner.PresetName((Object)(object)value.preset).Equals("ControlRoom", StringComparison.OrdinalIgnoreCase) || value.worldObjects == null)
				{
					continue;
				}
				List<EvidenceMultiPage> list = CollectResidentRosters(value);
				if (list.Count == 0)
				{
					continue;
				}
				EvidenceMultiPage val = PickKeeper(list);
				if (Plugin.CompleteResidentRosters.Value)
				{
					int num6 = AddMissingBuildingResidents(value, val);
					if (num6 > 0)
					{
						((Evidence)val).forceSave = true;
						num4++;
						num5 += num6;
					}
				}
				int num7 = 0;
				int num8 = 0;
				for (int i = 0; i < list.Count; i++)
				{
					EvidenceMultiPage val2 = list[i];
					if (val2 != val)
					{
						int num9 = ClearRosterPages(val2);
						if (num9 > 0)
						{
							num7++;
							num8 += num9;
						}
					}
				}
				if (list.Count > 1)
				{
					num++;
					num2 += num7;
					num3 += num8;
					ManualLogSource logSource = Plugin.LogSource;
					val3 = new BepInExInfoLogInterpolatedStringHandler(101, 4, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ControlRoom ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(value.roomID);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" resident files: keeping 1 drawer ");
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("with ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(PageCount(val));
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" pages; cleared ");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num7);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" extra ");
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("drawers (");
						((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num8);
						((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" duplicate pages).");
					}
					logSource.LogInfo(val3);
				}
			}
			ManualLogSource logSource2 = Plugin.LogSource;
			val3 = new BepInExInfoLogInterpolatedStringHandler(90, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ResidentRoster one-drawer limit: rooms=");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("extra drawers cleared=");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num2);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("duplicate pages removed=");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num3);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
			}
			logSource2.LogInfo(val3);
			if (Plugin.CompleteResidentRosters.Value)
			{
				ManualLogSource logSource3 = Plugin.LogSource;
				val3 = new BepInExInfoLogInterpolatedStringHandler(74, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ResidentRoster completion updated ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num4);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" keeper rosters ");
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("with ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num5);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" missing residents.");
				}
				logSource3.LogInfo(val3);
			}
		}

		private static List<EvidenceMultiPage> CollectResidentRosters(NewRoom room)
		{
			List<EvidenceMultiPage> list = new List<EvidenceMultiPage>();
			Enumerator<Interactable> enumerator = room.worldObjects.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Interactable current = enumerator.Current;
				if (!((SoCustomComparison)(object)((current != null) ? current.preset : null) == (SoCustomComparison)null) && ControlRoomScanner.PresetName((Object)(object)current.preset).Equals("ResidentRoster", StringComparison.OrdinalIgnoreCase))
				{
					Evidence evidence = current.evidence;
					EvidenceMultiPage val = (EvidenceMultiPage)(object)((evidence is EvidenceMultiPage) ? evidence : null);
					if (val != null)
					{
						list.Add(val);
					}
				}
			}
			return list;
		}

		private static EvidenceMultiPage PickKeeper(List<EvidenceMultiPage> rosters)
		{
			EvidenceMultiPage val = rosters[0];
			int num = PageCount(val);
			for (int i = 1; i < rosters.Count; i++)
			{
				EvidenceMultiPage val2 = rosters[i];
				int num2 = PageCount(val2);
				if (num2 > num)
				{
					val = val2;
					num = num2;
				}
			}
			return val;
		}

		private static int PageCount(EvidenceMultiPage roster)
		{
			return roster.pageContent?.Count ?? 0;
		}

		private static int ClearRosterPages(EvidenceMultiPage roster)
		{
			if (roster.pageContent == null)
			{
				return 0;
			}
			int count = roster.pageContent.Count;
			if (count == 0)
			{
				return 0;
			}
			while (roster.pageContent.Count > 0)
			{
				roster.pageContent.RemoveAt(roster.pageContent.Count - 1);
			}
			((Evidence)roster).forceSave = true;
			return count;
		}

		private static int AddMissingBuildingResidents(NewRoom room, EvidenceMultiPage roster)
		{
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (roster.pageContent != null)
			{
				for (int i = 0; i < roster.pageContent.Count; i++)
				{
					MultiPageContent obj = roster.pageContent[i];
					string text = ((obj != null) ? obj.evID : null);
					if (!string.IsNullOrWhiteSpace(text))
					{
						hashSet.Add(text);
					}
				}
			}
			NewBuilding building = room.building;
			int num = ((building != null) ? building.buildingID : (-1));
			if (num < 0)
			{
				return 0;
			}
			int num2 = 0;
			List<NewAddress> addressDirectory = CityData.Instance.addressDirectory;
			for (int j = 0; j < addressDirectory.Count; j++)
			{
				NewAddress val = addressDirectory[j];
				if (val == null)
				{
					continue;
				}
				NewBuilding building2 = ((NewGameLocation)val).building;
				if (((building2 != null) ? new int?(building2.buildingID) : ((int?)null)) != num || val.inhabitants == null)
				{
					continue;
				}
				for (int k = 0; k < val.inhabitants.Count; k++)
				{
					Human obj2 = val.inhabitants[k];
					EvidenceWitness val2 = ((obj2 != null) ? ((Actor)obj2).evidenceEntry : null);
					if (val2 != null && !string.IsNullOrWhiteSpace(((Evidence)val2).evID) && hashSet.Add(((Evidence)val2).evID))
					{
						roster.AddEvidenceToNewPage((Evidence)(object)val2);
						num2++;
					}
				}
			}
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(76, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ControlRoom ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(room.roomID);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" keeper ResidentRoster now references ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(hashSet.Count);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" unique residents; added=");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num2);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
			}
			logSource.LogInfo(val3);
			return num2;
		}
	}
	internal static class SpawnedLayerFill
	{
		private static readonly string[] RequiredPresetNames = new string[4] { "MicroCruncher", "Blueprints", "CompanyRoster", "ResidentRoster" };

		internal static void FillSpawnedLayer(FurnitureLocation location, int roomID)
		{
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			if (location == null)
			{
				return;
			}
			FurniturePreset val = null;
			try
			{
				val = location.furniture;
			}
			catch
			{
				return;
			}
			if ((SoCustomComparison)(object)val == (SoCustomComparison)null)
			{
				return;
			}
			List<SubObject> val2 = null;
			try
			{
				val2 = val.subObjects;
			}
			catch
			{
				return;
			}
			if (val2 == null || val2.Count == 0)
			{
				return;
			}
			string text = SafePresetName((SoCustomComparison)(object)val);
			HashSet<int> hashSet = new HashSet<int>();
			int num = 0;
			for (int i = 0; i < RequiredPresetNames.Length; i++)
			{
				string wanted = RequiredPresetNames[i];
				int num2 = -1;
				InteractablePreset val3 = null;
				int num3 = -1;
				InteractablePreset val4 = null;
				for (int j = 0; j < val2.Count; j++)
				{
					SubObject val5 = null;
					try
					{
						val5 = val2[j];
					}
					catch
					{
						continue;
					}
					if (val5 == null)
					{
						continue;
					}
					SubObjectClassPreset val6 = null;
					try
					{
						val6 = val5.preset;
					}
					catch
					{
						continue;
					}
					if ((SoCustomComparison)(object)val6 == (SoCustomComparison)null)
					{
						continue;
					}
					InteractablePreset val7 = FindByName(ResolveCandidates(val6), wanted);
					if (!((SoCustomComparison)(object)val7 == (SoCustomComparison)null))
					{
						if (!hashSet.Contains(j))
						{
							num2 = j;
							val3 = val7;
							break;
						}
						if (num3 < 0)
						{
							num3 = j;
							val4 = val7;
						}
					}
				}
				int num4 = num2;
				InteractablePreset val8 = val3;
				string reason = "fresh-slot";
				if ((SoCustomComparison)(object)val8 == (SoCustomComparison)null)
				{
					num4 = num3;
					val8 = val4;
					reason = "stacked-slot";
				}
				if (!((SoCustomComparison)(object)val8 == (SoCustomComparison)null))
				{
					SubObject val9 = null;
					try
					{
						val9 = val2[num4];
					}
					catch
					{
						continue;
					}
					if (val9 != null && Create(location, val9, val8, roomID, text, num4, reason))
					{
						num++;
						hashSet.Add(num4);
					}
				}
			}
			if (num > 0)
			{
				ManualLogSource logSource = Plugin.LogSource;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val10 = new BepInExInfoLogInterpolatedStringHandler(41, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val10).AppendLiteral("[fill] room=");
					((BepInExLogInterpolatedStringHandler)val10).AppendFormatted<int>(roomID);
					((BepInExLogInterpolatedStringHandler)val10).AppendLiteral(" furniture='");
					((BepInExLogInterpolatedStringHandler)val10).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val10).AppendLiteral("' slots=");
					((BepInExLogInterpolatedStringHandler)val10).AppendFormatted<int>(val2.Count);
					((BepInExLogInterpolatedStringHandler)val10).AppendLiteral(" created=");
					((BepInExLogInterpolatedStringHandler)val10).AppendFormatted<int>(num);
				}
				logSource.LogInfo(val10);
			}
		}

		private static InteractablePreset FindByName(List<InteractablePreset> candidates, string wanted)
		{
			if (candidates == null)
			{
				return null;
			}
			for (int i = 0; i < candidates.Count; i++)
			{
				InteractablePreset val = null;
				try
				{
					val = candidates[i];
				}
				catch
				{
					continue;
				}
				if (!((SoCustomComparison)(object)val == (SoCustomComparison)null) && SafePresetName((SoCustomComparison)(object)val) == wanted)
				{
					return val;
				}
			}
			return null;
		}

		private static bool Create(FurnitureLocation location, SubObject slot, InteractablePreset preset, int roomID, string furnitureName, int slotIndex, string reason)
		{
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			string text = "";
			try
			{
				text = slot.parent;
			}
			catch
			{
			}
			bool flag2 = default(bool);
			try
			{
				if (InteractableCreator.Instance.CreateFurnitureSpawnedInteractable(preset, location, slot, (Human)null, (Human)null, (Human)null, (List<Passed>)null, (LightingPreset)null, (Object)null, "") == null)
				{
					ManualLogSource logSource = Plugin.LogSource;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(73, 6, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[fill] room=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(roomID);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" furniture='");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(furnitureName);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' slot=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(slotIndex);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("parent='");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' preset='");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(SafePresetName((SoCustomComparison)(object)preset));
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' reason=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" returned null");
					}
					logSource.LogWarning(val);
					return false;
				}
				ManualLogSource logSource2 = Plugin.LogSource;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(60, 6, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[fill] room=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(roomID);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" furniture='");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(furnitureName);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' slot=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(slotIndex);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("parent='");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' created='");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(SafePresetName((SoCustomComparison)(object)preset));
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' reason=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(reason);
				}
				logSource2.LogInfo(val2);
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource logSource3 = Plugin.LogSource;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(67, 7, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[fill] room=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(roomID);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" furniture='");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(furnitureName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' slot=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(slotIndex);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("parent='");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' preset='");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(SafePresetName((SoCustomComparison)(object)preset));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' reason=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" threw: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				logSource3.LogWarning(val);
				return false;
			}
		}

		private static List<InteractablePreset> ResolveCandidates(SubObjectClassPreset classPreset)
		{
			try
			{
				Dictionary<SubObjectClassPreset, List<InteractablePreset>> subObjectsDictionary = Toolbox.Instance.subObjectsDictionary;
				if (subObjectsDictionary == null)
				{
					return null;
				}
				if (!subObjectsDictionary.ContainsKey(classPreset))
				{
					return null;
				}
				return subObjectsDictionary[classPreset];
			}
			catch
			{
				return null;
			}
		}

		private static string SafePresetName(SoCustomComparison item)
		{
			if (item == (SoCustomComparison)null)
			{
				return "?";
			}
			try
			{
				string presetName = item.GetPresetName();
				if (!string.IsNullOrEmpty(presetName))
				{
					return presetName;
				}
			}
			catch
			{
			}
			try
			{
				return ((Object)item).name;
			}
			catch
			{
				return "?";
			}
		}
	}
	internal static class VacantPostHiring
	{
		internal static void Run()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			int controlRooms;
			int addressNull;
			int companyNull;
			List<Company> list = CollectCompanies(out controlRooms, out addressNull, out companyNull);
			string murdererId;
			string victimId;
			int previousCount;
			List<Citizen> list2 = CollectCandidates(CollectExcludedHumanIds(out murdererId, out victimId, out previousCount));
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(89, 7, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[hire] murderer=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(murdererId);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" victim=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(victimId);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("previousMurderers=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(previousCount);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" pool=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list2.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("|controlRooms=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(controlRooms);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("|addressNull=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(addressNull);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("|companyNull=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(companyNull);
			}
			logSource.LogInfo(val);
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				Company company = list[i];
				try
				{
					if (TryHireForCompany(company, list2))
					{
						num++;
					}
				}
				catch (Exception exception)
				{
					LogThrew(exception);
				}
			}
			ManualLogSource logSource2 = Plugin.LogSource;
			val = new BepInExInfoLogInterpolatedStringHandler(27, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[hire] hired ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" of ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" companies");
			}
			logSource2.LogInfo(val);
		}

		private static List<Company> CollectCompanies(out int controlRooms, out int addressNull, out int companyNull)
		{
			controlRooms = 0;
			addressNull = 0;
			companyNull = 0;
			SortedDictionary<int, Company> sortedDictionary = new SortedDictionary<int, Company>();
			CityData val = null;
			try
			{
				val = CityData.Instance;
			}
			catch (Exception exception)
			{
				LogThrew(exception);
				return new List<Company>();
			}
			if ((Object)(object)val == (Object)null)
			{
				return new List<Company>();
			}
			Dictionary<int, NewRoom> val2 = null;
			try
			{
				val2 = val.roomDictionary;
			}
			catch (Exception exception2)
			{
				LogThrew(exception2);
				return new List<Company>();
			}
			if (val2 == null)
			{
				return new List<Company>();
			}
			Enumerator<int, NewRoom> val3 = null;
			try
			{
				val3 = val2.GetEnumerator();
			}
			catch (Exception exception3)
			{
				LogThrew(exception3);
				return new List<Company>();
			}
			while (true)
			{
				bool flag;
				try
				{
					flag = val3.MoveNext();
				}
				catch (Exception exception4)
				{
					LogThrew(exception4);
					break;
				}
				if (!flag)
				{
					break;
				}
				try
				{
					NewRoom value = val3.Current.Value;
					if ((Object)(object)value == (Object)null)
					{
						continue;
					}
					RoomConfiguration val4 = null;
					try
					{
						val4 = value.preset;
					}
					catch (Exception exception5)
					{
						LogThrew(exception5);
						goto end_IL_0097;
					}
					if ((SoCustomComparison)(object)val4 == (SoCustomComparison)null)
					{
						continue;
					}
					string text;
					try
					{
						text = ControlRoomScanner.PresetName((Object)(object)val4);
					}
					catch (Exception exception6)
					{
						LogThrew(exception6);
						goto end_IL_0097;
					}
					if (text != "ControlRoom")
					{
						continue;
					}
					controlRooms++;
					NewAddress val5 = null;
					try
					{
						val5 = (((Object)(object)value.gameLocation != (Object)null) ? ((Il2CppObjectBase)value.gameLocation).TryCast<NewAddress>() : null);
					}
					catch (Exception exception7)
					{
						LogThrew(exception7);
						goto end_IL_0097;
					}
					if ((Object)(object)val5 == (Object)null)
					{
						addressNull++;
						continue;
					}
					Company val6 = null;
					try
					{
						val6 = val5.company;
					}
					catch (Exception exception8)
					{
						LogThrew(exception8);
						goto end_IL_0097;
					}
					if (val6 == null)
					{
						companyNull++;
						continue;
					}
					int companyID;
					try
					{
						companyID = val6.companyID;
					}
					catch (Exception exception9)
					{
						LogThrew(exception9);
						goto end_IL_0097;
					}
					if (!sortedDictionary.ContainsKey(companyID))
					{
						sortedDictionary[companyID] = val6;
					}
					end_IL_0097:;
				}
				catch (Exception exception10)
				{
					LogThrew(exception10);
				}
			}
			List<Company> list = new List<Company>();
			foreach (KeyValuePair<int, Company> item in sortedDictionary)
			{
				list.Add(item.Value);
			}
			return list;
		}

		private static HashSet<int> CollectExcludedHumanIds(out string murdererId, out string victimId, out int previousCount)
		{
			murdererId = "null";
			victimId = "null";
			previousCount = 0;
			HashSet<int> hashSet = new HashSet<int>();
			MurderController val = null;
			try
			{
				val = MurderController.Instance;
			}
			catch (Exception exception)
			{
				LogThrew(exception);
				return hashSet;
			}
			if ((Object)(object)val == (Object)null)
			{
				return hashSet;
			}
			Human human = null;
			try
			{
				human = val.currentMurderer;
			}
			catch (Exception exception2)
			{
				LogThrew(exception2);
			}
			TryExclude(human, hashSet, out murdererId);
			Human human2 = null;
			try
			{
				human2 = val.currentVictim;
			}
			catch (Exception exception3)
			{
				LogThrew(exception3);
			}
			TryExclude(human2, hashSet, out victimId);
			List<Human> val2 = null;
			try
			{
				val2 = val.previousMurderers;
			}
			catch (Exception exception4)
			{
				LogThrew(exception4);
			}
			if (val2 == null)
			{
				return hashSet;
			}
			try
			{
				previousCount = val2.Count;
			}
			catch (Exception exception5)
			{
				LogThrew(exception5);
				previousCount = 0;
				return hashSet;
			}
			for (int i = 0; i < previousCount; i++)
			{
				Human val3 = null;
				try
				{
					val3 = val2[i];
				}
				catch (Exception exception6)
				{
					LogThrew(exception6);
					continue;
				}
				TryExclude(val3, hashSet, out string _);
			}
			return hashSet;
		}

		private static void TryExclude(Human? human, HashSet<int> excluded, out string loggedId)
		{
			loggedId = "null";
			if ((Object)(object)human == (Object)null)
			{
				return;
			}
			try
			{
				int humanID = human.humanID;
				excluded.Add(humanID);
				loggedId = humanID.ToString();
			}
			catch (Exception exception)
			{
				LogThrew(exception);
			}
		}

		private static List<Citizen> CollectCandidates(HashSet<int> excludedIds)
		{
			List<KeyValuePair<int, Citizen>> list = new List<KeyValuePair<int, Citizen>>();
			CityData val = null;
			try
			{
				val = CityData.Instance;
			}
			catch (Exception exception)
			{
				LogThrew(exception);
				return new List<Citizen>();
			}
			if ((Object)(object)val == (Object)null)
			{
				return new List<Citizen>();
			}
			List<Citizen> val2 = null;
			try
			{
				val2 = val.citizenDirectory;
			}
			catch (Exception exception2)
			{
				LogThrew(exception2);
				return new List<Citizen>();
			}
			if (val2 == null)
			{
				return new List<Citizen>();
			}
			int count;
			try
			{
				count = val2.Count;
			}
			catch (Exception exception3)
			{
				LogThrew(exception3);
				return new List<Citizen>();
			}
			for (int i = 0; i < count; i++)
			{
				Citizen val3 = null;
				try
				{
					val3 = val2[i];
				}
				catch (Exception exception4)
				{
					LogThrew(exception4);
					continue;
				}
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				bool isDead;
				try
				{
					isDead = ((Actor)val3).isDead;
				}
				catch (Exception exception5)
				{
					LogThrew(exception5);
					continue;
				}
				if (isDead)
				{
					continue;
				}
				bool removedFromWorld;
				try
				{
					removedFromWorld = ((Human)val3).removedFromWorld;
				}
				catch (Exception exception6)
				{
					LogThrew(exception6);
					continue;
				}
				if (removedFromWorld)
				{
					continue;
				}
				int humanID;
				try
				{
					humanID = ((Human)val3).humanID;
				}
				catch (Exception exception7)
				{
					LogThrew(exception7);
					continue;
				}
				if (excludedIds.Contains(humanID))
				{
					continue;
				}
				Occupation val4 = null;
				try
				{
					val4 = ((Human)val3).job;
				}
				catch (Exception exception8)
				{
					LogThrew(exception8);
					continue;
				}
				if (val4 != null)
				{
					Company val5 = null;
					try
					{
						val5 = val4.employer;
					}
					catch (Exception exception9)
					{
						LogThrew(exception9);
						continue;
					}
					if (val5 != null || ReadOccupationPresetName(val4) != "Unemployed")
					{
						continue;
					}
				}
				list.Add(new KeyValuePair<int, Citizen>(humanID, val3));
			}
			list.Sort((KeyValuePair<int, Citizen> left, KeyValuePair<int, Citizen> right) => left.Key.CompareTo(right.Key));
			List<Citizen> list2 = new List<Citizen>(list.Count);
			for (int num = 0; num < list.Count; num++)
			{
				list2.Add(list[num].Value);
			}
			return list2;
		}

		private static bool TryHireForCompany(Company company, List<Citizen> pool)
		{
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			string text;
			try
			{
				text = company.name ?? "";
			}
			catch (Exception exception)
			{
				LogThrew(exception);
				text = "FAILED";
			}
			int companyID;
			try
			{
				companyID = company.companyID;
			}
			catch (Exception exception2)
			{
				LogThrew(exception2);
				return false;
			}
			int numberOfFilledJobs;
			try
			{
				numberOfFilledJobs = company.GetNumberOfFilledJobs();
			}
			catch (Exception exception3)
			{
				LogThrew(exception3);
				return false;
			}
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (numberOfFilledJobs > 0)
			{
				ManualLogSource logSource = Plugin.LogSource;
				val = new BepInExInfoLogInterpolatedStringHandler(32, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[hire] skip company=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" id=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(companyID);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" filled=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(numberOfFilledJobs);
				}
				logSource.LogInfo(val);
				return false;
			}
			Occupation val2 = FindVacantPost(company);
			if (val2 == null)
			{
				ManualLogSource logSource2 = Plugin.LogSource;
				val = new BepInExInfoLogInterpolatedStringHandler(46, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[hire] skip company=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" id=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(companyID);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" reason=no-vacant-post");
				}
				logSource2.LogInfo(val);
				return false;
			}
			if (pool.Count == 0)
			{
				ManualLogSource logSource3 = Plugin.LogSource;
				val = new BepInExInfoLogInterpolatedStringHandler(44, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[hire] skip company=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" id=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(companyID);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" reason=no-candidate");
				}
				logSource3.LogInfo(val);
				return false;
			}
			Citizen val3 = pool[0];
			try
			{
				((Human)val3).SetJob(val2);
			}
			catch (Exception exception4)
			{
				LogThrew(exception4);
				return false;
			}
			pool.RemoveAt(0);
			string text2 = ReadOccupationPresetName(val2);
			string text3;
			try
			{
				text3 = ((Human)val3).humanID.ToString();
			}
			catch (Exception exception5)
			{
				LogThrew(exception5);
				text3 = "FAILED";
			}
			string text4;
			try
			{
				text4 = ((Human)val3).GetCitizenName() ?? "";
			}
			catch (Exception exception6)
			{
				LogThrew(exception6);
				text4 = "FAILED";
			}
			string text5 = "null";
			Occupation val4 = null;
			try
			{
				val4 = ((Human)val3).job;
			}
			catch (Exception exception7)
			{
				LogThrew(exception7);
				text5 = "FAILED";
			}
			if (val4 != null)
			{
				try
				{
					text5 = val4.name ?? "";
				}
				catch (Exception exception8)
				{
					LogThrew(exception8);
					text5 = "FAILED";
				}
			}
			string text6 = "null";
			Human val5 = null;
			try
			{
				val5 = val2.employee;
			}
			catch (Exception exception9)
			{
				LogThrew(exception9);
				text6 = "FAILED";
			}
			if ((Object)(object)val5 != (Object)null)
			{
				try
				{
					text6 = val5.humanID.ToString();
				}
				catch (Exception exception10)
				{
					LogThrew(exception10);
					text6 = "FAILED";
				}
			}
			ManualLogSource logSource4 = Plugin.LogSource;
			val = new BepInExInfoLogInterpolatedStringHandler(48, 7, ref flag);
			if (flag)
			{