Decompiled source of Enhanced Law Enforcement v1.2.0

Law_Enforcement_Enhancement.dll

Decompiled 3 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Il2CppFishNet.Connection;
using Il2CppFishNet.Managing;
using Il2CppFishNet.Managing.Object;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.GameTime;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.NPCs.Behaviour;
using Il2CppScheduleOne.Police;
using LawEnforcementEnhancementMod;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Enhanced Law Enforcement", "1.2.0", "surrealnirvana", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Law_Enforcement_Enhancement")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Law_Enforcement_Enhancement")]
[assembly: AssemblyTitle("Law_Enforcement_Enhancement")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
namespace LawEnforcementEnhancementMod
{
	public class Core : MelonMod
	{
		private static Core _instance;

		private GameObject? _networkManagerObj;

		private ModSettings _settings;

		private PoliceManager? _policeManager;

		private OfficerSpawnSystem? _officerSpawnSystem;

		private SentrySpawnSystem? _sentrySpawnSystem;

		public readonly string ModVersion = "1.0.0";

		private int _framesSinceLastCheck;

		public static Core Instance => _instance;

		public GameObject? NetworkManagerObject => _networkManagerObj;

		public ModSettings Settings => _settings;

		public PoliceManager PoliceManager => _policeManager ?? throw new InvalidOperationException("PoliceManager not initialized");

		public OfficerSpawnSystem OfficerSpawnSystem => _officerSpawnSystem ?? throw new InvalidOperationException("OfficerSpawnSystem not initialized");

		public SentrySpawnSystem SentrySpawnSystem => _sentrySpawnSystem ?? throw new InvalidOperationException("SentrySpawnSystem not initialized");

		public override void OnInitializeMelon()
		{
			_instance = this;
			InitializeSettings();
			_policeManager = new PoliceManager();
			_officerSpawnSystem = new OfficerSpawnSystem();
			_sentrySpawnSystem = new SentrySpawnSystem();
			((MelonBase)this).LoggerInstance.Msg("Law Enforcement Enhancement Mod v" + ModVersion + " Initialized.");
		}

		private void InitializeSettings()
		{
			try
			{
				string path = Path.Combine(MelonEnvironment.UserDataDirectory, "law_enforcement_settings.json");
				_settings = new ModSettings();
				if (File.Exists(path))
				{
					ModSettings modSettings = JsonConvert.DeserializeObject<ModSettings>(File.ReadAllText(path));
					if (modSettings != null)
					{
						_settings = modSettings;
						((MelonBase)this).LoggerInstance.Msg("Settings loaded successfully.");
					}
				}
				else
				{
					string contents = JsonConvert.SerializeObject((object)_settings, (Formatting)1);
					File.WriteAllText(path, contents);
					((MelonBase)this).LoggerInstance.Msg("Created default settings file.");
				}
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Failed to initialize settings: " + ex.Message);
				_settings = new ModSettings();
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (!sceneName.Contains("Main"))
			{
				return;
			}
			try
			{
				_networkManagerObj = GameObject.Find("NetworkManager");
				if ((Object)(object)_networkManagerObj == (Object)null)
				{
					((MelonBase)this).LoggerInstance.Error("NetworkManager not found in scene!");
					return;
				}
				InitializeModSystems();
				((MelonBase)this).LoggerInstance.Msg("Law Enforcement Enhancement Mod: Scene setup complete.");
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Error in OnSceneWasLoaded: " + ex.Message);
			}
		}

		private void InitializeModSystems()
		{
			try
			{
				_policeManager = new PoliceManager();
				_officerSpawnSystem = new OfficerSpawnSystem();
				_sentrySpawnSystem = new SentrySpawnSystem();
				((MelonBase)this).LoggerInstance.Msg("Mod systems initialized successfully.");
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Failed to initialize mod systems: " + ex.Message);
			}
		}

		public override void OnUpdate()
		{
			if ((Object)(object)_networkManagerObj == (Object)null)
			{
				return;
			}
			try
			{
				_policeManager?.UpdateOfficers(Time.frameCount);
				_officerSpawnSystem?.Update();
				_sentrySpawnSystem?.Update();
				_framesSinceLastCheck++;
				if (_framesSinceLastCheck >= 1800)
				{
					_policeManager?.CleanupOfficers();
					_framesSinceLastCheck = 0;
				}
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Error in OnUpdate: " + ex.Message);
			}
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			try
			{
				_officerSpawnSystem?.OnSceneUnloaded();
				_sentrySpawnSystem?.OnSceneUnloaded();
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Error in OnSceneWasUnloaded: " + ex.Message + "`");
			}
		}

		public override void OnApplicationQuit()
		{
			try
			{
				_policeManager?.CleanupOfficers();
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Error during application quit cleanup: " + ex.Message);
			}
		}
	}
	public class ModSettings
	{
		public bool EnableMod { get; set; } = true;


		public bool DebugMode { get; set; }

		public PatrolSettings Patrol { get; set; }

		public AISettings AI { get; set; }

		public ModSettings()
		{
			Patrol = new PatrolSettings();
			AI = new AISettings();
		}
	}
	public class PatrolSettings
	{
		public float PatrolSpeed { get; set; } = 5f;


		public float PatrolWaitTime { get; set; } = 30f;


		public float PatrolRadius { get; set; } = 50f;


		public int MaxPatrolPoints { get; set; } = 5;


		public bool RandomizePatrolPoints { get; set; } = true;

	}
	public class AISettings
	{
		public float DetectionRange { get; set; } = 20f;


		public float SuspicionThreshold { get; set; } = 0.7f;


		public float InvestigationTime { get; set; } = 60f;


		public bool EnableNightPatrols { get; set; } = true;


		public float NightPatrolSpeedMultiplier { get; set; } = 1.2f;

	}
	[RegisterTypeInIl2Cpp]
	public class ModSpawnedOfficerTag : MonoBehaviour
	{
	}
	public class OfficerSpawnSystem
	{
		private enum DistrictPopulationState
		{
			InitialCheck,
			InitialPopulation,
			VerificationCheck,
			MaintenanceMode
		}

		private enum PatrolPatternType
		{
			Circle,
			Grid,
			Zigzag,
			Star,
			Random
		}

		private class PooledOfficer
		{
			public GameObject? GameObject { get; set; }

			public PoliceOfficer? Officer { get; set; }

			public NetworkObject? NetworkObject { get; set; }

			public DateTime PooledTime { get; set; }
		}

		public class SpawnJob
		{
			public Vector3 Position { get; set; }

			public District? District { get; set; }

			public float Priority { get; set; } = 1f;


			public DateTime QueuedTime { get; set; } = DateTime.Now;

		}

		public class District
		{
			public string Name { get; set; } = string.Empty;


			public Vector3 Center { get; set; }

			public float Radius { get; set; }

			public List<Vector3> SpawnPoints { get; set; } = new List<Vector3>();


			public List<PoliceOfficer> OfficersSpawned { get; set; } = new List<PoliceOfficer>();


			public int TargetOfficers { get; set; }

			public DateTime LastVisited { get; set; } = DateTime.Now;


			public bool ContainsPoint(Vector3 point)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				return Vector3.Distance(Center, point) <= Radius;
			}

			public bool OverlapsWith(District other, float buffer = 10f)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				return Vector3.Distance(Center, other.Center) <= Radius + other.Radius + buffer;
			}
		}

		public class SpawnSystemConfig
		{
			public float SpawnCooldown { get; set; } = 4.5f;


			public float DespawnCooldown { get; set; } = 12f;


			public float PlayerCheckInterval { get; set; } = 6f;


			public float DistrictTransitionCooldown { get; set; } = 20f;


			public bool PreserveDistrictOfficers { get; set; } = true;


			public int MaxSpawnsPerCycle { get; set; } = 1;


			public int MaxDespawnsPerCycle { get; set; } = 1;


			public int MaxLocalOfficers { get; set; } = 8;


			public float LocalOfficerRadius { get; set; } = 90f;


			public float NormalDistrictMaintenanceInterval { get; set; } = 35f;


			public float ReducedDistrictMaintenanceInterval { get; set; } = 350f;


			public int DistrictTransitionBuffer { get; set; } = 2;


			public float MinPatrolRadius { get; set; } = 20f;


			public float MaxPatrolRadius { get; set; } = 40f;


			public int MinPatrolWaypoints { get; set; } = 5;


			public int MaxPatrolWaypoints { get; set; } = 8;


			public bool PopulateAllDistrictsOnStartup { get; set; } = true;


			public bool PreloadAllDistrictOfficers { get; set; }

			public float DelayBeforeSpawning { get; set; } = 10f;


			public int MorningOfficerLimit { get; set; } = 8;


			public int AfternoonOfficerLimit { get; set; } = 14;


			public int EveningOfficerLimit { get; set; } = 20;


			public int NightOfficerLimit { get; set; } = 24;


			public Dictionary<string, int> DistrictMaxOfficers { get; set; } = new Dictionary<string, int>
			{
				{ "Downtown", 4 },
				{ "Eastern District", 4 },
				{ "Western District", 6 },
				{ "Far Western District", 6 },
				{ "Northern District", 4 },
				{ "Southern District", 4 }
			};


			public bool EnableConsoleLogs { get; set; }
		}

		[CompilerGenerated]
		private sealed class <SpawnOfficerCoroutine>d__134 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public OfficerSpawnSystem <>4__this;

			public Vector3 position;

			public District district;

			public bool isForDistrictPopulation;

			private int <i>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SpawnOfficerCoroutine>d__134(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				OfficerSpawnSystem officerSpawnSystem = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (!officerSpawnSystem.SpawnOfficer(position, district, isForDistrictPopulation))
					{
						officerSpawnSystem._consecutiveSpawnFailures++;
						if (officerSpawnSystem._consecutiveSpawnFailures >= 3)
						{
							officerSpawnSystem.LogWarning($"Warning: {officerSpawnSystem._consecutiveSpawnFailures} consecutive spawn failures detected. Possible game state issue.");
							officerSpawnSystem._consecutiveSpawnFailures = 0;
						}
					}
					else
					{
						officerSpawnSystem._consecutiveSpawnFailures = 0;
					}
					<i>5__2 = 0;
					break;
				case 2:
					<>1__state = -1;
					<i>5__2++;
					break;
				}
				if (<i>5__2 < 5)
				{
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				officerSpawnSystem._currentlySpawningOfficer = false;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private bool _gameReady;

		private float _gameReadyCheckTime;

		private float _gameReadyCheckInterval = 1f;

		private int _initFailCount;

		private const int MAX_INIT_FAILURES = 5;

		private float _worldLoadedTime;

		private float _requiredStabilityDelay = 3f;

		private bool _playerMovementDetected;

		private Vector3 _lastCheckedPosition = Vector3.zero;

		private DistrictPopulationState _populationState;

		private bool _needsStatusUpdate = true;

		private DateTime _lastPopulationStateChangeTime = DateTime.Now;

		private DateTime _lastLogDisplayTime = DateTime.MinValue;

		private bool _enableDistrictDebugLogs;

		private bool _enableConsoleLogs;

		private readonly string[] OfficerTypes = new string[11]
		{
			"OfficerBailey", "OfficerCooper", "OfficerGreen", "OfficerHoward", "OfficerJackson", "OfficerLee", "OfficerLeo", "OfficerLopez", "OfficerMurphy", "OfficerOakley",
			"OfficerSanchez"
		};

		private readonly Queue<PooledOfficer> _officerPool = new Queue<PooledOfficer>();

		private const int MAX_POOLED_OFFICERS = 10;

		private readonly Core _core;

		private NetworkManager? _networkManager;

		private bool _initialized;

		private bool _gameFullyLoaded;

		private float _spawnCooldown = 4.5f;

		private float _nextSpawnTime;

		private float _despawnCooldown = 12f;

		private float _nextDespawnTime;

		private float _localOfficerRadius = 90f;

		private int _maxLocalOfficers = 8;

		private Dictionary<string, int> _districtMaxOfficers = new Dictionary<string, int>();

		private int _lastCheckedGameTime = -1;

		private bool _dayDespawnCompleted;

		private float _lastTimeCheckTime;

		private float _timeCheckInterval = 10f;

		private float _normalDistrictMaintenanceInterval = 35f;

		private float _reducedDistrictMaintenanceInterval = 350f;

		private float _districtMaintenanceInterval = 30f;

		private float _lastDistrictMaintenanceTime;

		private float _lastReconciliationTime;

		private float _reconciliationInterval = 15f;

		private DateTime _lastFullDistrictCheckTime = DateTime.MinValue;

		private float _playerCheckInterval = 6f;

		private float _lastPlayerCheckTime;

		private float _districtTransitionCooldown = 20f;

		private float _lastDistrictTransitionTime;

		private Vector3 _lastPlayerPosition = Vector3.zero;

		private District? _currentPlayerDistrict;

		private District? _previousPlayerDistrict;

		private readonly List<PoliceOfficer> _activeOfficers = new List<PoliceOfficer>();

		private readonly Queue<SpawnJob> _spawnQueue = new Queue<SpawnJob>();

		private readonly Queue<PoliceOfficer> _despawnQueue = new Queue<PoliceOfficer>();

		private Dictionary<PoliceOfficer, Vector3> _lastOfficerPositions = new Dictionary<PoliceOfficer, Vector3>();

		private Dictionary<PoliceOfficer, int> _officerStuckCounter = new Dictionary<PoliceOfficer, int>();

		private float _lastStuckCheckTime;

		private float _stuckCheckInterval = 10f;

		private const int STUCK_THRESHOLD = 3;

		private bool _isNinePMMaxSpawnTriggered;

		private float _lastNinePMCheckTime;

		private readonly List<District> _districts = new List<District>();

		private int _morningOfficerLimit = 8;

		private int _afternoonOfficerLimit = 14;

		private int _eveningOfficerLimit = 20;

		private int _nightOfficerLimit = 24;

		private bool _isNightTime;

		private bool _officersShouldBeActive;

		private readonly string _configFilePath;

		private bool _preserveDistrictOfficers = true;

		private int _maxSpawnsPerCycle = 1;

		private int _maxDespawnsPerCycle = 1;

		private int _districtTransitionBuffer = 2;

		private float _minPatrolRadius = 20f;

		private float _maxPatrolRadius = 40f;

		private int _minWaypoints = 5;

		private int _maxWaypoints = 8;

		private float _waypointHeightOffset = 0.2f;

		private bool _populateAllDistrictsOnStartup = true;

		private bool _preloadAllDistrictOfficers;

		private float _delayBeforeSpawning = 15f;

		private float _startupDelayTimer;

		private bool _startupSpawnInitiated;

		private bool _districtsFullyPopulated;

		private float _lastGameSpawnCheck;

		private float _gameSpawnAvoidanceWindow = 0.5f;

		private bool _isGameCurrentlySpawning;

		private int _consecutiveSpawnFailures;

		private const int MAX_SPAWN_FAILURES = 3;

		private Dictionary<PoliceOfficer, string> _officerRouteNames = new Dictionary<PoliceOfficer, string>();

		private int _frameCounter;

		private const int SPAWN_FRAME_INTERVAL = 6;

		private const int MAINTENANCE_FRAME_INTERVAL = 30;

		private bool _currentlySpawningOfficer;

		private int _districtOfficerCount;

		private int _maxDistrictOfficers;

		private Dictionary<string, GameObject> _patrolRouteObjects = new Dictionary<string, GameObject>();

		private float _lastUpdateTime;

		public OfficerSpawnSystem()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			_core = Core.Instance;
			_configFilePath = Path.Combine(MelonEnvironment.UserDataDirectory, "law_user_config.json");
			LoadConfig();
			InitializeDistricts();
			((MelonEventBase<LemonAction<int, string>>)(object)MelonEvents.OnSceneWasLoaded).Subscribe((LemonAction<int, string>)OnSceneWasLoaded, 0, false);
		}

		private void Log(string message)
		{
			if (_enableConsoleLogs)
			{
				((MelonBase)_core).LoggerInstance.Msg(message);
			}
		}

		private void LogWarning(string message)
		{
			if (_enableConsoleLogs)
			{
				((MelonBase)_core).LoggerInstance.Warning(message);
			}
		}

		private bool IsModSpawnedOfficer(PoliceOfficer officer)
		{
			if ((Object)(object)officer == (Object)null || (Object)(object)((Component)officer).gameObject == (Object)null)
			{
				return false;
			}
			return (Object)(object)((Component)officer).gameObject.GetComponent<ModSpawnedOfficerTag>() != (Object)null;
		}

		private void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			Log("Scene loaded: " + sceneName + ", preparing initialization");
			_gameReady = false;
			_gameReadyCheckTime = 0f;
			_initFailCount = 0;
			_playerMovementDetected = false;
			_lastCheckedPosition = Vector3.zero;
			_worldLoadedTime = Time.time;
			_lastCheckedGameTime = -1;
			_dayDespawnCompleted = false;
			_isNightTime = false;
			_officersShouldBeActive = false;
			try
			{
				OnSceneUnloaded();
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Error cleaning up previous scene: " + ex.Message);
			}
		}

		private void LoadConfig()
		{
			try
			{
				if (File.Exists(_configFilePath))
				{
					SpawnSystemConfig spawnSystemConfig = JsonConvert.DeserializeObject<SpawnSystemConfig>(File.ReadAllText(_configFilePath));
					if (spawnSystemConfig != null)
					{
						_spawnCooldown = spawnSystemConfig.SpawnCooldown;
						_despawnCooldown = spawnSystemConfig.DespawnCooldown;
						_playerCheckInterval = spawnSystemConfig.PlayerCheckInterval;
						_districtTransitionCooldown = spawnSystemConfig.DistrictTransitionCooldown;
						_preserveDistrictOfficers = spawnSystemConfig.PreserveDistrictOfficers;
						_maxSpawnsPerCycle = spawnSystemConfig.MaxSpawnsPerCycle;
						_maxDespawnsPerCycle = spawnSystemConfig.MaxDespawnsPerCycle;
						_maxLocalOfficers = spawnSystemConfig.MaxLocalOfficers;
						_localOfficerRadius = spawnSystemConfig.LocalOfficerRadius;
						_normalDistrictMaintenanceInterval = spawnSystemConfig.NormalDistrictMaintenanceInterval;
						_reducedDistrictMaintenanceInterval = spawnSystemConfig.ReducedDistrictMaintenanceInterval;
						_districtTransitionBuffer = spawnSystemConfig.DistrictTransitionBuffer;
						_minPatrolRadius = spawnSystemConfig.MinPatrolRadius;
						_maxPatrolRadius = spawnSystemConfig.MaxPatrolRadius;
						_minWaypoints = spawnSystemConfig.MinPatrolWaypoints;
						_maxWaypoints = spawnSystemConfig.MaxPatrolWaypoints;
						_populateAllDistrictsOnStartup = spawnSystemConfig.PopulateAllDistrictsOnStartup;
						_preloadAllDistrictOfficers = spawnSystemConfig.PreloadAllDistrictOfficers;
						_delayBeforeSpawning = spawnSystemConfig.DelayBeforeSpawning;
						_morningOfficerLimit = spawnSystemConfig.MorningOfficerLimit;
						_afternoonOfficerLimit = spawnSystemConfig.AfternoonOfficerLimit;
						_eveningOfficerLimit = spawnSystemConfig.EveningOfficerLimit;
						_nightOfficerLimit = spawnSystemConfig.NightOfficerLimit;
						if (spawnSystemConfig.DistrictMaxOfficers != null && spawnSystemConfig.DistrictMaxOfficers.Count > 0)
						{
							_districtMaxOfficers = spawnSystemConfig.DistrictMaxOfficers;
						}
						else
						{
							_districtMaxOfficers["Downtown"] = 10;
							_districtMaxOfficers["Eastern District"] = 5;
							_districtMaxOfficers["Western District"] = 8;
							_districtMaxOfficers["Far Western District"] = 8;
							_districtMaxOfficers["Northern District"] = 10;
							_districtMaxOfficers["Southern District"] = 6;
						}
						_enableConsoleLogs = spawnSystemConfig.EnableConsoleLogs;
						Log("Loaded officer spawn system configuration from " + _configFilePath);
					}
				}
				else
				{
					SaveDefaultConfig();
				}
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Failed to load config: " + ex.Message);
				SaveDefaultConfig();
			}
		}

		private void SaveDefaultConfig()
		{
			try
			{
				if (_districtMaxOfficers.Count == 0)
				{
					_districtMaxOfficers["Downtown"] = 4;
					_districtMaxOfficers["Eastern District"] = 4;
					_districtMaxOfficers["Western District"] = 6;
					_districtMaxOfficers["Far Western District"] = 6;
					_districtMaxOfficers["Northern District"] = 4;
					_districtMaxOfficers["Southern District"] = 4;
				}
				string contents = JsonConvert.SerializeObject((object)new SpawnSystemConfig
				{
					SpawnCooldown = _spawnCooldown,
					DespawnCooldown = _despawnCooldown,
					PlayerCheckInterval = _playerCheckInterval,
					DistrictTransitionCooldown = _districtTransitionCooldown,
					PreserveDistrictOfficers = _preserveDistrictOfficers,
					MaxSpawnsPerCycle = _maxSpawnsPerCycle,
					MaxDespawnsPerCycle = _maxDespawnsPerCycle,
					MaxLocalOfficers = _maxLocalOfficers,
					LocalOfficerRadius = _localOfficerRadius,
					NormalDistrictMaintenanceInterval = _normalDistrictMaintenanceInterval,
					ReducedDistrictMaintenanceInterval = _reducedDistrictMaintenanceInterval,
					DistrictTransitionBuffer = _districtTransitionBuffer,
					MinPatrolRadius = _minPatrolRadius,
					MaxPatrolRadius = _maxPatrolRadius,
					MinPatrolWaypoints = _minWaypoints,
					MaxPatrolWaypoints = _maxWaypoints,
					PopulateAllDistrictsOnStartup = _populateAllDistrictsOnStartup,
					PreloadAllDistrictOfficers = _preloadAllDistrictOfficers,
					DelayBeforeSpawning = _delayBeforeSpawning,
					MorningOfficerLimit = _morningOfficerLimit,
					AfternoonOfficerLimit = _afternoonOfficerLimit,
					EveningOfficerLimit = _eveningOfficerLimit,
					NightOfficerLimit = _nightOfficerLimit,
					DistrictMaxOfficers = _districtMaxOfficers,
					EnableConsoleLogs = _enableConsoleLogs
				}, (Formatting)1);
				File.WriteAllText(_configFilePath, contents);
				Log("Created default configuration at " + _configFilePath);
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Failed to save default config: " + ex.Message);
			}
		}

		private void InitializeDistricts()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_044b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0450: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_046c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_0488: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_050f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0514: Unknown result type (might be due to invalid IL or missing references)
			//IL_052b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0530: Unknown result type (might be due to invalid IL or missing references)
			//IL_0547: Unknown result type (might be due to invalid IL or missing references)
			//IL_054c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0563: Unknown result type (might be due to invalid IL or missing references)
			//IL_0568: Unknown result type (might be due to invalid IL or missing references)
			//IL_057f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0584: Unknown result type (might be due to invalid IL or missing references)
			//IL_059b: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_060b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0610: Unknown result type (might be due to invalid IL or missing references)
			//IL_0627: Unknown result type (might be due to invalid IL or missing references)
			//IL_062c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0643: Unknown result type (might be due to invalid IL or missing references)
			//IL_0648: Unknown result type (might be due to invalid IL or missing references)
			//IL_065f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0664: Unknown result type (might be due to invalid IL or missing references)
			//IL_067b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0680: Unknown result type (might be due to invalid IL or missing references)
			//IL_0697: Unknown result type (might be due to invalid IL or missing references)
			//IL_069c: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0707: Unknown result type (might be due to invalid IL or missing references)
			//IL_070c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0723: Unknown result type (might be due to invalid IL or missing references)
			//IL_0728: Unknown result type (might be due to invalid IL or missing references)
			//IL_073f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0744: Unknown result type (might be due to invalid IL or missing references)
			//IL_075b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0760: Unknown result type (might be due to invalid IL or missing references)
			//IL_0777: Unknown result type (might be due to invalid IL or missing references)
			//IL_077c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0793: Unknown result type (might be due to invalid IL or missing references)
			//IL_0798: Unknown result type (might be due to invalid IL or missing references)
			//IL_07af: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0803: Unknown result type (might be due to invalid IL or missing references)
			//IL_0808: Unknown result type (might be due to invalid IL or missing references)
			//IL_081f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0824: Unknown result type (might be due to invalid IL or missing references)
			//IL_083b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0840: Unknown result type (might be due to invalid IL or missing references)
			//IL_0850: Unknown result type (might be due to invalid IL or missing references)
			//IL_0855: Unknown result type (might be due to invalid IL or missing references)
			//IL_0879: Unknown result type (might be due to invalid IL or missing references)
			//IL_087d: Unknown result type (might be due to invalid IL or missing references)
			//IL_08bb: Unknown result type (might be due to invalid IL or missing references)
			_districts.Clear();
			District item = new District
			{
				Name = "Downtown",
				Center = new Vector3(0f, 0f, 40f),
				Radius = 50f,
				TargetOfficers = GetDistrictMaxOfficers("Downtown"),
				SpawnPoints = new List<Vector3>()
			};
			District item2 = new District
			{
				Name = "Eastern District",
				Center = new Vector3(100f, 0f, 0f),
				Radius = 120f,
				TargetOfficers = GetDistrictMaxOfficers("Eastern District"),
				SpawnPoints = new List<Vector3>()
			};
			District item3 = new District
			{
				Name = "Western District",
				Center = new Vector3(-80f, 0f, 0f),
				Radius = 80f,
				TargetOfficers = GetDistrictMaxOfficers("Western District"),
				SpawnPoints = new List<Vector3>()
			};
			District item4 = new District
			{
				Name = "Far Western District",
				Center = new Vector3(-150f, 0f, 80f),
				Radius = 80f,
				TargetOfficers = GetDistrictMaxOfficers("Far Western District"),
				SpawnPoints = new List<Vector3>()
			};
			District item5 = new District
			{
				Name = "Northern District",
				Center = new Vector3(0f, 0f, 120f),
				Radius = 80f,
				TargetOfficers = GetDistrictMaxOfficers("Northern District"),
				SpawnPoints = new List<Vector3>()
			};
			District item6 = new District
			{
				Name = "Southern District",
				Center = new Vector3(0f, 0f, -80f),
				Radius = 100f,
				TargetOfficers = GetDistrictMaxOfficers("Southern District"),
				SpawnPoints = new List<Vector3>()
			};
			_districts.Add(item);
			_districts.Add(item2);
			_districts.Add(item3);
			_districts.Add(item4);
			_districts.Add(item5);
			_districts.Add(item6);
			Vector3[] array = (Vector3[])(object)new Vector3[55]
			{
				new Vector3(-71.45f, 0.97f, 75.85f),
				new Vector3(-71.47f, -1.3f, 46.21f),
				new Vector3(-22.2f, 1.07f, 72.23f),
				new Vector3(-22.32f, 1.07f, 101.65f),
				new Vector3(-29.85f, -2.94f, 137.92f),
				new Vector3(-48.01f, -4.03f, 167.29f),
				new Vector3(-37.16f, -3.03f, 168.8f),
				new Vector3(-78.48f, -2.1f, 113.7f),
				new Vector3(-73.82f, -2.94f, 136.79f),
				new Vector3(-102.9f, -2.95f, 134.23f),
				new Vector3(-105.01f, -2.39f, 118.26f),
				new Vector3(-131.49f, -2.77f, 130.55f),
				new Vector3(-162.51f, -3.03f, 133.09f),
				new Vector3(-167.84f, -2.94f, 84.17f),
				new Vector3(-147.63f, -2.96f, 60.41f),
				new Vector3(-140.34f, -2.94f, 37.37f),
				new Vector3(-122.01f, -3.03f, 27.4f),
				new Vector3(-135.37f, -2.96f, 60.58f),
				new Vector3(-118.52f, -2.94f, 77.56f),
				new Vector3(-143.94f, -3.03f, 85.16f),
				new Vector3(-130.27f, -3.03f, 98.29f),
				new Vector3(-148.46f, -3.01f, 106.75f),
				new Vector3(-140.68f, -3.03f, 116.8f),
				new Vector3(-110.72f, -2.93f, 87.72f),
				new Vector3(-47.86f, 1.07f, 61.94f),
				new Vector3(10.4f, 0.97f, 78.1f),
				new Vector3(29.06f, 1.02f, 100.08f),
				new Vector3(56.68f, 1.07f, 83.01f),
				new Vector3(74.79f, 1.02f, 98.62f),
				new Vector3(111.3f, 1.07f, 72.78f),
				new Vector3(127.86f, 1.07f, 86.5f),
				new Vector3(137.5f, 1.02f, 63.43f),
				new Vector3(127.37f, 0.97f, 43.81f),
				new Vector3(101.93f, 1.06f, 29.7f),
				new Vector3(82.99f, 1.07f, 33.83f),
				new Vector3(99.24f, 0.98f, 2.68f),
				new Vector3(126.18f, 1.03f, 16.27f),
				new Vector3(128.73f, 1.14f, 3.58f),
				new Vector3(98.6f, 0.95f, -16.96f),
				new Vector3(75.62f, 1.07f, 0.43f),
				new Vector3(55.74f, 1.17f, -0.7f),
				new Vector3(49.81f, 1.07f, 18.16f),
				new Vector3(24.19f, 0.97f, 20.85f),
				new Vector3(-10.99f, 0.97f, 7.65f),
				new Vector3(-23.35f, 1.07f, -19.58f),
				new Vector3(-11.51f, 0.98f, -52.11f),
				new Vector3(-38.18f, -1.41f, -65.73f),
				new Vector3(-50.05f, -1.54f, -53.82f),
				new Vector3(-70.17f, -1.53f, -36.96f),
				new Vector3(-12.13f, 0.91f, -79.86f),
				new Vector3(62.28f, 4.96f, -94.93f),
				new Vector3(90.62f, 4.96f, -111.36f),
				new Vector3(105.26f, 5.05f, -111.22f),
				new Vector3(138.35f, 4.96f, -97.37f),
				new Vector3(97.69f, 4.96f, -78.33f)
			};
			foreach (Vector3 val in array)
			{
				District district = null;
				float num = float.MaxValue;
				foreach (District district2 in _districts)
				{
					float num2 = Vector3.Distance(val, district2.Center);
					if (num2 < num)
					{
						num = num2;
						district = district2;
					}
				}
				district?.SpawnPoints.Add(val);
			}
			_maxDistrictOfficers = _districts.Sum((District d) => d.TargetOfficers);
			Log($"Initialized {_districts.Count} districts with {_districts.Sum((District d) => d.SpawnPoints.Count)} total spawn points");
			foreach (District district3 in _districts)
			{
				Log($"  {district3.Name}: {district3.SpawnPoints.Count} spawn points, target {district3.TargetOfficers} officers");
			}
			Log($"District population requires {_maxDistrictOfficers} officers");
		}

		private int GetDistrictMaxOfficers(string districtName)
		{
			if (_districtMaxOfficers.ContainsKey(districtName))
			{
				return _districtMaxOfficers[districtName];
			}
			return 4;
		}

		private void UpdateDistrictTargetOfficers()
		{
			int currentOfficerLimit = GetCurrentOfficerLimit();
			int num = currentOfficerLimit / _districts.Count;
			int num2 = currentOfficerLimit % _districts.Count;
			Log($"Updating district targets: {currentOfficerLimit} total officers, {num} base per district, {num2} remaining");
			for (int i = 0; i < _districts.Count; i++)
			{
				District district = _districts[i];
				int num3 = num;
				if (i < num2)
				{
					num3++;
				}
				int districtMaxOfficers = GetDistrictMaxOfficers(district.Name);
				if (num3 > districtMaxOfficers)
				{
					num3 = districtMaxOfficers;
				}
				district.TargetOfficers = num3;
				Log($"  {district.Name}: Target set to {num3} officers");
			}
			_maxDistrictOfficers = _districts.Sum((District d) => d.TargetOfficers);
			Log($"Updated district targets, total: {_maxDistrictOfficers}");
		}

		public void Initialize()
		{
			_lastUpdateTime = Time.time;
			_lastPlayerCheckTime = Time.time;
			_lastNinePMCheckTime = Time.time;
			_lastTimeCheckTime = Time.time;
			_lastDistrictTransitionTime = Time.time;
			_lastDistrictMaintenanceTime = Time.time;
			_lastReconciliationTime = Time.time;
			_lastStuckCheckTime = Time.time;
			_lastFullDistrictCheckTime = DateTime.Now;
			_lastLogDisplayTime = DateTime.Now;
			_initialized = true;
			_startupSpawnInitiated = false;
			_startupDelayTimer = 0f;
			_districtMaintenanceInterval = _normalDistrictMaintenanceInterval;
			_populationState = DistrictPopulationState.InitialCheck;
			_needsStatusUpdate = true;
			_lastPopulationStateChangeTime = DateTime.Now;
			_lastCheckedGameTime = -1;
			_dayDespawnCompleted = false;
			_isNightTime = false;
			_officersShouldBeActive = false;
			UpdateDistrictTargetOfficers();
			Log("District-based officer spawn system initialized");
		}

		private void InitiateStartupSpawning()
		{
			if (_startupSpawnInitiated)
			{
				return;
			}
			Log("Game has stabilized - beginning district population");
			_startupSpawnInitiated = true;
			if (_populateAllDistrictsOnStartup)
			{
				if (_preloadAllDistrictOfficers)
				{
					Log("Preloading all district officers at once");
					PreloadDistrictOfficers();
				}
				else
				{
					QueueInitialDistrictPopulation();
				}
			}
		}

		public void Update()
		{
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!_gameReady)
				{
					if (!(Time.time > _gameReadyCheckTime))
					{
						return;
					}
					_gameReadyCheckTime = Time.time + _gameReadyCheckInterval;
					if ((Object)(object)_networkManager == (Object)null)
					{
						_networkManager = Object.FindObjectOfType<NetworkManager>();
						if ((Object)(object)_networkManager == (Object)null)
						{
							_initFailCount++;
							if (_initFailCount % 3 == 0)
							{
								Log("Waiting for NetworkManager...");
							}
							return;
						}
					}
					if (!_initialized)
					{
						Initialize();
					}
					float num = Time.time - _worldLoadedTime;
					if (num < _requiredStabilityDelay)
					{
						if (_initFailCount % 3 == 0)
						{
							Log($"Waiting for world to stabilize: {num:F1}/{_requiredStabilityDelay} seconds");
						}
						_initFailCount++;
						return;
					}
					GameObject val = GameObject.Find("Player_Local");
					if (!((Object)(object)val != (Object)null))
					{
						_initFailCount++;
						if (_initFailCount % 3 == 0)
						{
							Log("Waiting for player object...");
						}
						if (_initFailCount >= 5)
						{
							_gameReady = true;
							_gameFullyLoaded = true;
							Log("Forcing initialization after multiple attempts");
						}
						return;
					}
					Vector3 position = val.transform.position;
					if (_lastCheckedPosition == Vector3.zero)
					{
						_lastCheckedPosition = position;
						if (_initFailCount % 3 == 0)
						{
							Log("Found player, waiting for movement detection...");
						}
						_initFailCount++;
						return;
					}
					if (!_playerMovementDetected)
					{
						if (!(Vector3.Distance(_lastCheckedPosition, position) > 0.1f))
						{
							_lastCheckedPosition = position;
							if (_initFailCount % 5 == 0)
							{
								Log("Waiting for player movement...");
							}
							_initFailCount++;
							return;
						}
						_playerMovementDetected = true;
						Log("Player movement detected, initializing officer system");
					}
					_lastPlayerPosition = position;
					_gameReady = true;
					_gameFullyLoaded = true;
					Log("Game fully initialized, beginning officer spawning");
				}
				float time = Time.time;
				_frameCounter++;
				try
				{
					if (_gameFullyLoaded && !_startupSpawnInitiated)
					{
						_startupDelayTimer += Time.deltaTime;
						if (_startupDelayTimer >= _delayBeforeSpawning)
						{
							InitiateStartupSpawning();
						}
					}
					if (_gameReady && time - _lastTimeCheckTime >= _timeCheckInterval)
					{
						_lastTimeCheckTime = time;
						CheckGameTime();
					}
					if (_officersShouldBeActive)
					{
						_dayDespawnCompleted = false;
						if (time - _lastPlayerCheckTime >= _playerCheckInterval)
						{
							_lastPlayerCheckTime = time;
							CheckPlayerDistrict();
						}
						if (time - _lastReconciliationTime >= _reconciliationInterval)
						{
							_lastReconciliationTime = time;
							ReconcileDistrictOfficers();
						}
						if (time - _lastStuckCheckTime >= _stuckCheckInterval)
						{
							_lastStuckCheckTime = time;
							CheckForStuckOfficers();
						}
						if (_frameCounter % 30 == 0 && time - _lastDistrictMaintenanceTime >= _districtMaintenanceInterval)
						{
							_lastDistrictMaintenanceTime = time;
							EnsureAllDistrictsHaveTargetOfficers();
						}
						if (_frameCounter % 6 == 0 && time >= _nextSpawnTime && _spawnQueue.Count > 0)
						{
							_nextSpawnTime = time + _spawnCooldown;
							ProcessSpawnQueue();
						}
					}
					else if (!_dayDespawnCompleted && _activeOfficers.Count > 0)
					{
						((MelonBase)_core).LoggerInstance.Msg("Day time or early morning: Performing one-time officer cleanup");
						DespawnAllOfficersImmediately();
						_dayDespawnCompleted = true;
					}
					if (time >= _nextDespawnTime && _despawnQueue.Count > 0)
					{
						_nextDespawnTime = time + _despawnCooldown;
						ProcessDespawnQueue();
					}
					if (time - _lastUpdateTime >= 15f)
					{
						_lastUpdateTime = time;
						LogOfficerCounts();
						CleanOldPooledOfficers();
					}
					if ((double)Random.value < 0.01)
					{
						CleanupInvalidOfficers();
					}
					if ((double)Random.value < 0.001)
					{
						GC.Collect();
					}
				}
				catch (Exception ex)
				{
					((MelonBase)_core).LoggerInstance.Error("Error in Update: " + ex.Message + "\n" + ex.StackTrace);
				}
			}
			catch (Exception ex2)
			{
				((MelonBase)_core).LoggerInstance.Error("Critical error in Update: " + ex2.Message + "\n" + ex2.StackTrace);
			}
		}

		private void CheckGameTime()
		{
			TimeManager val = Object.FindObjectOfType<TimeManager>();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int currentTime = val.CurrentTime;
			if (_lastCheckedGameTime != -1 && (currentTime < _lastCheckedGameTime || currentTime > _lastCheckedGameTime + 100))
			{
				Log($"Detected time jump: {_lastCheckedGameTime} -> {currentTime}. Refreshing officer status.");
				bool isNightTime = _isNightTime;
				_isNightTime = currentTime >= 2100 || currentTime < 600;
				if (isNightTime != _isNightTime)
				{
					if (_isNightTime)
					{
						Log("Night time after time jump. Activating officers.");
						_officersShouldBeActive = true;
						_isNinePMMaxSpawnTriggered = true;
						_dayDespawnCompleted = false;
					}
					else
					{
						Log("Day time after time jump. Deactivating officers.");
						_officersShouldBeActive = false;
						_isNinePMMaxSpawnTriggered = false;
						if (!_dayDespawnCompleted && _activeOfficers.Count > 0)
						{
							DespawnAllOfficersImmediately();
							_dayDespawnCompleted = true;
						}
					}
				}
			}
			_lastCheckedGameTime = currentTime;
			int value;
			bool flag;
			if (currentTime >= 600 && currentTime < 1200)
			{
				value = 1;
				flag = true;
			}
			else if (currentTime >= 1200 && currentTime < 1800)
			{
				value = 2;
				flag = true;
			}
			else if (currentTime >= 1800 && currentTime < 2100)
			{
				value = 3;
				flag = true;
			}
			else
			{
				value = 4;
				flag = true;
				if (currentTime >= 2100 && !_isNinePMMaxSpawnTriggered)
				{
					_isNinePMMaxSpawnTriggered = true;
					Log("9 PM detected - Initiating night officer spawning protocol");
				}
			}
			if (flag != _officersShouldBeActive)
			{
				_officersShouldBeActive = flag;
				if (_officersShouldBeActive)
				{
					Log($"Time period {value} detected. Activating officers.");
					_dayDespawnCompleted = false;
				}
				else
				{
					Log("Inactive time period detected. Deactivating officers.");
					if (!_dayDespawnCompleted && _activeOfficers.Count > 0)
					{
						DespawnAllOfficersImmediately();
						_dayDespawnCompleted = true;
					}
				}
			}
			bool flag2 = currentTime >= 2100 || currentTime < 600;
			if (flag2 == _isNightTime)
			{
				return;
			}
			_isNightTime = flag2;
			if (!_isNightTime)
			{
				Log("Day time detected (< 9 PM). Resetting night spawning flag.");
				_isNinePMMaxSpawnTriggered = false;
				if (!_dayDespawnCompleted && _activeOfficers.Count > 0)
				{
					DespawnAllOfficersImmediately();
					_dayDespawnCompleted = true;
				}
			}
		}

		private void DespawnAllOfficersImmediately()
		{
			((MelonBase)_core).LoggerInstance.Msg($"Day change detected - despawning all {_activeOfficers.Count} officers");
			foreach (PoliceOfficer item in new List<PoliceOfficer>(_activeOfficers))
			{
				if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null)
				{
					DespawnOfficer(item);
				}
			}
			_despawnQueue.Clear();
			foreach (District district in _districts)
			{
				district.OfficersSpawned.Clear();
			}
			_populationState = DistrictPopulationState.InitialCheck;
			_needsStatusUpdate = true;
			_districtOfficerCount = 0;
			_districtsFullyPopulated = false;
			if (_activeOfficers.Count > 0)
			{
				((MelonBase)_core).LoggerInstance.Msg($"WARNING: {_activeOfficers.Count} officers still active after immediate despawn!");
			}
			else
			{
				Log("All officers successfully despawned");
			}
			GC.Collect();
			GC.WaitForPendingFinalizers();
		}

		private void ReconcileDistrictOfficers()
		{
			int num = 0;
			foreach (District district in _districts)
			{
				for (int num2 = district.OfficersSpawned.Count - 1; num2 >= 0; num2--)
				{
					PoliceOfficer val = district.OfficersSpawned[num2];
					if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || !((Component)val).gameObject.activeInHierarchy)
					{
						district.OfficersSpawned.RemoveAt(num2);
						num++;
						if (!_districtsFullyPopulated)
						{
							_districtOfficerCount = Math.Max(0, _districtOfficerCount - 1);
						}
					}
				}
			}
			if (num > 0)
			{
				Log($"Reconciliation found and removed {num} despawned officers from district counts");
				CleanupInvalidOfficers();
				if (_populationState == DistrictPopulationState.MaintenanceMode && num > 5)
				{
					_populationState = DistrictPopulationState.InitialCheck;
					_needsStatusUpdate = true;
					Log("Significant officer loss detected. Restarting district population process.");
				}
			}
		}

		private void CheckForStuckOfficers()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (PoliceOfficer item in new List<PoliceOfficer>(_activeOfficers))
			{
				if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null)
				{
					continue;
				}
				Vector3 position = ((Component)item).transform.position;
				if (!_lastOfficerPositions.ContainsKey(item))
				{
					_lastOfficerPositions[item] = position;
					_officerStuckCounter[item] = 0;
					continue;
				}
				if (Vector3.Distance(_lastOfficerPositions[item], position) < 0.1f)
				{
					_officerStuckCounter[item] = ((!_officerStuckCounter.ContainsKey(item)) ? 1 : (_officerStuckCounter[item] + 1));
				}
				else
				{
					_officerStuckCounter[item] = 0;
				}
				_lastOfficerPositions[item] = position;
				if (_officerStuckCounter.ContainsKey(item) && _officerStuckCounter[item] >= 3)
				{
					if (FixStuckOfficer(item))
					{
						num++;
					}
					_officerStuckCounter[item] = 0;
				}
			}
			List<PoliceOfficer> list = new List<PoliceOfficer>();
			foreach (PoliceOfficer key in _lastOfficerPositions.Keys)
			{
				if ((Object)(object)key != (Object)null && ((Object)(object)((Component)key).gameObject == (Object)null || !((Component)key).gameObject.activeInHierarchy))
				{
					list.Add(key);
				}
			}
			foreach (PoliceOfficer item2 in list)
			{
				_lastOfficerPositions.Remove(item2);
				_officerStuckCounter.Remove(item2);
			}
			if (num > 0)
			{
				Log($"Fixed {num} stuck officers");
			}
		}

		private bool FixStuckOfficer(PoliceOfficer officer)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			try
			{
				if ((Object)(object)officer == (Object)null || (Object)(object)((Component)officer).gameObject == (Object)null)
				{
					return false;
				}
				if (!IsModSpawnedOfficer(officer))
				{
					return false;
				}
				NPCMovement movement = ((NPC)officer).Movement;
				if ((Object)(object)movement == (Object)null)
				{
					return false;
				}
				NavMeshAgent agent = movement.Agent;
				if ((Object)(object)agent == (Object)null)
				{
					return false;
				}
				NavMeshHit val = default(NavMeshHit);
				if (NavMesh.SamplePosition(((Component)officer).transform.position, ref val, 10f, -1))
				{
					SafeInvokeMethod(agent, "Warp", new object[1] { ((NavMeshHit)(ref val)).position });
					string value = null;
					if (_officerRouteNames.TryGetValue(officer, out value) && value != null)
					{
						GameObject value2 = null;
						if (_patrolRouteObjects.TryGetValue(value, out value2) && (Object)(object)value2 != (Object)null)
						{
							FootPatrolRoute component = value2.GetComponent<FootPatrolRoute>();
							if ((Object)(object)component != (Object)null)
							{
								PatrolGroup val2 = new PatrolGroup(component);
								officer.StartFootPatrol(val2, true);
							}
						}
					}
					return true;
				}
				District district = null;
				foreach (District district2 in _districts)
				{
					if (district2.OfficersSpawned.Contains(officer))
					{
						district = district2;
						break;
					}
				}
				if (district != null)
				{
					QueueDespawn(officer);
					QueueSpawnInDistrict(district, 2f);
					return true;
				}
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Error fixing stuck officer: " + ex.Message);
			}
			return false;
		}

		private void SafeSetProperty(object obj, string propertyName, object value)
		{
			try
			{
				PropertyInfo property = obj.GetType().GetProperty(propertyName);
				if (property != null && property.CanWrite)
				{
					property.SetValue(obj, value);
				}
			}
			catch
			{
			}
		}

		private T SafeGetProperty<T>(object obj, string propertyName, T defaultValue)
		{
			try
			{
				PropertyInfo property = obj.GetType().GetProperty(propertyName);
				if (property != null && property.CanRead)
				{
					return (T)property.GetValue(obj);
				}
			}
			catch
			{
			}
			return defaultValue;
		}

		private void SafeInvokeMethod(object obj, string methodName, object[] args)
		{
			try
			{
				MethodInfo method = obj.GetType().GetMethod(methodName);
				if (method != null)
				{
					method.Invoke(obj, args);
				}
			}
			catch
			{
			}
		}

		private void PreloadDistrictOfficers()
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_networkManager == (Object)null)
				{
					return;
				}
				Log($"Beginning immediate preload of {_maxDistrictOfficers} district officers");
				int num = 0;
				foreach (District district in _districts)
				{
					int targetOfficers = district.TargetOfficers;
					Log($"Preloading {targetOfficers} officers for {district.Name}");
					for (int i = 0; i < targetOfficers; i++)
					{
						if (district.SpawnPoints.Count == 0)
						{
							continue;
						}
						int index = Random.Range(0, district.SpawnPoints.Count);
						Vector3 position = district.SpawnPoints[index];
						if (SpawnOfficer(position, district, isForDistrictPopulation: true))
						{
							num++;
							if (num % 5 == 0)
							{
								GC.Collect();
								GC.WaitForPendingFinalizers();
							}
						}
					}
				}
				if (num >= _maxDistrictOfficers)
				{
					_districtsFullyPopulated = true;
					_populationState = DistrictPopulationState.MaintenanceMode;
					_districtMaintenanceInterval = _reducedDistrictMaintenanceInterval;
					Log($"Successfully preloaded {num} district officers");
					Log("All districts fully populated! Switching to maintenance mode.");
				}
				else
				{
					_populationState = DistrictPopulationState.VerificationCheck;
					Log($"Partially preloaded {num}/{_maxDistrictOfficers} district officers, checking gaps...");
				}
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Error during district officer preload: " + ex.Message);
				QueueInitialDistrictPopulation();
			}
		}

		private void QueueInitialDistrictPopulation()
		{
			_populationState = DistrictPopulationState.InitialCheck;
			_needsStatusUpdate = true;
			foreach (District district in _districts)
			{
				int num = Math.Max(0, district.TargetOfficers - district.OfficersSpawned.Count);
				if (num > 0)
				{
					Log($"Queueing {num} officers for initial population in {district.Name}");
					for (int i = 0; i < num; i++)
					{
						QueueSpawnInDistrict(district, 1.5f);
					}
				}
				else
				{
					Log($"Skipping {district.Name} - already at target ({district.OfficersSpawned.Count}/{district.TargetOfficers})");
				}
			}
		}

		public int GetCurrentOfficerLimit()
		{
			TimeManager val = Object.FindObjectOfType<TimeManager>();
			if ((Object)(object)val == (Object)null)
			{
				return _nightOfficerLimit;
			}
			int currentTime = val.CurrentTime;
			if (currentTime >= 2100 || _isNinePMMaxSpawnTriggered)
			{
				return _nightOfficerLimit;
			}
			if (currentTime >= 600 && currentTime < 1200)
			{
				return _morningOfficerLimit;
			}
			if (currentTime >= 1200 && currentTime < 1800)
			{
				return _afternoonOfficerLimit;
			}
			if (currentTime >= 1800 && currentTime < 2100)
			{
				return _eveningOfficerLimit;
			}
			return _nightOfficerLimit;
		}

		public int GetTotalOfficerCount(bool excludeDistrictPopulation = false)
		{
			if (excludeDistrictPopulation && !_districtsFullyPopulated)
			{
				return Math.Max(0, _activeOfficers.Count - _districtOfficerCount);
			}
			return _activeOfficers.Count;
		}

		private int GetLocalOfficerCount()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (_lastPlayerPosition == Vector3.zero)
			{
				return 0;
			}
			int num = 0;
			foreach (PoliceOfficer activeOfficer in _activeOfficers)
			{
				if ((Object)(object)activeOfficer != (Object)null && (Object)(object)((Component)activeOfficer).gameObject != (Object)null && Vector3.Distance(((Component)activeOfficer).gameObject.transform.position, _lastPlayerPosition) <= _localOfficerRadius)
				{
					num++;
				}
			}
			return num;
		}

		private void CheckForNinePM()
		{
			try
			{
				TimeManager val = Object.FindObjectOfType<TimeManager>();
				if (!((Object)(object)val == (Object)null))
				{
					int currentTime = val.CurrentTime;
					if (currentTime >= 2100 && !_isNinePMMaxSpawnTriggered)
					{
						Log("9 PM detected - Initiating maximum officer spawning protocol");
						_isNinePMMaxSpawnTriggered = true;
						QueueOfficersForNinePM();
					}
					else if (currentTime < 2100 && _isNinePMMaxSpawnTriggered && _lastCheckedGameTime > 2100 && currentTime < 600)
					{
						_isNinePMMaxSpawnTriggered = false;
						Log("New day detected - Resetting maximum officer spawning protocol");
					}
				}
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Error checking for 9 PM: " + ex.Message);
			}
		}

		private void QueueOfficersForNinePM()
		{
			int currentOfficerLimit = GetCurrentOfficerLimit();
			int totalOfficerCount = GetTotalOfficerCount();
			int num = currentOfficerLimit - totalOfficerCount;
			if (num <= 0)
			{
				return;
			}
			if (_currentPlayerDistrict != null)
			{
				int val = Math.Max(0, _currentPlayerDistrict.TargetOfficers - _currentPlayerDistrict.OfficersSpawned.Count);
				int num2 = Math.Min(num / 2, val);
				if (num2 > 0)
				{
					for (int i = 0; i < num2; i++)
					{
						QueueSpawnInDistrict(_currentPlayerDistrict, 2f);
						num--;
					}
				}
			}
			int num3 = Math.Min(num, 4);
			foreach (District item in (from d in _districts
				where d.OfficersSpawned.Count < d.TargetOfficers
				orderby d.OfficersSpawned.Count - d.TargetOfficers
				select d).ToList())
			{
				if (num3 <= 0)
				{
					break;
				}
				int num4 = Math.Min(Math.Max(0, item.TargetOfficers - item.OfficersSpawned.Count), num3);
				if (num4 > 0)
				{
					for (int j = 0; j < num4; j++)
					{
						QueueSpawnInDistrict(item);
					}
					num3 -= num4;
				}
			}
		}

		private void CheckPlayerDistrict()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = GameObject.Find("Player_Local");
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Vector3 val2 = (_lastPlayerPosition = val.transform.position);
				District district = null;
				float num = float.MaxValue;
				foreach (District district2 in _districts)
				{
					float num2 = Vector3.Distance(val2, district2.Center);
					if (district2.ContainsPoint(val2) && num2 < num)
					{
						district = district2;
						num = num2;
					}
				}
				if (district != null && district != _currentPlayerDistrict)
				{
					Log("Player entered " + district.Name);
					_previousPlayerDistrict = _currentPlayerDistrict;
					_currentPlayerDistrict = district;
					_currentPlayerDistrict.LastVisited = DateTime.Now;
					if (Time.time - _lastDistrictTransitionTime >= _districtTransitionCooldown)
					{
						_lastDistrictTransitionTime = Time.time;
						HandleDistrictTransition(_previousPlayerDistrict, _currentPlayerDistrict);
					}
				}
				if (Random.value < 0.1f && !_preserveDistrictOfficers)
				{
					DespawnOfficersFromFarDistricts();
				}
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Error checking player district: " + ex.Message);
			}
		}

		private void HandleDistrictTransition(District? oldDistrict, District newDistrict)
		{
			int num = Math.Max(0, newDistrict.TargetOfficers - newDistrict.OfficersSpawned.Count);
			if (num > 0 && !_districtsFullyPopulated)
			{
				if (_enableDistrictDebugLogs)
				{
					Log($"Adding {num} officers to {newDistrict.Name} (transition)");
				}
				for (int i = 0; i < num; i++)
				{
					QueueSpawnInDistrict(newDistrict, 2f);
				}
			}
			if (!_districtsFullyPopulated)
			{
				foreach (District district in _districts)
				{
					if (district == newDistrict || !district.OverlapsWith(newDistrict))
					{
						continue;
					}
					int num2 = Math.Max(0, district.TargetOfficers - district.OfficersSpawned.Count);
					if (num2 > 0)
					{
						if (_enableDistrictDebugLogs)
						{
							Log($"Adding {num2} officers to adjacent {district.Name}");
						}
						for (int j = 0; j < num2; j++)
						{
							QueueSpawnInDistrict(district, 1.5f);
						}
					}
				}
			}
			if (oldDistrict == null || newDistrict.OverlapsWith(oldDistrict) || _preserveDistrictOfficers)
			{
				return;
			}
			int num3 = Math.Max(0, oldDistrict.OfficersSpawned.Count - oldDistrict.TargetOfficers);
			if (num3 > 0)
			{
				int num4 = Math.Min(num3, 2);
				if (_enableDistrictDebugLogs)
				{
					Log($"Removing {num4} excess officers from {oldDistrict.Name}");
				}
				for (int k = 0; k < num4 && k < oldDistrict.OfficersSpawned.Count; k++)
				{
					QueueDespawn(oldDistrict.OfficersSpawned[k]);
				}
			}
		}

		private void DespawnOfficersFromFarDistricts()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			if (_currentPlayerDistrict == null || _preserveDistrictOfficers)
			{
				return;
			}
			foreach (District district in _districts)
			{
				if (district == _currentPlayerDistrict || district == _previousPlayerDistrict || district.OfficersSpawned.Count <= district.TargetOfficers || (DateTime.Now - district.LastVisited).TotalMinutes < 5.0 || (_currentPlayerDistrict != null && district.OverlapsWith(_currentPlayerDistrict)) || _currentPlayerDistrict == null || !(Vector3.Distance(district.Center, _currentPlayerDistrict.Center) > district.Radius + _currentPlayerDistrict.Radius + 30f))
				{
					continue;
				}
				int num = district.OfficersSpawned.Count - district.TargetOfficers;
				if (num <= 0)
				{
					continue;
				}
				int num2 = Math.Min(num, 1);
				if (_enableDistrictDebugLogs)
				{
					Log($"Despawning {num2} excess officers from distant {district.Name}");
				}
				for (int i = 0; i < num2; i++)
				{
					if (district.OfficersSpawned.Count > district.TargetOfficers && i < district.OfficersSpawned.Count)
					{
						QueueDespawn(district.OfficersSpawned[i]);
					}
				}
			}
		}

		private void QueueSpawnInDistrict(District district, float priority = 1f)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (district.SpawnPoints.Count != 0 && district.OfficersSpawned.Count < district.TargetOfficers)
			{
				int index = Random.Range(0, district.SpawnPoints.Count);
				Vector3 position = district.SpawnPoints[index];
				SpawnJob item = new SpawnJob
				{
					Position = position,
					District = district,
					Priority = priority,
					QueuedTime = DateTime.Now
				};
				_spawnQueue.Enqueue(item);
			}
		}

		private void QueueDespawn(PoliceOfficer officer)
		{
			if (!((Object)(object)officer == (Object)null) && ((Component)officer).gameObject.activeInHierarchy && IsModSpawnedOfficer(officer))
			{
				_despawnQueue.Enqueue(officer);
			}
		}

		private void ProcessSpawnQueue()
		{
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			if (_spawnQueue.Count == 0 || _currentlySpawningOfficer)
			{
				return;
			}
			bool isForDistrictPopulation = _populationState != DistrictPopulationState.MaintenanceMode;
			if (Time.time - _lastGameSpawnCheck > 0.1f)
			{
				_lastGameSpawnCheck = Time.time;
				_isGameCurrentlySpawning = IsGameSpawningEntities();
				if (_isGameCurrentlySpawning)
				{
					return;
				}
			}
			if (_isGameCurrentlySpawning && Time.time < _lastGameSpawnCheck + _gameSpawnAvoidanceWindow)
			{
				return;
			}
			_isGameCurrentlySpawning = false;
			List<SpawnJob> list = new List<SpawnJob>(_spawnQueue);
			_spawnQueue.Clear();
			list.Sort((SpawnJob a, SpawnJob b) => b.Priority.CompareTo(a.Priority));
			foreach (SpawnJob item in list)
			{
				if (!((DateTime.Now - item.QueuedTime).TotalMinutes > 2.0) && (item.District == null || item.District.OfficersSpawned.Count < item.District.TargetOfficers))
				{
					_spawnQueue.Enqueue(item);
				}
			}
			if (_spawnQueue.Count != 0)
			{
				SpawnJob spawnJob = _spawnQueue.Dequeue();
				if ((_populationState != DistrictPopulationState.MaintenanceMode || GetLocalOfficerCount() < _maxLocalOfficers || !(Vector3.Distance(spawnJob.Position, _lastPlayerPosition) <= _localOfficerRadius)) && (spawnJob.District == null || spawnJob.District.OfficersSpawned.Count < spawnJob.District.TargetOfficers))
				{
					_currentlySpawningOfficer = true;
					MelonCoroutines.Start(SpawnOfficerCoroutine(spawnJob.Position, spawnJob.District, isForDistrictPopulation));
				}
			}
		}

		[IteratorStateMachine(typeof(<SpawnOfficerCoroutine>d__134))]
		private IEnumerator SpawnOfficerCoroutine(Vector3 position, District? district, bool isForDistrictPopulation)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SpawnOfficerCoroutine>d__134(0)
			{
				<>4__this = this,
				position = position,
				district = district,
				isForDistrictPopulation = isForDistrictPopulation
			};
		}

		private bool IsGameSpawningEntities()
		{
			return Time.deltaTime > Time.smoothDeltaTime * 1.5f;
		}

		private void ProcessDespawnQueue()
		{
			if (_despawnQueue.Count == 0)
			{
				return;
			}
			int num = Math.Min(_maxDespawnsPerCycle, _despawnQueue.Count);
			for (int i = 0; i < num; i++)
			{
				if (_despawnQueue.Count == 0)
				{
					break;
				}
				PoliceOfficer officer = _despawnQueue.Dequeue();
				DespawnOfficer(officer);
			}
		}

		private bool SpawnOfficer(Vector3 position, District? district, bool isForDistrictPopulation)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Expected O, but got Unknown
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Expected O, but got Unknown
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (district != null && district.OfficersSpawned.Count >= district.TargetOfficers)
				{
					return false;
				}
				PooledOfficer pooledOfficer = null;
				if (_officerPool.Count > 0)
				{
					pooledOfficer = _officerPool.Dequeue();
				}
				if (pooledOfficer != null && (Object)(object)pooledOfficer.Officer != (Object)null && (Object)(object)pooledOfficer.GameObject != (Object)null)
				{
					PoliceOfficer officer = pooledOfficer.Officer;
					GameObject? gameObject = pooledOfficer.GameObject;
					Vector3 val = default(Vector3);
					((Vector3)(ref val))..ctor(Random.Range(-0.5f, 0.5f), 0f, Random.Range(-0.5f, 0.5f));
					gameObject.transform.position = position + val;
					gameObject.SetActive(true);
					string text = Guid.NewGuid().ToString();
					string text2 = "PatrolRoute_" + text;
					GameObject val2 = new GameObject(text2);
					val2.transform.position = position;
					_patrolRouteObjects[text2] = val2;
					FootPatrolRoute obj = val2.AddComponent<FootPatrolRoute>();
					obj.RouteName = text2;
					obj.StartWaypointIndex = 0;
					CreateEnhancedPatrolWaypoints(val2, position);
					PatrolGroup val3 = new PatrolGroup(obj);
					_officerRouteNames[officer] = text2;
					if ((Object)(object)((Component)officer).gameObject.GetComponent<ModSpawnedOfficerTag>() == (Object)null)
					{
						((Component)officer).gameObject.AddComponent<ModSpawnedOfficerTag>();
					}
					EnhanceOfficerNavigation(officer);
					officer.Activate();
					officer.StartFootPatrol(val3, true);
					_activeOfficers.Add(officer);
					district?.OfficersSpawned.Add(officer);
					if (isForDistrictPopulation)
					{
						_districtOfficerCount++;
						if (_populationState == DistrictPopulationState.InitialPopulation || _enableDistrictDebugLogs)
						{
							Log($"District population: {_districtOfficerCount}/{_maxDistrictOfficers}");
						}
					}
					if (_enableDistrictDebugLogs && district != null)
					{
						Log("Officer added to " + district.Name);
					}
					return true;
				}
				string text3 = OfficerTypes[Random.Range(0, OfficerTypes.Length)];
				NetworkObject val4 = null;
				NetworkManager? networkManager = _networkManager;
				PrefabObjects val5 = ((networkManager != null) ? networkManager.SpawnablePrefabs : null);
				if ((Object)(object)val5 != (Object)null)
				{
					for (int i = 0; i < val5.GetObjectCount(); i++)
					{
						NetworkObject @object = val5.GetObject(true, i);
						if ((Object)(object)@object != (Object)null && ((Object)((Component)@object).gameObject).name == text3)
						{
							val4 = @object;
							break;
						}
					}
				}
				if ((Object)(object)val4 == (Object)null || (Object)(object)_networkManager == (Object)null)
				{
					((MelonBase)_core).LoggerInstance.Error("Could not find prefab for " + text3 + " or NetworkManager is null");
					return false;
				}
				string text4 = Guid.NewGuid().ToString();
				string text5 = "PatrolRoute_" + text4;
				GameObject val6 = new GameObject(text5);
				val6.transform.position = position;
				_patrolRouteObjects[text5] = val6;
				FootPatrolRoute obj2 = val6.AddComponent<FootPatrolRoute>();
				obj2.RouteName = text5;
				obj2.StartWaypointIndex = 0;
				CreateEnhancedPatrolWaypoints(val6, position);
				PatrolGroup val7 = new PatrolGroup(obj2);
				NetworkObject val8 = Object.Instantiate<NetworkObject>(val4);
				((Object)((Component)val8).gameObject).name = text3 + "_Spawned_" + text4;
				Vector3 val9 = default(Vector3);
				((Vector3)(ref val9))..ctor(Random.Range(-0.5f, 0.5f), 0f, Random.Range(-0.5f, 0.5f));
				((Component)val8).transform.position = position + val9;
				((Component)val8).gameObject.SetActive(true);
				PoliceOfficer component = ((Component)val8).gameObject.GetComponent<PoliceOfficer>();
				if ((Object)(object)component != (Object)null)
				{
					component.Activate();
					((Component)val8).gameObject.AddComponent<ModSpawnedOfficerTag>();
					_officerRouteNames[component] = text5;
					EnhanceOfficerNavigation(component);
					component.StartFootPatrol(val7, true);
					_networkManager.ServerManager.Spawn(val8, (NetworkConnection)null, default(Scene));
					if ((Object)(object)component != (Object)null)
					{
						_activeOfficers.Add(component);
					}
					if (district != null && (Object)(object)component != (Object)null)
					{
						district.OfficersSpawned.Add(component);
					}
					if (isForDistrictPopulation)
					{
						_districtOfficerCount++;
						if (_populationState == DistrictPopulationState.InitialPopulation || _enableDistrictDebugLogs)
						{
							Log($"District population: {_districtOfficerCount}/{_maxDistrictOfficers}");
						}
					}
					if (_enableDistrictDebugLogs && district != null)
					{
						Log("Officer added to " + district.Name);
					}
					return true;
				}
				((MelonBase)_core).LoggerInstance.Error("Failed to get PoliceOfficer component from instantiated officer");
				return false;
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Error spawning officer: " + ex.Message + "\n" + ex.StackTrace);
				return false;
			}
		}

		private void EnhanceOfficerNavigation(PoliceOfficer officer)
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)officer == (Object)null)
			{
				return;
			}
			try
			{
				NPCMovement movement = ((NPC)officer).Movement;
				if ((Object)(object)movement == (Object)null)
				{
					return;
				}
				NavMeshAgent agent = movement.Agent;
				if (!((Object)(object)agent == (Object)null))
				{
					SafeSetProperty(agent, "speed", 3.5f);
					SafeSetProperty(agent, "acceleration", 12f);
					SafeSetProperty(agent, "angularSpeed", 180f);
					SafeSetProperty(agent, "stoppingDistance", 0.5f);
					SafeSetProperty(agent, "obstacleAvoidanceType", 1);
					NavMeshHit val = default(NavMeshHit);
					if (!SafeGetProperty(agent, "isOnNavMesh", defaultValue: true) && NavMesh.SamplePosition(((Component)officer).transform.position, ref val, 5f, -1))
					{
						SafeInvokeMethod(agent, "Warp", new object[1] { ((NavMeshHit)(ref val)).position });
					}
				}
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Error enhancing officer navigation: " + ex.Message);
			}
		}

		private void CreateEnhancedPatrolWaypoints(GameObject routeGO, Vector3 centerPos)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PatrolPatternType patrolPatternType = (PatrolPatternType)Random.Range(0, 5);
				int count = Random.Range(_minWaypoints, _maxWaypoints + 1);
				float radius = Random.Range(_minPatrolRadius, _maxPatrolRadius);
				List<Transform> list = new List<Transform>();
				GameObject val = new GameObject("Waypoint_0");
				val.transform.position = centerPos;
				val.transform.SetParent(routeGO.transform);
				list.Add(val.transform);
				switch (patrolPatternType)
				{
				case PatrolPatternType.Circle:
					GenerateCirclePattern(routeGO, centerPos, radius, count, list);
					break;
				case PatrolPatternType.Grid:
					GenerateGridPattern(routeGO, centerPos, radius, count, list);
					break;
				case PatrolPatternType.Zigzag:
					GenerateZigzagPattern(routeGO, centerPos, radius, count, list);
					break;
				case PatrolPatternType.Star:
					GenerateStarPattern(routeGO, centerPos, radius, count, list);
					break;
				default:
					GenerateRandomPattern(routeGO, centerPos, radius, count, list);
					break;
				}
				FootPatrolRoute component = routeGO.GetComponent<FootPatrolRoute>();
				component.Waypoints = new Il2CppReferenceArray<Transform>((long)list.Count);
				for (int i = 0; i < list.Count; i++)
				{
					((Il2CppArrayBase<Transform>)(object)component.Waypoints)[i] = list[i];
				}
				component.UpdateWaypoints();
			}
			catch (Exception ex)
			{
				((MelonBase)_core).LoggerInstance.Error("Error creating enhanced patrol waypoints: " + ex.Message);
				try
				{
					GameObject val2 = new GameObject("Waypoint_0");
					val2.transform.position = centerPos;
					val2.transform.SetParent(routeGO.transform);
					FootPatrolRoute component2 = routeGO.GetComponent<FootPatrolRoute>();
					component2.Waypoints = new Il2CppReferenceArray<Transform>(1L);
					((Il2CppArrayBase<Transform>)(object)component2.Waypoints)[0] = val2.transform;
					component2.UpdateWaypoints();
				}
				catch
				{
				}
			}
		}

		private void GenerateCirclePattern(GameObject routeGO, Vector3 center, float radius, int count, List<Transform> waypoints)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 1; i < count; i++)
			{
				float num = (float)i * ((float)Math.PI * 2f / (float)(count - 1));
				Vector3 position = center + new Vector3(Mathf.Cos(num) * radius, 0f, Mathf.Sin(num) * radius);
				CreateValidWaypoint(routeGO, position, i, center.y, waypoints);
			}
		}

		private void GenerateGridPattern(GameObject routeGO, Vector3 center, float radius, int count, List<Transform> waypoints)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.CeilToInt(Mathf.Sqrt((float)(count - 1)));
			float num2 = radius * 2f / (float)num;
			int num3 = 1;
			for (int i = 0; i < num; i++)
			{
				if (num3 >= count)
				{
					break;
				}
				for (int j = 0; j < num; j++)
				{
					if (num3 >= count)
					{
						break;
					}
					Vector3 position = center + new Vector3((float)i * num2 - radius * 0.9f, 0f, (float)j * num2 - radius * 0.9f);
					CreateValidWaypoint(routeGO, position, num3, center.y, waypoints);
					num3++;
				}
			}
		}

		private void GenerateZigzagPattern(GameObject routeGO, Vector3 center, float radius, int count, List<Transform> waypoints)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			float num = 2f * radius / (float)((count - 1) / 2);
			for (int i = 1; i < count; i++)
			{
				float num2 = (float)((i % 2 != 0) ? 1 : (-1)) * (radius * 0.8f);
				float num3 = (float)(i / 2) * num - radius;
				Vector3 position = center + new Vector3(num2, 0f, num3);
				CreateValidWaypoint(routeGO, position, i, center.y, waypoints);
			}
		}

		private void GenerateStarPattern(GameObject routeGO, Vector3 center, float radius, int count, List<Transform> waypoints)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Min(count - 1, 8);
			float num2 = radius * 0.4f;
			for (int i = 0; i < num; i++)
			{
				float num3 = (float)i * ((float)Math.PI * 2f / (float)num);
				Vector3 position = center + new Vector3(Mathf.Cos(num3) * radius, 0f, Mathf.Sin(num3) * radius);
				CreateValidWaypoint(routeGO, position, i * 2 + 1, center.y, waypoints);
				if (i * 2 + 2 < count)
				{
					float num4 = ((float)i + 0.5f) * ((float)Math.PI * 2f / (float)num);
					Vector3 position2 = center + new Vector3(Mathf.Cos(num4) * num2, 0f, Mathf.Sin(num4) * num2);
					CreateValidWaypoint(routeGO, position2, i * 2 + 2, center.y, waypoints);
				}
			}
		}

		private void GenerateRandomPattern(GameObject routeGO, Vector3 center, float radius, int count, List<Transform> waypoints)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 1; i < count; i++)
			{
				float num = Random.Range(0f, (float)Math.PI * 2f);
				float num2 = Random.Range(radius * 0.3f, radius);
				Vector3 position = center + new Vector3(Mathf.Cos(num) * num2, 0f, Mathf.Sin(num) * num2);
				CreateValidWaypoint(routeGO, position, i, center.y, waypoints);
			}
		}

		private void CreateValidWaypoint(GameObject routeGO, Vector3 position, int index, float defaultY, List<Transform> waypoints)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position2 = position;
			bool flag = false;
			NavMeshHit val = default(NavMeshHit);
			NavMeshHit val6 = default(NavMeshHit);
			for (int i = 0; i < 5; i++)
			{
				float num = 2f + (float)i * 2f;
				if (NavMesh.SamplePosition(position, ref val, num, -1))
				{
					new NavMeshPath();
					Vector3 val2 = ((NavMeshHit)(ref val)).position + new Vector3(1f, 0f, 0f);
					Vector3 val3 = ((NavMeshHit)(ref val)).position + new Vector3(-1f, 0f, 0f);
					Vector3 val4 = ((NavMeshHit)(ref val)).position + new Vector3(0f, 0f, 1f);
					Vector3 val5 = ((NavMeshHit)(ref val)).position + new Vector3(0f, 0f, -1f);
					int num2 = 0;
					if (NavMesh.SamplePosition(val2, ref val6, 2f, -1))
					{
						num2++;
					}
					if (NavMesh.SamplePosition(val3, ref val6, 2f, -1))
					{
						num2++;
					}
					if (NavMesh.SamplePosition(val4, ref val6, 2f, -1))
					{
						num2++;
					}
					if (NavMesh.SamplePosition(val5, ref val6, 2f, -1))
					{
						num2++;
					}
					if (num2 >= 3)
					{
						position2 = ((NavMeshHit)(ref val)).position;
						position2.y += _waypointHeightOffset;
						flag = true;
						break;
					}
				}
			}
			if (!flag)
			{
				position2 = position;
				position2.y = defaultY + _waypointHeightOffset;
				if (_enableDistrictDebugLogs)
				{
					LogWarning($"Warning: Could not find valid NavMesh position for waypoint {index}, using fallback");
				}
			}
			GameObject val7 = new GameObject($"Waypoint_{index}");
			val7.transform.position = position2;
			val7.transform.SetParent(routeGO.transform);
			waypoints.Add(val7.transform);
		}

		private void DespawnOfficer(PoliceOfficer officer)
		{
			if ((Object)(object)officer == (Object)null)
			{
				return;
			}
			try
			{
				if (!IsModSpawnedOfficer(officer))
				{
					return;
				}
				District district = null;
				foreach (District district2 in _districts)
				{
					if (district2.OfficersSpawned.Contains(officer))
					{
						district = district2;
						break;
					}
				}
				if (district != null)
				{
					district.OfficersSpawned.Remove(officer);
					if (!_districtsFullyPopulated)
					{
						_districtOfficerCount = Math.Max(0, _districtOfficerCount - 1);
					}
				}
				_activeOfficers.Remove(officer);
				_lastOfficerPositions.Remove(officer);
				_officerStuckCounter.Remove(officer);
				if (_officerPool.Count < 10 && (Object)(object)((Component)officer).gameObject != (Object)null)
				{
					try
					{
						string value = null;
						if (_officerRouteNames.TryGetValue(officer, out value) && value != null)
						{
							GameObject value2 = null;
							if (_patrolRouteObjects.TryGetValue(value, out value2) && (Object)(object)value2 != (Object)null)
							{
								try
								{
									Object.Destroy((Object)(object)value2);
								}
								catch (Exception ex)
								{
									((MelonBase)_core).LoggerInstance.Error("Error destroying route: " + ex.Message);
								}
								_patrolRouteObjects.Remove(value);
							}
							else
							{
								foreach (FootPatrolRoute item2 in Object.FindObjectsOfType<FootPatrolRoute>())
								{
									if ((Object)(object)item2 != (Object)null && ((Object)item2).name == value)
									{
										try
										{
											Object.Destroy((Object)(object)((Component)item2).gameObject);
										}
										catch (Exception ex2)
										{
											((MelonBase)_core).LoggerInstance.Error("Error destroying route: " + ex2.Message);
										}
										break;
									}
								}
							}
							_officerRouteNames.Remove(officer);
						}
						officer.Deactivate();
						((Component)officer).gameObject.SetActive(false);
						PooledOfficer item = new PooledOfficer
						{
							GameObject = ((Component)officer).gameObject,
							Officer = officer,
							NetworkObject = ((Component)officer).gameObject.GetComponent<NetworkObject>(),
							PooledTime = DateTime.Now
						};
						_officerPool.Enqueue(item);
						if (district != null && _enableDistrictDebugLogs)
						{
							Log("Officer pooled from " + district.Name);
						}
						return;
					}
					catch (Exception ex3)
					{
						((MelonBase)_core).LoggerInstance.Error("Error pooling officer: " + ex3.Message);
					}
				}
				if ((Object)(object)((Component)officer).gameObject != (Object)null)
				{
					try
					{
						string value3 = null;
						if (_officerRouteNames.TryGetValue(officer, out value3) && value3 != null)
						{
							GameObject value4 = null;
							if (_patrolRouteObjects.TryGetValue(value3, out value4) && (Object)(object)value4 != (Object)null)
							{
								try
								{
									Object.Destroy((Object)(object)value4);
								}
								catch (Exception ex4)
								{
									((MelonBase)_core).LoggerInstance.Error("Error destroying route: " + ex4.Message);
								}
								_patrolRouteObjects.Remove(value3);
							}
							else
							{
								foreach (FootPatrolRoute item3 in Object.FindObjectsOfType<FootPatrolRoute>())
								{
									if ((Object)(object)item3 != (Object)null && ((Object)item3).name == value3)
									{
										try
										{
											Object.Destroy((Object)(object)((Component)item3).gameObject);
										}
										catch (Exception ex5)
										{
											((MelonBase)_core).LoggerInstance.Error("Error destroying route: " + ex5.Message);
										}
										break;
									}
								}
							}
							_officerRouteNames.Remove(officer);
						}
					}
					catch (Exception ex6)
					{
						((MelonBase)_core).LoggerInstance.Error("Error cleaning up officer route: " + ex6.Message);
					}
					officer.Deactivate();
					Object.Destroy((Object)(object)((Component)officer).gameObject);
				}
				if (district != null && _enableDistrictDebugLogs)
				{
					Log("Officer removed from " + district.Name);
				}
			}
			catch (Exception ex7)
			{
				((MelonBase)_core).LoggerInstance.Error("Error despawning officer: " + ex7.Message);
				try
				{
					if ((Object)(object)officer != (Object)null && (Object)(object)((Component)officer).gameObject != (Object)null)
					{
						officer.Deactivate();
						Object.Destroy((Object)(object)((Component)officer).gameObject);
					}
				}
				catch
				{
				}
			}
		}

		private void CleanupInvalidOfficers()
		{
			int num = 0;
			for (int num2 = _activeOfficers.Count - 1; num2 >= 0; num2--)
			{
				PoliceOfficer val = _activeOfficers[num2];
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || !((Component)val).gameObject.activeInHierarchy)
				{
					if ((Object)(object)val != (Object)null)
					{
						if (_officerRouteNames.TryGetValue(val, out string value) && value != null)
						{
							if (_patrolRouteObjects.TryGetValue(value, out GameObject value2) && (Object)(object)value2 != (Object)null)
							{
								try
								{
									Object.Destroy((Object)(object)value2);
								}
								catch
								{
								}
								_patrolRouteObjects.Remove(value);
							}
							_officerRouteNames.Remove(val);
						}
						_lastOfficerPositions.Remove(val);
						_officerStuckCounter.Remove(val);
					}
					_activeOfficers.RemoveAt(num2);
					num++;
				}
			}
			foreach (District district in _districts)
			{
				for (int num3 = district.OfficersSpawned.Count - 1; num3 >= 0; num3--)
				{
					PoliceOfficer val2 = district.OfficersSpawned[num3];
					if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).gameObject == (Object)null || !((Component)val2).gameObject.activeInHierarchy)
					{
						district.OfficersSpawned.RemoveAt(num3);
						num++;
						if (!_districtsFullyPopulated)
						{
							_districtOfficerCount = Math.Max(0, _districtOfficerCount - 1);
						}
					}
				}
			}
			if (num > 0 && _enableDistrictDebugLogs)
			{
				Log($"Cleaned up {num} invalid officers");
				if (num >= 10)
				{
					GC.Collect();
				}
			}
		}

		private void CleanOldPooledOfficers()
		{
			DateTime dateTime = DateTime.Now.AddMinutes(-5.0);
			int num = 0;
			while (_officerPool.Count > 0 && _officerPool.Peek().PooledTime < dateTime)
			{
				PooledOfficer pooledOfficer = _officerPool.Dequeue();
				try
				{
					if ((Object)(object)pooledOfficer.GameObject != (Object)null)
					{
						Object.Destroy((Object)(object)pooledOfficer.GameObject);
					}
				}
				catch
				{
				}
				num++;
			}
			if (num > 0)
			{
				Log($"Cleaned {num} old officers from the pool");
			}
		}

		private void LogOfficerCounts()
		{
			if (!_enableConsoleLogs && !_enableDistrictDebugLogs && _populationState == DistrictPopulationState.MaintenanceMode)
			{
				return;
			}
			double num = ((_populationState == DistrictPopulationState.MaintenanceMode) ? 120 : 30);
			if ((DateTime.Now - _lastLogDisplayTime).TotalSeconds < num)
			{
				return;
			}
			_lastLogDisplayTime = DateTime.Now;
			GetCurrentOfficerLimit();
			int totalOfficerCount = GetTotalOfficerCount();
			if (_populationState == DistrictPopulationState.MaintenanceMode)
			{
				Log($"Maintenance status: {totalOfficerCount} officers - District: {_districtOfficerCount}/{_maxDistrictOfficers}");
				return;
			}
			int localOfficerCount = GetLocalOfficerCount();
			Log($"Population progress: {_districtOfficerCount}/{_maxDistrictOfficers} district officers - Local: {localOfficerCount}/{_maxLocalOfficers}");
			foreach (District district in _districts)
			{
				int value = ((district.TargetOfficers > 0) ? (district.OfficersSpawned.Count * 100 / district.TargetOfficers) : 0);
				Log($"  {district.Name}: {district.OfficersSpawned.Count}/{district.TargetOfficers} officers ({value}%)");
			}
		}

		private void EnsureAllDistrictsHaveTargetOfficers()
		{
			UpdateDistrictTargetOfficers();
			if (_populationState == DistrictPopulationState.MaintenanceMode)
			{
				bool flag = false;
				foreach (District district in _districts)
				{
					if (district.OfficersSpawned.Count < district.TargetOfficers)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					_populationState = DistrictPopulationState.InitialCheck;
					_needsStatusUpdate = true;
					Log("Some districts need repopulation. Restarting district population process.");
					return;
				}
				{
					foreach (District district2 in _districts)
					{