Decompiled source of Empress Spawn Browser v4.5.0

EmpressSpawnBrowser.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Empress")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("4.0.0.0")]
[assembly: AssemblyInformationalVersion("4.0.0")]
[assembly: AssemblyProduct("EmpressSpawnBrowser")]
[assembly: AssemblyTitle("EmpressSpawnBrowser")]
[assembly: AssemblyVersion("4.0.0.0")]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Empress.SpawnBrowser
{
	internal static class SectorAccess
	{
		private static readonly FieldInfo? PlayerAvatarPlayerHealthField = AccessTools.Field(typeof(PlayerAvatar), "playerHealth");

		private static readonly FieldInfo? PlayerAvatarPlayerDeathHeadField = AccessTools.Field(typeof(PlayerAvatar), "playerDeathHead");

		private static readonly FieldInfo? PlayerAvatarPlayerNameField = AccessTools.Field(typeof(PlayerAvatar), "playerName");

		private static readonly FieldInfo? PlayerAvatarIsLocalField = AccessTools.Field(typeof(PlayerAvatar), "isLocal");

		private static readonly FieldInfo? PlayerAvatarIsDisabledField = AccessTools.Field(typeof(PlayerAvatar), "isDisabled");

		private static readonly FieldInfo? PlayerAvatarDeadSetField = AccessTools.Field(typeof(PlayerAvatar), "deadSet");

		private static readonly FieldInfo? PlayerAvatarSteamIdField = AccessTools.Field(typeof(PlayerAvatar), "steamID");

		private static readonly FieldInfo? PlayerHealthHealthField = AccessTools.Field(typeof(PlayerHealth), "health");

		private static readonly FieldInfo? PlayerHealthMaxHealthField = AccessTools.Field(typeof(PlayerHealth), "maxHealth");

		private static readonly FieldInfo? PlayerHealthGodModeField = AccessTools.Field(typeof(PlayerHealth), "godMode");

		private static readonly FieldInfo? PlayerControllerDebugEnergyField = AccessTools.Field(typeof(PlayerController), "DebugEnergy");

		private static readonly FieldInfo? PlayerControllerEnergyCurrentField = AccessTools.Field(typeof(PlayerController), "EnergyCurrent");

		private static readonly FieldInfo? PlayerControllerEnergyStartField = AccessTools.Field(typeof(PlayerController), "EnergyStart");

		private static readonly FieldInfo? PlayerControllerAvatarField = AccessTools.Field(typeof(PlayerController), "playerAvatarScript");

		private static readonly FieldInfo? PlayerControllerSteamIdField = AccessTools.Field(typeof(PlayerController), "playerSteamID");

		private static readonly FieldInfo? PlayerDeathHeadInExtractionPointField = AccessTools.Field(typeof(PlayerDeathHead), "inExtractionPoint");

		private static readonly FieldInfo? EnemyDirectorDebugNoVisionField = AccessTools.Field(typeof(EnemyDirector), "debugNoVision");

		private static readonly FieldInfo? EnemyDirectorDebugNoSpawnIdlePauseField = AccessTools.Field(typeof(EnemyDirector), "debugNoSpawnIdlePause");

		private static readonly FieldInfo? EnemyDirectorDebugSpawnCloseField = AccessTools.Field(typeof(EnemyDirector), "debugSpawnClose");

		private static readonly FieldInfo? EnemyDirectorEnemiesSpawnedField = AccessTools.Field(typeof(EnemyDirector), "enemiesSpawned");

		private static readonly FieldInfo? EnemyParentSpawnedField = AccessTools.Field(typeof(EnemyParent), "Spawned");

		private static readonly FieldInfo? EnemyParentSetupDoneField = AccessTools.Field(typeof(EnemyParent), "SetupDone");

		private static readonly FieldInfo? EnemyParentFirstSpawnPointUsedField = AccessTools.Field(typeof(EnemyParent), "firstSpawnPointUsed");

		private static readonly FieldInfo? ValuableObjectPhysGrabObjectField = AccessTools.Field(typeof(ValuableObject), "physGrabObject");

		private static readonly FieldInfo? AssetManagerEnemyValuableSmallField = AccessTools.Field(typeof(AssetManager), "enemyValuableSmall");

		private static readonly FieldInfo? AssetManagerEnemyValuableMediumField = AccessTools.Field(typeof(AssetManager), "enemyValuableMedium");

		private static readonly FieldInfo? AssetManagerEnemyValuableBigField = AccessTools.Field(typeof(AssetManager), "enemyValuableBig");

		private static readonly FieldInfo? PrefabRefPrefabNameField = AccessTools.Field(typeof(PrefabRef), "prefabName");

		private static readonly FieldInfo? PrefabRefResourcePathField = AccessTools.Field(typeof(PrefabRef), "resourcePath");

		private static readonly FieldInfo? DebugCommandHandlerEnemyNoVisionField = AccessTools.Field(typeof(DebugCommandHandler), "enemyNoVision");

		private static readonly FieldInfo? MetaManagerCosmeticTokensField = AccessTools.Field(typeof(MetaManager), "cosmeticTokens");

		private static readonly MethodInfo? MetaManagerSaveMethod = AccessTools.Method(typeof(MetaManager), "Save", (Type[])null, (Type[])null);

		private static readonly MethodInfo? CosmeticTokenUiSetupMethod = AccessTools.Method(typeof(CosmeticTokenUI), "Setup", (Type[])null, (Type[])null);

		private static readonly FieldInfo? RoundDirectorExtractionPointActiveField = AccessTools.Field(typeof(RoundDirector), "extractionPointActive");

		private static readonly FieldInfo? RoundDirectorExtractionPointListField = AccessTools.Field(typeof(RoundDirector), "extractionPointList");

		private static readonly FieldInfo? RoundDirectorExtractionPointCurrentField = AccessTools.Field(typeof(RoundDirector), "extractionPointCurrent");

		private static readonly FieldInfo? ExtractionPointCurrentStateField = AccessTools.Field(typeof(ExtractionPoint), "currentState");

		private static readonly FieldInfo? ExtractionPointCompletedRightAwayField = AccessTools.Field(typeof(ExtractionPoint), "isCompletedRightAway");

		private static readonly MethodInfo? ExtractionPointOnClickMethod = AccessTools.Method(typeof(ExtractionPoint), "OnClick", (Type[])null, (Type[])null);

		private static readonly MethodInfo? ExtractionPointStateSetMethod = AccessTools.Method(typeof(ExtractionPoint), "StateSet", (Type[])null, (Type[])null);

		private static readonly FieldInfo? RunManagerDebugLevelField = AccessTools.Field(typeof(RunManager), "debugLevel");

		private static readonly FieldInfo? RunManagerGameOverField = AccessTools.Field(typeof(RunManager), "gameOver");

		private static readonly FieldInfo? MenuCursorMeshField = AccessTools.Field(typeof(MenuCursor), "mesh");

		private static readonly FieldInfo? MenuCursorShowTimerField = AccessTools.Field(typeof(MenuCursor), "showTimer");

		private static readonly FieldInfo? MenuCursorOverridePosTimerField = AccessTools.Field(typeof(MenuCursor), "overridePosTimer");

		private static readonly FieldInfo? CursorManagerUnlockTimerField = AccessTools.Field(typeof(CursorManager), "unlockTimer");

		private static readonly FieldInfo? PunManagerPhotonViewField = AccessTools.Field(typeof(PunManager), "photonView");

		public static PlayerHealth? GetPlayerHealth(PlayerAvatar? player)
		{
			return GetFieldValue<PlayerHealth>(PlayerAvatarPlayerHealthField, player);
		}

		public static PlayerDeathHead? GetPlayerDeathHead(PlayerAvatar? player)
		{
			return GetFieldValue<PlayerDeathHead>(PlayerAvatarPlayerDeathHeadField, player);
		}

		public static string GetPlayerName(PlayerAvatar? player)
		{
			return GetFieldValue(PlayerAvatarPlayerNameField, player, "Unknown operative");
		}

		public static bool IsPlayerLocal(PlayerAvatar? player)
		{
			return GetFieldValue(PlayerAvatarIsLocalField, player, fallback: false);
		}

		public static bool IsPlayerDisabled(PlayerAvatar? player)
		{
			return GetFieldValue(PlayerAvatarIsDisabledField, player, fallback: false);
		}

		public static bool IsPlayerDead(PlayerAvatar? player)
		{
			return GetFieldValue(PlayerAvatarDeadSetField, player, fallback: false);
		}

		public static string GetPlayerSteamId(PlayerAvatar? player)
		{
			return GetFieldValue(PlayerAvatarSteamIdField, player, string.Empty);
		}

		public static string GetLocalSteamId()
		{
			string fieldValue = GetFieldValue(PlayerControllerSteamIdField, PlayerController.instance, string.Empty);
			if (string.IsNullOrWhiteSpace(fieldValue))
			{
				return GetPlayerSteamId(PlayerAvatar.instance);
			}
			return fieldValue;
		}

		public static int GetHealth(PlayerHealth? playerHealth)
		{
			return GetFieldValue(PlayerHealthHealthField, playerHealth, 0);
		}

		public static int GetMaxHealth(PlayerHealth? playerHealth)
		{
			return GetFieldValue(PlayerHealthMaxHealthField, playerHealth, 0);
		}

		public static void SetPlayerGodMode(PlayerHealth? playerHealth, bool enabled)
		{
			SetFieldValue(PlayerHealthGodModeField, playerHealth, enabled);
		}

		public static float GetEnergyCurrent(PlayerController? playerController)
		{
			return GetFieldValue(PlayerControllerEnergyCurrentField, playerController, 0f);
		}

		public static float GetEnergyStart(PlayerController? playerController)
		{
			return GetFieldValue(PlayerControllerEnergyStartField, playerController, 0f);
		}

		public static void SetEnergyCurrent(PlayerController? playerController, float value)
		{
			SetFieldValue(PlayerControllerEnergyCurrentField, playerController, value);
		}

		public static void SetDebugEnergy(PlayerController? playerController, bool enabled)
		{
			SetFieldValue(PlayerControllerDebugEnergyField, playerController, enabled);
		}

		public static PlayerAvatar? GetControllerAvatar(PlayerController? playerController)
		{
			return GetFieldValue<PlayerAvatar>(PlayerControllerAvatarField, playerController);
		}

		public static void SetInExtractionPoint(PlayerDeathHead? playerDeathHead, bool enabled)
		{
			SetFieldValue(PlayerDeathHeadInExtractionPointField, playerDeathHead, enabled);
		}

		public static bool GetEnemyNoVision(EnemyDirector? enemyDirector)
		{
			return GetEnemyNoVision(enemyDirector, GetLocalSteamId());
		}

		public static void SetEnemyNoVision(EnemyDirector? enemyDirector, bool enabled)
		{
			SetEnemyNoVision(enemyDirector, GetLocalSteamId(), enabled);
		}

		public static bool GetEnemyNoVision(EnemyDirector? enemyDirector, string steamId)
		{
			if (string.IsNullOrWhiteSpace(steamId))
			{
				return false;
			}
			return GetFieldValue<List<string>>(EnemyDirectorDebugNoVisionField, enemyDirector)?.Contains(steamId) ?? false;
		}

		public static void SetEnemyNoVision(EnemyDirector? enemyDirector, string steamId, bool enabled)
		{
			SetStringListMembership(EnemyDirectorDebugNoVisionField, enemyDirector, steamId, enabled);
		}

		public static void SetDebugCommandEnemyNoVision(DebugCommandHandler? debugCommandHandler, string steamId, bool enabled)
		{
			SetStringListMembership(DebugCommandHandlerEnemyNoVisionField, debugCommandHandler, steamId, enabled);
		}

		public static bool AddTaxToken(Rarity rarity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return AddTaxTokens(rarity, 1);
		}

		public static bool AddTaxTokens(Rarity rarity, int amount)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected I4, but got Unknown
			MetaManager instance = MetaManager.instance;
			List<int> fieldValue = GetFieldValue<List<int>>(MetaManagerCosmeticTokensField, instance);
			if (fieldValue == null)
			{
				return false;
			}
			int num = Mathf.Clamp(amount, 1, 999);
			for (int i = 0; i < num; i++)
			{
				fieldValue.Add((int)rarity);
			}
			InvokeMethod(CosmeticTokenUiSetupMethod, CosmeticTokenUI.instance);
			InvokeMethod(MetaManagerSaveMethod, instance);
			return true;
		}

		public static bool GetEnemyNoSpawnIdlePause(EnemyDirector? enemyDirector)
		{
			return GetFieldValue(EnemyDirectorDebugNoSpawnIdlePauseField, enemyDirector, fallback: false);
		}

		public static void SetEnemyNoSpawnIdlePause(EnemyDirector? enemyDirector, bool enabled)
		{
			SetFieldValue(EnemyDirectorDebugNoSpawnIdlePauseField, enemyDirector, enabled);
		}

		public static bool GetEnemySpawnClose(EnemyDirector? enemyDirector)
		{
			return GetFieldValue(EnemyDirectorDebugSpawnCloseField, enemyDirector, fallback: false);
		}

		public static void SetEnemySpawnClose(EnemyDirector? enemyDirector, bool enabled)
		{
			SetFieldValue(EnemyDirectorDebugSpawnCloseField, enemyDirector, enabled);
		}

		public static List<EnemyParent> GetSpawnedEnemies(EnemyDirector? enemyDirector)
		{
			return GetFieldValue(EnemyDirectorEnemiesSpawnedField, enemyDirector, new List<EnemyParent>());
		}

		public static bool IsEnemySpawned(EnemyParent? enemyParent)
		{
			return GetFieldValue(EnemyParentSpawnedField, enemyParent, fallback: false);
		}

		public static void SetEnemySetupDone(EnemyParent? enemyParent, bool enabled)
		{
			SetFieldValue(EnemyParentSetupDoneField, enemyParent, enabled);
		}

		public static void SetEnemyFirstSpawnPointUsed(EnemyParent? enemyParent, bool enabled)
		{
			SetFieldValue(EnemyParentFirstSpawnPointUsedField, enemyParent, enabled);
		}

		public static GameObject? GetMenuCursorMesh(MenuCursor? menuCursor)
		{
			return GetFieldValue<GameObject>(MenuCursorMeshField, menuCursor);
		}

		public static void SetMenuCursorShowTimer(MenuCursor? menuCursor, float value)
		{
			SetFieldValue(MenuCursorShowTimerField, menuCursor, value);
		}

		public static void SetMenuCursorOverridePosTimer(MenuCursor? menuCursor, float value)
		{
			SetFieldValue(MenuCursorOverridePosTimerField, menuCursor, value);
		}

		public static void SetCursorUnlockTimer(CursorManager? cursorManager, float value)
		{
			SetFieldValue(CursorManagerUnlockTimerField, cursorManager, value);
		}

		public static PhysGrabObject? GetValuablePhysGrabObject(ValuableObject? valuableObject)
		{
			return GetFieldValue<PhysGrabObject>(ValuableObjectPhysGrabObjectField, valuableObject);
		}

		public static GameObject? GetEnemyValuableSmall(AssetManager? assetManager)
		{
			return GetFieldValue<GameObject>(AssetManagerEnemyValuableSmallField, assetManager);
		}

		public static GameObject? GetEnemyValuableMedium(AssetManager? assetManager)
		{
			return GetFieldValue<GameObject>(AssetManagerEnemyValuableMediumField, assetManager);
		}

		public static GameObject? GetEnemyValuableBig(AssetManager? assetManager)
		{
			return GetFieldValue<GameObject>(AssetManagerEnemyValuableBigField, assetManager);
		}

		public static PrefabRef? CreateResourcePrefabRef(GameObject? prefab, string resourcePath)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			if ((Object)(object)prefab == (Object)null || string.IsNullOrWhiteSpace(resourcePath))
			{
				return null;
			}
			PrefabRef val = new PrefabRef();
			SetFieldValue(PrefabRefPrefabNameField, val, ((Object)prefab).name);
			SetFieldValue(PrefabRefResourcePathField, val, resourcePath);
			if (!val.IsValid())
			{
				return null;
			}
			return val;
		}

		public static PhotonView? GetPunManagerPhotonView(PunManager? punManager)
		{
			return GetFieldValue<PhotonView>(PunManagerPhotonViewField, punManager);
		}

		public static bool GetRoundExtractionPointActive(RoundDirector? roundDirector)
		{
			return GetFieldValue(RoundDirectorExtractionPointActiveField, roundDirector, fallback: false);
		}

		public static List<GameObject> GetRoundExtractionPointList(RoundDirector? roundDirector)
		{
			return GetFieldValue(RoundDirectorExtractionPointListField, roundDirector, new List<GameObject>());
		}

		public static ExtractionPoint? GetRoundExtractionPointCurrent(RoundDirector? roundDirector)
		{
			return GetFieldValue<ExtractionPoint>(RoundDirectorExtractionPointCurrentField, roundDirector);
		}

		public static void SetRoundExtractionPointCurrent(RoundDirector? roundDirector, ExtractionPoint? extractionPoint)
		{
			SetFieldValue<ExtractionPoint>(RoundDirectorExtractionPointCurrentField, roundDirector, extractionPoint);
		}

		public static State GetExtractionPointState(ExtractionPoint? extractionPoint)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return GetFieldValue<State>(ExtractionPointCurrentStateField, extractionPoint, (State)0);
		}

		public static bool ActivateExtractionPoint(ExtractionPoint? extractionPoint)
		{
			return InvokeMethod(ExtractionPointOnClickMethod, extractionPoint);
		}

		public static bool CompleteExtractionPoint(ExtractionPoint? extractionPoint)
		{
			if ((Object)(object)extractionPoint == (Object)null)
			{
				return false;
			}
			SetFieldValue(ExtractionPointCompletedRightAwayField, extractionPoint, value: true);
			return InvokeMethod(ExtractionPointStateSetMethod, extractionPoint, (object)(State)6);
		}

		public static bool GetRunGameOver(RunManager? runManager)
		{
			return GetFieldValue(RunManagerGameOverField, runManager, fallback: false);
		}

		public static void SetRunDebugLevel(RunManager? runManager, Level? level)
		{
			SetFieldValue<Level>(RunManagerDebugLevelField, runManager, level);
		}

		private static T GetFieldValue<T>(FieldInfo? fieldInfo, object? instance, T fallback = default(T))
		{
			if (fieldInfo == null || instance == null)
			{
				return fallback;
			}
			try
			{
				return (T)((fieldInfo.GetValue(instance) is T val) ? ((object)val) : ((object)fallback));
			}
			catch
			{
				return fallback;
			}
		}

		private static void SetFieldValue<T>(FieldInfo? fieldInfo, object? instance, T value)
		{
			if (fieldInfo == null || instance == null)
			{
				return;
			}
			try
			{
				fieldInfo.SetValue(instance, value);
			}
			catch
			{
			}
		}

		private static void SetStringListMembership(FieldInfo? fieldInfo, object? instance, string value, bool enabled)
		{
			if (fieldInfo == null || instance == null || string.IsNullOrWhiteSpace(value))
			{
				return;
			}
			try
			{
				if (!(fieldInfo.GetValue(instance) is List<string> list))
				{
					return;
				}
				if (enabled)
				{
					if (!list.Contains(value))
					{
						list.Add(value);
					}
				}
				else
				{
					list.Remove(value);
				}
			}
			catch
			{
			}
		}

		private static bool InvokeMethod(MethodInfo? methodInfo, object? instance, params object?[] parameters)
		{
			if (methodInfo == null || instance == null)
			{
				return false;
			}
			try
			{
				methodInfo.Invoke(instance, parameters);
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	internal sealed class SectorActions
	{
		private const float InfiniteStrengthGrabValue = 100f;

		private readonly ManualLogSource _logger;

		private readonly SectorOverlayState _state;

		private readonly SectorCatalog _catalog;

		private PhysGrabber? _strengthGrabber;

		private float _strengthGrabberOriginal = 1f;

		public SectorActions(ManualLogSource logger, SectorOverlayState state, SectorCatalog catalog)
		{
			_logger = logger;
			_state = state;
			_catalog = catalog;
		}

		public void Tick()
		{
			try
			{
				ApplyLocalPowerState();
			}
			catch (Exception ex)
			{
				_logger.LogError((object)ex);
			}
		}

		public void ResetLocalPowerState()
		{
			PlayerHealth playerHealth = SectorAccess.GetPlayerHealth(PlayerAvatar.instance);
			if ((Object)(object)playerHealth != (Object)null)
			{
				SectorAccess.SetPlayerGodMode(playerHealth, enabled: false);
			}
			if ((Object)(object)PlayerController.instance != (Object)null)
			{
				SectorAccess.SetDebugEnergy(PlayerController.instance, enabled: false);
				PlayerController.instance.OverrideSpeed(1f, 0.05f);
			}
			_state.GodMode = false;
			_state.InfiniteEnergy = false;
			RestoreInfiniteStrength();
			_state.InfiniteStrength = false;
			_state.StickyBoost = false;
		}

		public SectorRuntimeSnapshot GetSnapshot()
		{
			List<PlayerAvatar> list = SectorGame.GetPlayers().ToList();
			PlayerHealth playerHealth = SectorAccess.GetPlayerHealth(SectorGame.GetLocalPlayer());
			PlayerController instance = PlayerController.instance;
			List<EnemyParent> spawnedEnemies = SectorAccess.GetSpawnedEnemies(EnemyDirector.instance);
			bool inRun = SectorGame.IsInPlayableRun();
			bool isHost = SemiFunc.IsMasterClientOrSingleplayer();
			object obj = RunManager.instance?.levelCurrent?.NarrativeName;
			if (obj == null)
			{
				RunManager instance2 = RunManager.instance;
				if (instance2 == null)
				{
					obj = null;
				}
				else
				{
					Level levelCurrent = instance2.levelCurrent;
					obj = ((levelCurrent != null) ? ((Object)levelCurrent).name : null);
				}
				if (obj == null)
				{
					obj = "No active level";
				}
			}
			return new SectorRuntimeSnapshot(inRun, isHost, (string)obj, list.Count, list.Count((PlayerAvatar player) => (Object)(object)player != (Object)null && !SectorAccess.IsPlayerDead(player) && !SectorAccess.IsPlayerDisabled(player)), list.Count((PlayerAvatar player) => (Object)(object)player != (Object)null && SectorAccess.IsPlayerDead(player)), spawnedEnemies.Count((EnemyParent enemy) => (Object)(object)enemy != (Object)null), Object.FindObjectsByType<ValuableObject>((FindObjectsSortMode)0).Length, SectorAccess.GetHealth(playerHealth), SectorAccess.GetMaxHealth(playerHealth), SectorAccess.GetEnergyCurrent(instance), SectorAccess.GetEnergyStart(instance), SectorAccess.GetEnemyNoVision(EnemyDirector.instance));
		}

		public void ExecuteCommand(string input)
		{
			string text = (input ?? string.Empty).Trim();
			if (string.IsNullOrEmpty(text))
			{
				_state.PushToast("Command deck is empty.");
				return;
			}
			string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0)
			{
				_state.PushToast("Command deck is empty.");
				return;
			}
			switch (array[0].ToLowerInvariant())
			{
			case "help":
				_state.PushToast("Commands: spawn, heal, revive, despawn, destroy, noaggro, energy, god, strength, boost, truck, level.");
				return;
			case "spawn":
				ExecuteSpawnCommand(array);
				return;
			case "heal":
				ExecuteHealCommand(array);
				return;
			case "revive":
				ExecuteReviveCommand(array);
				return;
			case "despawn":
				if (array.Length >= 2 && array[1].Equals("enemies", StringComparison.OrdinalIgnoreCase))
				{
					DespawnEnemies();
					return;
				}
				break;
			case "destroy":
				if (array.Length >= 2 && array[1].Equals("enemies", StringComparison.OrdinalIgnoreCase))
				{
					DestroyEnemies();
					return;
				}
				break;
			case "noaggro":
				SetNoAggro(array.Length < 2 || ParseToggle(array[1], _state.NoAggro));
				return;
			case "energy":
				SetInfiniteEnergy(array.Length < 2 || ParseToggle(array[1], _state.InfiniteEnergy));
				return;
			case "god":
				SetGodMode(array.Length < 2 || ParseToggle(array[1], _state.GodMode));
				return;
			case "strength":
				SetInfiniteStrength(array.Length < 2 || ParseToggle(array[1], _state.InfiniteStrength));
				return;
			case "boost":
				ExecuteBoostCommand(array);
				return;
			case "truck":
				if (array.Length >= 2 && array[1].Equals("valuables", StringComparison.OrdinalIgnoreCase))
				{
					RecallValuablesToTruck();
					return;
				}
				break;
			case "level":
				ExecuteLevelCommand(array);
				return;
			}
			_state.PushToast("Unknown command: " + text);
		}

		public void Spawn(SectorSpawnEntry entry, int count)
		{
			count = Mathf.Clamp(count, 1, 25);
			if (EnsureHostTools("spawning"))
			{
				switch (entry.Kind)
				{
				case SectorSpawnKind.Enemy:
					SpawnEnemyEntry(entry, count);
					break;
				case SectorSpawnKind.Item:
					SpawnItemEntry(entry, count);
					break;
				case SectorSpawnKind.Valuable:
					SpawnValuableEntry(entry, count);
					break;
				case SectorSpawnKind.CosmeticBox:
					SpawnValuableEntry(entry, count);
					break;
				}
			}
		}

		public void RefillLocalPlayer()
		{
			PlayerHealth playerHealth = SectorAccess.GetPlayerHealth(PlayerAvatar.instance);
			if ((Object)(object)playerHealth != (Object)null)
			{
				int num = Mathf.Max(0, SectorAccess.GetMaxHealth(playerHealth) - SectorAccess.GetHealth(playerHealth));
				if (num > 0)
				{
					playerHealth.Heal(num, true);
				}
			}
			if ((Object)(object)PlayerController.instance != (Object)null)
			{
				SectorAccess.SetEnergyCurrent(PlayerController.instance, SectorAccess.GetEnergyStart(PlayerController.instance));
			}
			_state.PushToast("Local player refilled.");
		}

		public void HealPlayer(PlayerAvatar? player)
		{
			PlayerHealth playerHealth = SectorAccess.GetPlayerHealth(player);
			if ((Object)(object)playerHealth == (Object)null)
			{
				_state.PushToast("Player health is unavailable.");
				return;
			}
			int num = Mathf.Max(0, SectorAccess.GetMaxHealth(playerHealth) - SectorAccess.GetHealth(playerHealth));
			if (num <= 0)
			{
				_state.PushToast(SectorAccess.GetPlayerName(player) + " is already full.");
				return;
			}
			playerHealth.HealOther(num, true);
			_state.PushToast("Healed " + SectorAccess.GetPlayerName(player) + ".");
		}

		public void AddLobbyTaxToken(Rarity rarity)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			AddLobbyTaxToken(rarity, 1);
		}

		public void AddLobbyTaxToken(Rarity rarity, string amountText)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (!int.TryParse((amountText ?? string.Empty).Trim(), out var result))
			{
				_state.PushToast("Enter a whole number for tax tokens.");
			}
			else
			{
				AddLobbyTaxToken(rarity, result);
			}
		}

		public void AddLobbyTaxToken(Rarity rarity, int amount)
		{
			//IL_0059: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureCurrencyTools())
			{
				return;
			}
			int num = Mathf.Clamp(amount, 1, 999);
			if (!SemiFunc.IsMultiplayer())
			{
				if (SectorAccess.AddTaxTokens(rarity, num))
				{
					_state.PushToast($"Added {num} {GetRarityName(rarity)} tax token(s).");
				}
				else
				{
					_state.PushToast("Tax token bank is unavailable right now.");
				}
			}
			else if (SectorNetwork.BroadcastLobbyTaxToken(rarity, num))
			{
				_state.PushToast($"Sent {num} {GetRarityName(rarity)} tax token(s) to Sector clients.");
			}
			else
			{
				_state.PushToast("Tax token broadcast failed.");
			}
		}

		public void HealAllPlayers()
		{
			int num = 0;
			foreach (PlayerAvatar player in SectorGame.GetPlayers())
			{
				PlayerHealth playerHealth = SectorAccess.GetPlayerHealth(player);
				if (!((Object)(object)playerHealth == (Object)null))
				{
					int num2 = Mathf.Max(0, SectorAccess.GetMaxHealth(playerHealth) - SectorAccess.GetHealth(playerHealth));
					if (num2 > 0)
					{
						playerHealth.HealOther(num2, true);
						num++;
					}
				}
			}
			_state.PushToast((num > 0) ? $"Healed {num} player(s)." : "Nobody needed healing.");
		}

		public void RevivePlayer(PlayerAvatar? player)
		{
			PlayerDeathHead playerDeathHead = SectorAccess.GetPlayerDeathHead(player);
			if ((Object)(object)player == (Object)null || !SectorAccess.IsPlayerDead(player) || (Object)(object)playerDeathHead == (Object)null)
			{
				_state.PushToast("That player is not in a revivable state.");
			}
			else if (EnsureHostTools("reviving"))
			{
				SectorAccess.SetInExtractionPoint(playerDeathHead, enabled: true);
				playerDeathHead.Revive();
				_state.PushToast("Revive requested for " + SectorAccess.GetPlayerName(player) + ".");
			}
		}

		public void ReviveAllPlayers()
		{
			if (!EnsureHostTools("reviving"))
			{
				return;
			}
			int num = 0;
			foreach (PlayerAvatar player in SectorGame.GetPlayers())
			{
				PlayerDeathHead playerDeathHead = SectorAccess.GetPlayerDeathHead(player);
				if (!((Object)(object)player == (Object)null) && SectorAccess.IsPlayerDead(player) && !((Object)(object)playerDeathHead == (Object)null))
				{
					SectorAccess.SetInExtractionPoint(playerDeathHead, enabled: true);
					playerDeathHead.Revive();
					num++;
				}
			}
			_state.PushToast((num > 0) ? $"Revive requested for {num} player(s)." : "No dead players found.");
		}

		public void DespawnEnemies()
		{
			if (!EnsureHostTools("enemy despawn"))
			{
				return;
			}
			int num = 0;
			if ((Object)(object)EnemyDirector.instance != (Object)null)
			{
				foreach (EnemyParent item in SectorAccess.GetSpawnedEnemies(EnemyDirector.instance).ToList())
				{
					if (!((Object)(object)item == (Object)null) && SectorAccess.IsEnemySpawned(item))
					{
						item.SpawnedTimerSet(0f);
						item.DespawnedTimerSet(10f, false);
						num++;
					}
				}
			}
			_state.PushToast((num > 0) ? $"Queued {num} enemy despawn(s)." : "No spawned enemies to despawn.");
		}

		public void DestroyEnemies()
		{
			if (!EnsureHostTools("enemy destroy"))
			{
				return;
			}
			int num = 0;
			if ((Object)(object)EnemyDirector.instance != (Object)null)
			{
				List<EnemyParent> spawnedEnemies = SectorAccess.GetSpawnedEnemies(EnemyDirector.instance);
				foreach (EnemyParent item in spawnedEnemies.ToList())
				{
					if (!((Object)(object)item == (Object)null))
					{
						spawnedEnemies.Remove(item);
						if (SemiFunc.IsMultiplayer())
						{
							PhotonNetwork.Destroy(((Component)item).gameObject);
						}
						else
						{
							Object.Destroy((Object)(object)((Component)item).gameObject);
						}
						num++;
					}
				}
			}
			_state.PushToast((num > 0) ? $"Destroyed {num} enemy object(s)." : "No enemies found.");
		}

		public void RecallValuablesToTruck()
		{
			//IL_00b9: 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_00c0: 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)
			if (!EnsureHostTools("valuable recall"))
			{
				return;
			}
			if ((Object)(object)TruckSafetySpawnPoint.instance == (Object)null)
			{
				_state.PushToast("Truck safety spawn is unavailable in this scene.");
				return;
			}
			ValuableObject[] array = Object.FindObjectsByType<ValuableObject>((FindObjectsSortMode)0);
			int num = 0;
			Vector3 val2 = default(Vector3);
			for (int i = 0; i < array.Length; i++)
			{
				ValuableObject val = array[i];
				PhysGrabObject valuablePhysGrabObject = SectorAccess.GetValuablePhysGrabObject(val);
				if (!((Object)(object)valuablePhysGrabObject == (Object)null))
				{
					int num2 = i % 8;
					int num3 = i / 8;
					float num4 = (float)num2 / 8f * MathF.PI * 2f;
					float num5 = 1.2f + (float)num3 * 0.8f;
					((Vector3)(ref val2))..ctor(Mathf.Cos(num4) * num5, 0.35f + (float)num3 * 0.1f, Mathf.Sin(num4) * num5);
					valuablePhysGrabObject.Teleport(((Component)TruckSafetySpawnPoint.instance).transform.position + val2, ((Component)TruckSafetySpawnPoint.instance).transform.rotation);
					val.DollarValueSetLogic();
					num++;
				}
			}
			_state.PushToast((num > 0) ? $"Recalled {num} valuable(s) to the truck." : "No valuables found.");
		}

		public void DiscoverExtractionPoint()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			if (!EnsureHostTools("extraction discovery"))
			{
				return;
			}
			ExtractionPoint roundExtractionPointCurrent = SectorAccess.GetRoundExtractionPointCurrent(RoundDirector.instance);
			if ((Object)(object)roundExtractionPointCurrent != (Object)null && (int)SectorAccess.GetExtractionPointState(roundExtractionPointCurrent) > 1)
			{
				_state.PushToast("An extraction point is already discovered.");
				return;
			}
			ExtractionPoint val = FindNearestExtractionPoint(idleOnly: true);
			if ((Object)(object)val == (Object)null)
			{
				_state.PushToast("No idle extraction point is available.");
			}
			else if (SectorAccess.ActivateExtractionPoint(val))
			{
				_state.PushToast("Extraction point discovery requested.");
			}
			else
			{
				_state.PushToast("Extraction point discovery failed.");
			}
		}

		public void CompleteExtractionPoint()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Invalid comparison between Unknown and I4
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Invalid comparison between Unknown and I4
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Invalid comparison between Unknown and I4
			if (!EnsureHostTools("extraction completion"))
			{
				return;
			}
			ExtractionPoint roundExtractionPointCurrent = SectorAccess.GetRoundExtractionPointCurrent(RoundDirector.instance);
			if ((Object)(object)roundExtractionPointCurrent == (Object)null)
			{
				_state.PushToast("Discover an extraction point first.");
				return;
			}
			State extractionPointState = SectorAccess.GetExtractionPointState(roundExtractionPointCurrent);
			if ((int)extractionPointState == 1 || (int)extractionPointState == 0)
			{
				_state.PushToast("Discover an extraction point first.");
			}
			else if ((int)extractionPointState == 6)
			{
				_state.PushToast("Extraction point is already completing.");
			}
			else if ((int)extractionPointState == 7 || (int)extractionPointState == 9)
			{
				_state.PushToast("Extraction point is already complete.");
			}
			else if (SectorAccess.CompleteExtractionPoint(roundExtractionPointCurrent))
			{
				_state.PushToast("Extraction point completion requested.");
			}
			else
			{
				_state.PushToast("Extraction point completion failed.");
			}
		}

		public void ForceEnemyInvestigateHere()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (EnsureHostTools("enemy redirect"))
			{
				PlayerAvatar localPlayer = SectorGame.GetLocalPlayer();
				if ((Object)(object)localPlayer == (Object)null)
				{
					_state.PushToast("Local player anchor is unavailable.");
					return;
				}
				SemiFunc.EnemyInvestigate(((Component)localPlayer).transform.position, 100f, true);
				_state.PushToast("Enemies redirected toward your position.");
			}
		}

		public void ToggleSpawnIdlePause()
		{
			if (EnsureHostTools("enemy idle timer toggle"))
			{
				if ((Object)(object)EnemyDirector.instance == (Object)null)
				{
					_state.PushToast("Enemy director is unavailable.");
					return;
				}
				bool flag = !SectorAccess.GetEnemyNoSpawnIdlePause(EnemyDirector.instance);
				SectorAccess.SetEnemyNoSpawnIdlePause(EnemyDirector.instance, flag);
				_state.PushToast(flag ? "Enemy spawn idle pause disabled." : "Enemy spawn idle pause restored.");
			}
		}

		public void SwitchLevel(string target)
		{
			string text = (target ?? string.Empty).Trim();
			if (string.IsNullOrEmpty(text))
			{
				_state.PushToast("Type a level target or use one of the quick switch buttons.");
			}
			else
			{
				if (!EnsureHostTools("level switching"))
				{
					return;
				}
				if ((Object)(object)RunManager.instance == (Object)null)
				{
					_state.PushToast("Run manager is unavailable.");
					return;
				}
				switch (text.ToLowerInvariant())
				{
				case "next":
					RunManager.instance.ChangeLevel(true, SemiFunc.RunIsArena(), (ChangeLevelType)0);
					_state.PushToast("Advancing to the next level.");
					break;
				case "random":
					RunManager.instance.ChangeLevel(false, false, (ChangeLevelType)1);
					_state.PushToast("Switching to a random run level.");
					break;
				case "refresh":
					RunManager.instance.RestartScene();
					if (!SemiFunc.RunIsTutorial())
					{
						SemiFunc.OnSceneSwitch(SectorAccess.GetRunGameOver(RunManager.instance), false);
					}
					_state.PushToast("Refreshing the current level.");
					break;
				case "shop":
					RunManager.instance.ChangeLevel(false, false, (ChangeLevelType)5);
					_state.PushToast("Switching to the shop.");
					break;
				case "recording":
					RunManager.instance.ChangeLevel(false, false, (ChangeLevelType)6);
					_state.PushToast("Switching to the recording level.");
					break;
				case "lobby":
					SwitchToSpecificLevel(RunManager.instance.levelLobby);
					break;
				case "arena":
					SwitchToSpecificLevel(RunManager.instance.levelArena.FirstOrDefault());
					break;
				default:
				{
					Level val = FindLevelMatch(text);
					if ((Object)(object)val == (Object)null)
					{
						_state.PushToast("No level matched '" + text + "'.");
					}
					else
					{
						SwitchToSpecificLevel(val);
					}
					break;
				}
				}
			}
		}

		public void AddMoney(int amount)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Invalid comparison between Unknown and I4
			if (amount <= 0)
			{
				_state.PushToast("Money amount must be above zero.");
			}
			else
			{
				if (!EnsureCurrencyTools())
				{
					return;
				}
				int num = SemiFunc.StatGetRunCurrency();
				int num2 = ((num > int.MaxValue - amount) ? int.MaxValue : (num + amount));
				SemiFunc.StatSetRunCurrency(num2);
				CurrencyUI instance = CurrencyUI.instance;
				if (instance != null)
				{
					instance.FetchCurrency();
				}
				if (SemiFunc.RunIsShop())
				{
					RunManager instance2 = RunManager.instance;
					if (instance2 != null)
					{
						instance2.ChangeLevel(false, false, (ChangeLevelType)5);
					}
				}
				else if (SemiFunc.RunIsLevel() && (int)SectorAccess.GetExtractionPointState(SectorAccess.GetRoundExtractionPointCurrent(RoundDirector.instance)) > 1)
				{
					RunManager instance3 = RunManager.instance;
					if (instance3 != null)
					{
						instance3.ChangeLevel(false, false, (ChangeLevelType)0);
					}
				}
				_state.PushToast("Added " + SemiFunc.DollarGetString(amount) + ". Cash now " + SemiFunc.DollarGetString(num2) + ".");
			}
		}

		public void AddMoney(string amountText)
		{
			if (!int.TryParse((amountText ?? string.Empty).Trim(), out var result))
			{
				_state.PushToast("Enter a whole number for cash.");
			}
			else
			{
				AddMoney(result);
			}
		}

		public IReadOnlyList<string> GetLevelSuggestions(string search)
		{
			if (RunManager.instance?.levels == null)
			{
				return Array.Empty<string>();
			}
			IEnumerable<Level> source = RunManager.instance.levels.Where((Level level) => (Object)(object)level != (Object)null);
			string trimmedSearch = (search ?? string.Empty).Trim();
			if (!string.IsNullOrEmpty(trimmedSearch))
			{
				source = source.Where((Level level) => LevelMatches(level, trimmedSearch, allowPartial: true));
			}
			return (from name in (from name in source.Select(GetLevelDisplayName)
					where !string.IsNullOrWhiteSpace(name)
					select name).Distinct<string>(StringComparer.OrdinalIgnoreCase)
				orderby name
				select name).Take(8).ToList();
		}

		public void SetGodMode(bool enabled)
		{
			_state.GodMode = enabled;
			_state.PushToast(enabled ? "God mode armed for the local player." : "God mode disabled.");
		}

		public void SetInfiniteEnergy(bool enabled)
		{
			_state.InfiniteEnergy = enabled;
			_state.PushToast(enabled ? "Infinite energy armed." : "Infinite energy disabled.");
		}

		public void SetInfiniteStrength(bool enabled)
		{
			_state.InfiniteStrength = enabled;
			if (!enabled)
			{
				RestoreInfiniteStrength();
			}
			_state.PushToast(enabled ? "Infinite strength armed. Pick up whatever you want." : "Infinite strength disabled.");
		}

		public void SetNoAggro(bool enabled)
		{
			_state.NoAggro = enabled;
			ApplyNoAggroState(sendRpc: true);
			_state.PushToast(enabled ? "Enemy vision disabled." : "Enemy vision restored.");
		}

		private void ApplyLocalPowerState()
		{
			PlayerAvatar localPlayer = SectorGame.GetLocalPlayer();
			PlayerHealth playerHealth = SectorAccess.GetPlayerHealth(localPlayer);
			if ((Object)(object)playerHealth != (Object)null)
			{
				SectorAccess.SetPlayerGodMode(playerHealth, _state.GodMode);
			}
			if ((Object)(object)PlayerController.instance != (Object)null)
			{
				SectorAccess.SetDebugEnergy(PlayerController.instance, _state.InfiniteEnergy);
				if (_state.InfiniteEnergy)
				{
					SectorAccess.SetEnergyCurrent(PlayerController.instance, SectorAccess.GetEnergyStart(PlayerController.instance));
				}
				ApplyInfiniteStrength(localPlayer);
				if (_state.StickyBoost && _state.SpeedMultiplier > 1.01f)
				{
					PlayerController.instance.OverrideSpeed(_state.SpeedMultiplier, 0.25f);
				}
			}
			if ((Object)(object)EnemyDirector.instance != (Object)null)
			{
				ApplyNoAggroState(sendRpc: false);
			}
		}

		private void ApplyNoAggroState(bool sendRpc)
		{
			string localSteamId = SectorAccess.GetLocalSteamId();
			if (string.IsNullOrWhiteSpace(localSteamId))
			{
				return;
			}
			SectorAccess.SetDebugCommandEnemyNoVision(DebugCommandHandler.instance, localSteamId, _state.NoAggro);
			SectorAccess.SetEnemyNoVision(EnemyDirector.instance, localSteamId, _state.NoAggro);
			if (sendRpc && SemiFunc.IsMultiplayer() && !((Object)(object)PunManager.instance == (Object)null))
			{
				PhotonView punManagerPhotonView = SectorAccess.GetPunManagerPhotonView(PunManager.instance);
				if (!((Object)(object)punManagerPhotonView == (Object)null))
				{
					punManagerPhotonView.RPC("TesterNoAggroCommandRPC", (RpcTarget)2, new object[2] { localSteamId, _state.NoAggro });
				}
			}
		}

		private void ApplyInfiniteStrength(PlayerAvatar? localPlayer)
		{
			PhysGrabber val = localPlayer?.physGrabber ?? PhysGrabber.instance;
			if (!_state.InfiniteStrength)
			{
				RestoreInfiniteStrength();
			}
			else if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)_strengthGrabber != (Object)(object)val)
				{
					RestoreInfiniteStrength();
					_strengthGrabber = val;
					_strengthGrabberOriginal = Mathf.Max(1f, val.grabStrength);
				}
				val.grabStrength = 100f;
			}
		}

		private void RestoreInfiniteStrength()
		{
			PhysGrabber strengthGrabber = _strengthGrabber;
			if ((Object)(object)strengthGrabber == (Object)null)
			{
				_strengthGrabber = null;
				_strengthGrabberOriginal = 1f;
			}
			else
			{
				strengthGrabber.grabStrength = Mathf.Max(1f, _strengthGrabberOriginal);
				_strengthGrabber = null;
				_strengthGrabberOriginal = 1f;
			}
		}

		private void ExecuteSpawnCommand(string[] tokens)
		{
			if (tokens.Length < 3)
			{
				_state.PushToast("Usage: spawn enemy|item|valuable <name> [count]");
				return;
			}
			int result = 1;
			bool num = int.TryParse(tokens[^1], out result);
			result = Mathf.Clamp(result, 1, 25);
			string text = tokens[1].ToLowerInvariant();
			int startIndex = 2;
			int num2 = (num ? (tokens.Length - 3) : (tokens.Length - 2));
			if (num2 < 1)
			{
				_state.PushToast("Spawn command is missing a target name.");
				return;
			}
			string text2 = string.Join(" ", tokens, startIndex, num2);
			if (!TryParseKind(text, out var kind))
			{
				_state.PushToast("Unknown spawn type: " + text);
				return;
			}
			SectorSpawnEntry sectorSpawnEntry = _catalog.FindBestMatch(kind, text2);
			if (sectorSpawnEntry == null)
			{
				_state.PushToast("No " + text + " matched '" + text2 + "'.");
			}
			else
			{
				Spawn(sectorSpawnEntry, result);
			}
		}

		private void ExecuteHealCommand(string[] tokens)
		{
			if (tokens.Length < 2)
			{
				_state.PushToast("Usage: heal me|all");
				return;
			}
			string text = tokens[1].ToLowerInvariant();
			if (!(text == "me"))
			{
				if (text == "all")
				{
					HealAllPlayers();
				}
				else
				{
					_state.PushToast("Usage: heal me|all");
				}
			}
			else
			{
				RefillLocalPlayer();
			}
		}

		private void ExecuteReviveCommand(string[] tokens)
		{
			if (tokens.Length < 2)
			{
				_state.PushToast("Usage: revive all");
			}
			else if (tokens[1].Equals("all", StringComparison.OrdinalIgnoreCase))
			{
				ReviveAllPlayers();
			}
			else
			{
				_state.PushToast("Usage: revive all");
			}
		}

		private void ExecuteBoostCommand(string[] tokens)
		{
			float result;
			if (tokens.Length < 2)
			{
				_state.StickyBoost = !_state.StickyBoost;
				_state.PushToast(_state.StickyBoost ? $"Sticky boost enabled at {_state.SpeedMultiplier:0.0}x." : "Sticky boost disabled.");
			}
			else if (tokens[1].Equals("off", StringComparison.OrdinalIgnoreCase))
			{
				_state.StickyBoost = false;
				_state.PushToast("Sticky boost disabled.");
			}
			else if (float.TryParse(tokens[1], out result))
			{
				_state.SpeedMultiplier = Mathf.Clamp(result, 1f, 4f);
				_state.StickyBoost = _state.SpeedMultiplier > 1.01f;
				_state.PushToast(_state.StickyBoost ? $"Sticky boost set to {_state.SpeedMultiplier:0.0}x." : "Sticky boost disabled.");
			}
			else
			{
				_state.PushToast("Usage: boost <multiplier>|off");
			}
		}

		private void ExecuteLevelCommand(string[] tokens)
		{
			if (tokens.Length < 2)
			{
				_state.PushToast("Usage: level <next|random|refresh|shop|lobby|arena|recording|name>");
			}
			else
			{
				SwitchLevel(string.Join(" ", tokens.Skip(1)));
			}
		}

		private static ExtractionPoint? FindNearestExtractionPoint(bool idleOnly)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			RoundDirector instance = RoundDirector.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			PlayerAvatar? localPlayer = SectorGame.GetLocalPlayer();
			Vector3 anchor = ((localPlayer != null) ? ((Component)localPlayer).transform.position : Vector3.zero);
			return (from point in SectorAccess.GetRoundExtractionPointList(instance)
				select (!((Object)(object)point != (Object)null)) ? null : point.GetComponent<ExtractionPoint>() into point
				where (Object)(object)point != (Object)null && (!idleOnly || (int)SectorAccess.GetExtractionPointState(point) == 1)
				orderby Vector3.Distance(((Component)point).transform.position, anchor)
				select point).FirstOrDefault();
		}

		private void SpawnEnemyEntry(SectorSpawnEntry entry, int count)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)entry.EnemySetup == (Object)null || entry.EnemySetup.spawnObjects == null || entry.EnemySetup.spawnObjects.Count == 0)
			{
				_state.PushToast("Enemy profile '" + entry.DisplayName + "' has no spawn objects.");
				return;
			}
			List<LevelPoint> list = SectorGame.GetSpawnPoints(count).ToList();
			if (list.Count == 0)
			{
				_state.PushToast("No usable level points are available yet.");
				return;
			}
			int num = 0;
			RunManager instance = RunManager.instance;
			if (instance != null)
			{
				instance.EnemiesSpawnedRemoveStart();
			}
			try
			{
				for (int i = 0; i < count; i++)
				{
					Vector3 val = ((Component)list[Mathf.Min(i, list.Count - 1)]).transform.position + Vector3.up * 0.1f;
					bool flag = false;
					foreach (PrefabRef spawnObject in entry.EnemySetup.spawnObjects)
					{
						if (spawnObject == null || !spawnObject.IsValid())
						{
							continue;
						}
						GameObject val2 = (SemiFunc.IsMultiplayer() ? PhotonNetwork.InstantiateRoomObject(spawnObject.ResourcePath, val, Quaternion.identity, (byte)0, (object[])null) : Object.Instantiate<GameObject>(spawnObject.Prefab, val, Quaternion.identity));
						if ((Object)(object)val2 == (Object)null)
						{
							continue;
						}
						EnemyParent component = val2.GetComponent<EnemyParent>();
						if ((Object)(object)component != (Object)null)
						{
							flag = true;
							SectorAccess.SetEnemySetupDone(component, enabled: true);
							SectorAccess.SetEnemyFirstSpawnPointUsed(component, enabled: true);
							Enemy componentInChildren = ((Component)component).GetComponentInChildren<Enemy>();
							if (componentInChildren != null)
							{
								componentInChildren.EnemyTeleported(val);
							}
							EnemyDirector instance2 = EnemyDirector.instance;
							if (instance2 != null)
							{
								instance2.FirstSpawnPointAdd(component);
							}
						}
					}
					if (flag)
					{
						num++;
					}
				}
			}
			finally
			{
				RunManager instance3 = RunManager.instance;
				if (instance3 != null)
				{
					instance3.EnemiesSpawnedRemoveEnd();
				}
			}
			_state.PushToast($"Spawned {num} '{entry.DisplayName}' pack(s).");
		}

		private void SpawnItemEntry(SectorSpawnEntry entry, int count)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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)
			//IL_00ac: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (entry.Item?.prefab == null || !entry.Item.prefab.IsValid())
			{
				_state.PushToast("Item '" + entry.DisplayName + "' is missing a valid prefab reference.");
				return;
			}
			List<LevelPoint> list = SectorGame.GetSpawnPoints(count).ToList();
			if (list.Count == 0)
			{
				_state.PushToast("No usable level points are available yet.");
				return;
			}
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				LevelPoint obj = list[Mathf.Min(i, list.Count - 1)];
				Vector3 val = ((Component)obj).transform.position + Vector3.up * (1f + (float)i * 0.03f);
				Quaternion val2 = ((Component)obj).transform.rotation * entry.Item.spawnRotationOffset;
				if (SemiFunc.IsMultiplayer())
				{
					PhotonNetwork.InstantiateRoomObject(entry.Item.prefab.ResourcePath, val, val2, (byte)0, (object[])null);
				}
				else
				{
					Object.Instantiate<GameObject>(entry.Item.prefab.Prefab, val, val2);
				}
				num++;
			}
			_state.PushToast($"Spawned {num} '{entry.DisplayName}' item(s).");
		}

		private void SpawnValuableEntry(SectorSpawnEntry entry, int count)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: 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)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			string text = ((entry.Kind == SectorSpawnKind.CosmeticBox) ? "cosmetic box" : "valuable");
			if (entry.PrefabRef == null || !entry.PrefabRef.IsValid())
			{
				_state.PushToast(GetSentenceCase(text) + " '" + entry.DisplayName + "' is missing a valid prefab reference.");
				return;
			}
			List<LevelPoint> list = SectorGame.GetSpawnPoints(count).ToList();
			if (list.Count == 0)
			{
				_state.PushToast("No usable level points are available yet.");
				return;
			}
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				LevelPoint val = list[Mathf.Min(i, list.Count - 1)];
				Vector3 val2 = ((Component)val).transform.position + Vector3.up * (1f + (float)i * 0.04f);
				GameObject obj = (SemiFunc.IsMultiplayer() ? PhotonNetwork.InstantiateRoomObject(entry.PrefabRef.ResourcePath, val2, ((Component)val).transform.rotation, (byte)0, (object[])null) : Object.Instantiate<GameObject>(entry.PrefabRef.Prefab, val2, ((Component)val).transform.rotation));
				if (obj != null)
				{
					ValuableObject component = obj.GetComponent<ValuableObject>();
					if (component != null)
					{
						component.DollarValueSetLogic();
					}
				}
				num++;
			}
			_state.PushToast($"Spawned {num} '{entry.DisplayName}' {text}(s).");
		}

		private bool EnsureHostTools(string label)
		{
			if (!SectorGame.IsInPlayableRun())
			{
				_state.PushToast("Start or join a live run before using " + label + ".");
				return false;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				_state.PushToast(label + " is host or singleplayer only.");
				return false;
			}
			return true;
		}

		private void SwitchToSpecificLevel(Level? level)
		{
			if ((Object)(object)RunManager.instance == (Object)null || (Object)(object)level == (Object)null)
			{
				_state.PushToast("That level target is unavailable.");
				return;
			}
			string levelDisplayName = GetLevelDisplayName(level);
			SectorAccess.SetRunDebugLevel(RunManager.instance, level);
			try
			{
				RunManager.instance.ChangeLevel(false, false, (ChangeLevelType)0);
			}
			finally
			{
				SectorAccess.SetRunDebugLevel(RunManager.instance, null);
			}
			_state.PushToast("Switching to " + levelDisplayName + ".");
		}

		private bool EnsureCurrencyTools()
		{
			if ((Object)(object)RunManager.instance == (Object)null || (Object)(object)StatsManager.instance == (Object)null)
			{
				_state.PushToast("Currency controls are unavailable right now.");
				return false;
			}
			if (SemiFunc.IsMainMenu() && !SemiFunc.RunIsLobbyMenu())
			{
				_state.PushToast("Join a lobby or start singleplayer before editing cash.");
				return false;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				_state.PushToast("Currency editing is host or singleplayer only.");
				return false;
			}
			return true;
		}

		private static string GetRarityName(Rarity rarity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			return (int)rarity switch
			{
				0 => "green", 
				1 => "blue", 
				2 => "purple", 
				3 => "gold", 
				_ => "unknown", 
			};
		}

		private static string GetSentenceCase(string value)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return char.ToUpperInvariant(value[0]) + value.Substring(1);
			}
			return value;
		}

		private static Level? FindLevelMatch(string target)
		{
			string target2 = target;
			if (RunManager.instance?.levels == null)
			{
				return null;
			}
			Level val = ((IEnumerable<Level>)RunManager.instance.levels).FirstOrDefault((Func<Level, bool>)((Level level) => LevelMatches(level, target2, allowPartial: false)));
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			return ((IEnumerable<Level>)RunManager.instance.levels).FirstOrDefault((Func<Level, bool>)((Level level) => LevelMatches(level, target2, allowPartial: true)));
		}

		private static bool LevelMatches(Level? level, string target, bool allowPartial)
		{
			if ((Object)(object)level == (Object)null)
			{
				return false;
			}
			string value = target.Trim().ToLowerInvariant();
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			foreach (string item in EnumerateLevelTerms(level))
			{
				string text = item.ToLowerInvariant();
				if (text.Equals(value, StringComparison.Ordinal))
				{
					return true;
				}
				if (allowPartial && text.Contains(value, StringComparison.Ordinal))
				{
					return true;
				}
			}
			return false;
		}

		private static IEnumerable<string> EnumerateLevelTerms(Level? level)
		{
			if (!((Object)(object)level == (Object)null))
			{
				string text = level.NarrativeName?.Trim();
				if (!string.IsNullOrEmpty(text))
				{
					yield return text;
				}
				string text2 = CleanLevelName(((Object)level).name);
				if (!string.IsNullOrEmpty(text2))
				{
					yield return text2;
				}
				string text3 = ((Object)level).name?.Trim();
				if (!string.IsNullOrEmpty(text3))
				{
					yield return text3;
				}
			}
		}

		private static string GetLevelDisplayName(Level? level)
		{
			if ((Object)(object)level == (Object)null)
			{
				return "Unknown level";
			}
			string text = level.NarrativeName?.Trim();
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			string text2 = CleanLevelName(((Object)level).name);
			if (!string.IsNullOrEmpty(text2))
			{
				return text2;
			}
			return "Unknown level";
		}

		private static string CleanLevelName(string? rawName)
		{
			string text = (rawName ?? string.Empty).Trim();
			if (!text.StartsWith("Level - ", StringComparison.OrdinalIgnoreCase))
			{
				return text;
			}
			return text.Substring("Level - ".Length).Trim();
		}

		private static bool ParseToggle(string token, bool currentValue)
		{
			switch (token.ToLowerInvariant())
			{
			case "1":
			case "enabled":
			case "on":
			case "true":
			case "enable":
				return true;
			case "0":
			case "disable":
			case "off":
			case "false":
			case "disabled":
				return false;
			default:
				return !currentValue;
			}
		}

		private static bool TryParseKind(string token, out SectorSpawnKind kind)
		{
			switch (token.ToLowerInvariant())
			{
			case "enemy":
			case "enemies":
				kind = SectorSpawnKind.Enemy;
				return true;
			case "items":
			case "item":
				kind = SectorSpawnKind.Item;
				return true;
			case "valuable":
			case "valuables":
				kind = SectorSpawnKind.Valuable;
				return true;
			case "boxes":
			case "cosmetic":
			case "cosmetics":
			case "box":
			case "cosmeticbox":
			case "cosmeticboxes":
				kind = SectorSpawnKind.CosmeticBox;
				return true;
			default:
				kind = SectorSpawnKind.Enemy;
				return false;
			}
		}
	}
	internal static class SectorGame
	{
		public static bool IsInPlayableRun()
		{
			if ((Object)(object)RunManager.instance == (Object)null || (Object)(object)LevelGenerator.Instance == (Object)null)
			{
				return false;
			}
			if (!LevelGenerator.Instance.Generated)
			{
				return false;
			}
			if (SemiFunc.IsMainMenu() || SemiFunc.RunIsLobbyMenu() || SemiFunc.RunIsTutorial())
			{
				return false;
			}
			return true;
		}

		public static PlayerAvatar? GetLocalPlayer()
		{
			PlayerAvatar controllerAvatar = SectorAccess.GetControllerAvatar(PlayerController.instance);
			if ((Object)(object)controllerAvatar != (Object)null)
			{
				return controllerAvatar;
			}
			return PlayerAvatar.instance;
		}

		public static IEnumerable<PlayerAvatar> GetPlayers()
		{
			return SemiFunc.PlayerGetList() ?? new List<PlayerAvatar>();
		}

		public static IEnumerable<LevelPoint> GetSpawnPoints(int desiredCount)
		{
			//IL_0029: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!IsInPlayableRun())
			{
				return Array.Empty<LevelPoint>();
			}
			PlayerAvatar? localPlayer = GetLocalPlayer();
			Vector3 anchor = ((localPlayer != null) ? ((Component)localPlayer).transform.position : Vector3.zero);
			List<LevelPoint> list = SemiFunc.LevelPointsGetAll();
			if (list == null || list.Count == 0)
			{
				return Array.Empty<LevelPoint>();
			}
			return (from point in list
				where (Object)(object)point != (Object)null
				orderby Vector3.Distance(((Component)point).transform.position, anchor)
				select point).Take(Mathf.Max(desiredCount, 1)).ToList();
		}
	}
	internal sealed class SectorCatalog
	{
		private static readonly Regex EnemyPrefix = new Regex("^Enemy (- )?", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		private static readonly Regex ItemPrefix = new Regex("^Item ", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		private static readonly Regex ValuablePrefix = new Regex("^Valuable ", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		private readonly ManualLogSource _logger;

		private readonly List<SectorSpawnEntry> _entries = new List<SectorSpawnEntry>();

		private float _nextRefreshTime;

		public int EnemyCount => _entries.Count((SectorSpawnEntry entry) => entry.Kind == SectorSpawnKind.Enemy);

		public int ItemCount => _entries.Count((SectorSpawnEntry entry) => entry.Kind == SectorSpawnKind.Item);

		public int ValuableCount => _entries.Count((SectorSpawnEntry entry) => entry.Kind == SectorSpawnKind.Valuable);

		public int CosmeticBoxCount => _entries.Count((SectorSpawnEntry entry) => entry.Kind == SectorSpawnKind.CosmeticBox);

		public SectorCatalog(ManualLogSource logger)
		{
			_logger = logger;
		}

		public IReadOnlyList<SectorSpawnEntry> GetEntries(SectorSpawnKind kind, string search)
		{
			RefreshIfNeeded();
			string text = (search ?? string.Empty).Trim();
			if (string.IsNullOrEmpty(text))
			{
				return (from entry in _entries
					where entry.Kind == kind
					orderby entry.DisplayName
					select entry).ToList();
			}
			string normalized = text.ToLowerInvariant();
			return (from entry in _entries
				where entry.Kind == kind && entry.SearchText.Contains(normalized, StringComparison.Ordinal)
				orderby entry.DisplayName
				select entry).ToList();
		}

		public SectorSpawnEntry? FindBestMatch(SectorSpawnKind kind, string query)
		{
			RefreshIfNeeded();
			if (string.IsNullOrWhiteSpace(query))
			{
				return null;
			}
			string trimmed = query.Trim();
			string lowered = trimmed.ToLowerInvariant();
			SectorSpawnEntry sectorSpawnEntry = _entries.FirstOrDefault((SectorSpawnEntry entry) => entry.Kind == kind && (entry.Key.Equals(lowered, StringComparison.Ordinal) || entry.DisplayName.Equals(trimmed, StringComparison.OrdinalIgnoreCase)));
			if (sectorSpawnEntry != null)
			{
				return sectorSpawnEntry;
			}
			return (from entry in _entries
				where entry.Kind == kind
				orderby entry.DisplayName
				select entry).FirstOrDefault((SectorSpawnEntry entry) => entry.Key.StartsWith(lowered, StringComparison.Ordinal) || entry.SearchText.Contains(lowered, StringComparison.Ordinal));
		}

		private void RefreshIfNeeded()
		{
			if (_entries.Count == 0 || !(Time.unscaledTime < _nextRefreshTime))
			{
				_nextRefreshTime = Time.unscaledTime + 2.5f;
				BuildCatalog();
			}
		}

		private void BuildCatalog()
		{
			_entries.Clear();
			try
			{
				BuildEnemyEntries();
				BuildItemEntries();
				BuildValuableEntries();
				BuildCosmeticWorldObjectEntries();
			}
			catch (Exception ex)
			{
				_logger.LogError((object)ex);
			}
		}

		private void BuildEnemyEntries()
		{
			if ((Object)(object)EnemyDirector.instance == (Object)null)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (EnemySetup item in Enumerate(EnemyDirector.instance.enemiesDifficulty1).Concat(Enumerate(EnemyDirector.instance.enemiesDifficulty2)).Concat(Enumerate(EnemyDirector.instance.enemiesDifficulty3)))
			{
				if (!((Object)(object)item == (Object)null))
				{
					string text = CleanEnemyName(((Object)item).name);
					string text2 = text.ToLowerInvariant();
					if (hashSet.Add(text2))
					{
						_entries.Add(new SectorSpawnEntry(SectorSpawnKind.Enemy, text2, text, "Enemy profile", BuildSearchText(text, ((Object)item).name, "enemy"), item));
					}
				}
			}
		}

		private void BuildItemEntries()
		{
			if ((Object)(object)StatsManager.instance == (Object)null)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (Item value in StatsManager.instance.itemDictionary.Values)
			{
				if (!((Object)(object)value == (Object)null) && !value.disabled)
				{
					string text = CleanItemName(((Object)value).name);
					string text2 = text.ToLowerInvariant();
					if (hashSet.Add(text2))
					{
						_entries.Add(new SectorSpawnEntry(SectorSpawnKind.Item, text2, text, ((object)(itemType)(ref value.itemType)).ToString(), BuildSearchText(text, value.itemName, value.description, ((object)(itemType)(ref value.itemType)).ToString(), "item"), null, value));
					}
				}
			}
		}

		private void BuildValuableEntries()
		{
			if ((Object)(object)RunManager.instance == (Object)null || RunManager.instance.levels == null)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (Level level in RunManager.instance.levels)
			{
				if ((Object)(object)level == (Object)null || level.ValuablePresets == null)
				{
					continue;
				}
				foreach (LevelValuables valuablePreset in level.ValuablePresets)
				{
					foreach (PrefabRef item in EnumerateValuables(valuablePreset))
					{
						if (item != null && item.IsValid())
						{
							string text = CleanValuableName(item.PrefabName);
							string text2 = text.ToLowerInvariant();
							if (hashSet.Add(text2))
							{
								_entries.Add(new SectorSpawnEntry(SectorSpawnKind.Valuable, text2, text, level.NarrativeName, BuildSearchText(text, item.PrefabName, level.NarrativeName, "valuable"), null, null, item));
							}
						}
					}
				}
			}
			BuildEnemyValuableEntries(hashSet);
		}

		private void BuildEnemyValuableEntries(HashSet<string> seen)
		{
			if (!((Object)(object)AssetManager.instance == (Object)null))
			{
				AddEnemyValuableEntry(seen, SectorAccess.GetEnemyValuableSmall(AssetManager.instance), "Small");
				AddEnemyValuableEntry(seen, SectorAccess.GetEnemyValuableMedium(AssetManager.instance), "Medium");
				AddEnemyValuableEntry(seen, SectorAccess.GetEnemyValuableBig(AssetManager.instance), "Large");
			}
		}

		private void AddEnemyValuableEntry(HashSet<string> seen, GameObject? prefab, string size)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return;
			}
			string text = "Enemy Orb (" + size + ")";
			string text2 = text.ToLowerInvariant();
			if (seen.Add(text2))
			{
				PrefabRef val = SectorAccess.CreateResourcePrefabRef(prefab, "Valuables/" + ((Object)prefab).name);
				if (val != null)
				{
					_entries.Add(new SectorSpawnEntry(SectorSpawnKind.Valuable, text2, text, "Enemy Orb", BuildSearchText(text, ((Object)prefab).name, size, "enemy", "monster", "orb", "valuable"), null, null, val));
				}
			}
		}

		private void BuildCosmeticWorldObjectEntries()
		{
			if ((Object)(object)ValuableDirector.instance == (Object)null || ValuableDirector.instance.cosmeticWorldObjectSetups == null)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (CosmeticWorldObjectSetup cosmeticWorldObjectSetup in ValuableDirector.instance.cosmeticWorldObjectSetups)
			{
				if (cosmeticWorldObjectSetup == null)
				{
					continue;
				}
				PrefabRef prefab = cosmeticWorldObjectSetup.prefab;
				if (prefab != null && prefab.IsValid())
				{
					string text = ((object)(Rarity)(ref cosmeticWorldObjectSetup.rarity)).ToString().Replace("UltraRare", "Ultra Rare");
					string text2 = "Cosmetic Box (" + text + ")";
					string text3 = text2.ToLowerInvariant();
					if (hashSet.Add(text3))
					{
						_entries.Add(new SectorSpawnEntry(SectorSpawnKind.CosmeticBox, text3, text2, "Cosmetics", BuildSearchText(text2, prefab.PrefabName, text, "cosmetic", "box", "valuable"), null, null, prefab));
					}
				}
			}
		}

		private static IEnumerable<T> Enumerate<T>(IEnumerable<T>? source)
		{
			return source ?? Array.Empty<T>();
		}

		private static IEnumerable<PrefabRef> EnumerateValuables(LevelValuables? preset)
		{
			if ((Object)(object)preset == (Object)null)
			{
				yield break;
			}
			foreach (PrefabRef item in Enumerate(preset.tiny))
			{
				yield return item;
			}
			foreach (PrefabRef item2 in Enumerate(preset.small))
			{
				yield return item2;
			}
			foreach (PrefabRef item3 in Enumerate(preset.medium))
			{
				yield return item3;
			}
			foreach (PrefabRef item4 in Enumerate(preset.big))
			{
				yield return item4;
			}
			foreach (PrefabRef item5 in Enumerate(preset.wide))
			{
				yield return item5;
			}
			foreach (PrefabRef item6 in Enumerate(preset.tall))
			{
				yield return item6;
			}
			foreach (PrefabRef item7 in Enumerate(preset.veryTall))
			{
				yield return item7;
			}
		}

		private static string BuildSearchText(params string?[] fragments)
		{
			return string.Join(" ", fragments.Where((string fragment) => !string.IsNullOrWhiteSpace(fragment))).ToLowerInvariant();
		}

		private static string CleanEnemyName(string rawName)
		{
			return EnemyPrefix.Replace(rawName ?? string.Empty, string.Empty).Trim();
		}

		private static string CleanItemName(string rawName)
		{
			return ItemPrefix.Replace(rawName ?? string.Empty, string.Empty).Trim();
		}

		private static string CleanValuableName(string rawName)
		{
			return ValuablePrefix.Replace(rawName ?? string.Empty, string.Empty).Trim();
		}
	}
	internal enum SectorTab
	{
		Ops,
		Spawn,
		Players,
		World,
		Scene
	}
	internal enum SectorSpawnKind
	{
		Enemy,
		Item,
		Valuable,
		CosmeticBox
	}
	internal sealed class SectorSpawnEntry
	{
		public SectorSpawnKind Kind { get; }

		public string Key { get; }

		public string DisplayName { get; }

		public string Subtitle { get; }

		public string SearchText { get; }

		public EnemySetup? EnemySetup { get; }

		public Item? Item { get; }

		public PrefabRef? PrefabRef { get; }

		public SectorSpawnEntry(SectorSpawnKind kind, string key, string displayName, string subtitle, string searchText, EnemySetup? enemySetup = null, Item? item = null, PrefabRef? prefabRef = null)
		{
			Kind = kind;
			Key = key;
			DisplayName = displayName;
			Subtitle = subtitle;
			SearchText = searchText;
			EnemySetup = enemySetup;
			Item = item;
			PrefabRef = prefabRef;
		}
	}
	internal sealed class SectorOverlayState
	{
		private readonly List<string> _activity = new List<string>();

		public bool Visible;

		public Rect WindowRect = new Rect(72f, 72f, 1180f, 720f);

		public SectorTab ActiveTab;

		public SectorSpawnKind ActiveSpawnKind;

		public Vector2 OpsScroll;

		public Vector2 SpawnScroll;

		public Vector2 PlayersScroll;

		public Vector2 WorldScroll;

		public Vector2 SceneScroll;

		public string SpawnSearch = string.Empty;

		public string CommandText = string.Empty;

		public string SpawnAmountText = "1";

		public string ObjectSearch = string.Empty;

		public string LevelSwitchText = string.Empty;

		public string MoneyAddText = "1000";

		public string TaxTokenAmountText = "1";

		public bool GodMode;

		public bool InfiniteEnergy;

		public bool InfiniteStrength;

		public bool StickyBoost;

		public bool NoAggro;

		public float SpeedMultiplier = 2f;

		public bool ShowLevelPoints;

		public bool ShowMeshLabels;

		public bool ShowMeshBounds;

		public int SelectedSceneObjectId;

		public string FlashMessage = string.Empty;

		public float FlashUntil;

		public bool ToggleKeyCaptureActive;

		public bool ToggleKeyPresetPickerOpen;

		public IReadOnlyList<string> Activity => _activity;

		public int SpawnAmount
		{
			get
			{
				if (int.TryParse(SpawnAmountText, out var result))
				{
					return Mathf.Clamp(result, 1, 25);
				}
				return 1;
			}
		}

		public int TaxTokenAmount
		{
			get
			{
				if (int.TryParse(TaxTokenAmountText, out var result))
				{
					return Mathf.Clamp(result, 1, 999);
				}
				return 1;
			}
		}

		public void PushToast(string message)
		{
			if (!string.IsNullOrWhiteSpace(message))
			{
				FlashMessage = message.Trim();
				FlashUntil = Time.unscaledTime + 4.5f;
				_activity.Insert(0, $"[{DateTime.Now:HH:mm:ss}] {FlashMessage}");
				if (_activity.Count > 10)
				{
					_activity.RemoveRange(10, _activity.Count - 10);
				}
			}
		}
	}
	internal readonly struct SectorRuntimeSnapshot
	{
		public bool InRun { get; }

		public bool IsHost { get; }

		public string LevelName { get; }

		public int Players { get; }

		public int AlivePlayers { get; }

		public int DeadPlayers { get; }

		public int Enemies { get; }

		public int Valuables { get; }

		public int LocalHealth { get; }

		public int LocalMaxHealth { get; }

		public float LocalEnergy { get; }

		public float LocalEnergyMax { get; }

		public bool NoAggroEnabled { get; }

		public SectorRuntimeSnapshot(bool inRun, bool isHost, string levelName, int players, int alivePlayers, int deadPlayers, int enemies, int valuables, int localHealth, int localMaxHealth, float localEnergy, float localEnergyMax, bool noAggroEnabled)
		{
			InRun = inRun;
			IsHost = isHost;
			LevelName = levelName;
			Players = players;
			AlivePlayers = alivePlayers;
			DeadPlayers = deadPlayers;
			Enemies = enemies;
			Valuables = valuables;
			LocalHealth = localHealth;
			LocalMaxHealth = localMaxHealth;
			LocalEnergy = localEnergy;
			LocalEnergyMax = localEnergyMax;
			NoAggroEnabled = noAggroEnabled;
		}
	}
	internal readonly struct SectorSceneSnapshot
	{
		public bool FreecamActive { get; }

		public bool CopyForgeActive { get; }

		public int TrackedObjects { get; }

		public int LevelPoints { get; }

		public int MeshObjects { get; }

		public string ModeLabel { get; }

		public SectorSceneSnapshot(bool freecamActive, bool copyForgeActive, int trackedObjects, int levelPoints, int meshObjects, string modeLabel)
		{
			FreecamActive = freecamActive;
			CopyForgeActive = copyForgeActive;
			TrackedObjects = trackedObjects;
			LevelPoints = levelPoints;
			MeshObjects = meshObjects;
			ModeLabel = modeLabel;
		}
	}
	internal sealed class SectorSceneObjectInfo
	{
		public int InstanceId { get; }

		public string Name { get; }

		public string Path { get; }

		public string Category { get; }

		public Vector3 Position { get; }

		public bool Active { get; }

		public int RendererCount { get; }

		public bool HasCollider { get; }

		public bool HasPhotonView { get; }

		public bool CanDelete { get; }

		public bool CanCopy { get; }

		public SectorSceneObjectInfo(int instanceId, string name, string path, string category, Vector3 position, bool active, int rendererCount, bool hasCollider, bool hasPhotonView, bool canDelete, bool canCopy)
		{
			//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)
			InstanceId = instanceId;
			Name = name;
			Path = path;
			Category = category;
			Position = position;
			Active = active;
			RendererCount = rendererCount;
			HasCollider = hasCollider;
			HasPhotonView = hasPhotonView;
			CanDelete = canDelete;
			CanCopy = canCopy;
		}
	}
	internal sealed class SectorSceneQueryResult
	{
		public IReadOnlyList<SectorSceneObjectInfo> Entries { get; }

		public int TotalMatches { get; }

		public SectorSceneQueryResult(IReadOnlyList<SectorSceneObjectInfo> entries, int totalMatches)
		{
			Entries = entries;
			TotalMatches = totalMatches;
		}
	}
	internal static class SectorNetwork
	{
		private const byte TaxTokenEventCode = 171;

		public static bool BroadcastLobbyTaxToken(Rarity rarity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return BroadcastLobbyTaxToken(rarity, 1);
		}

		public static bool BroadcastLobbyTaxToken(Rarity rarity, int amount)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected I4, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			if (!PhotonNetwork.InRoom)
			{
				return false;
			}
			return PhotonNetwork.RaiseEvent((byte)171, (object)new object[2]
			{
				(int)rarity,
				amount
			}, new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)1
			}, SendOptions.SendReliable);
		}

		public static void HandleEvent(EventData photonEvent, SectorOverlayState? state)
		{
			//IL_002c: 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 (photonEvent.Code == 171 && IsFromMasterClient(photonEvent) && TryReadTaxToken(photonEvent.CustomData, out var rarity, out var amount))
			{
				state?.PushToast(SectorAccess.AddTaxTokens(rarity, amount) ? $"Received {amount} {GetRarityName(rarity)} tax token(s)." : "Tax token bank is unavailable right now.");
			}
		}

		private static bool IsFromMasterClient(EventData photonEvent)
		{
			if (PhotonNetwork.MasterClient != null)
			{
				return photonEvent.Sender == PhotonNetwork.MasterClient.ActorNumber;
			}
			return false;
		}

		private static bool TryReadTaxToken(object? data, out Rarity rarity, out int amount)
		{
			rarity = (Rarity)0;
			amount = 1;
			object obj = ((data is object[] array && array.Length != 0) ? array[0] : data);
			object obj2 = ((data is object[] array2 && array2.Length > 1) ? array2[1] : null);
			int num2;
			if (!(obj is byte b))
			{
				if (!(obj is int num))
				{
					return false;
				}
				num2 = num;
			}
			else
			{
				num2 = b;
			}
			if (num2 < 0 || num2 > 3)
			{
				return false;
			}
			rarity = (Rarity)num2;
			if (obj2 is byte b2)
			{
				amount = b2;
			}
			else if (obj2 is int num3)
			{
				amount = num3;
			}
			amount = Mathf.Clamp(amount, 1, 999);
			return true;
		}

		private static string GetRarityName(Rarity rarity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			return (int)rarity switch
			{
				0 => "green", 
				1 => "blue", 
				2 => "purple", 
				3 => "gold", 
				_ => "unknown", 
			};
		}
	}
	[BepInPlugin("Empress.SpawnBrowser", "Empress Spawn Browser", "4.0.0")]
	internal sealed class SectorPlugin : BaseUnityPlugin, IOnEventCallback
	{
		internal const string PluginGuid = "Empress.SpawnBrowser";

		internal const string PluginName = "Empress Spawn Browser";

		internal const string PluginVersion = "4.0.0";

		private ConfigEntry<KeyCode>? _toggleKey;

		private SectorOverlayState? _state;

		private SectorCatalog? _catalog;

		private SectorActions? _actions;

		private SectorSceneController? _scene;

		private SectorUi? _ui;

		private bool _cursorCaptured;

		private bool _photonCallbacksAttached;

		private bool _previousCursorVisible;

		private CursorLockMode _previousCursorLockState;

		private Texture2D? _sectorCursorTexture;

		private void Awake()
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "ToggleKey", (KeyCode)277, "Toggle the Empress Spawn Browser window.");
			_state = new SectorOverlayState();
			_catalog = new SectorCatalog(((BaseUnityPlugin)this).Logger);
			_actions = new SectorActions(((BaseUnityPlugin)this).Logger, _state, _catalog);
			_scene = new SectorSceneController(((BaseUnityPlugin)this).Logger, _state);
			_ui = new SectorUi(((BaseUnityPlugin)this).Logger, _state, _catalog, _actions, _scene, _toggleKey);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"\n ________  __       __  _______   _______   ________   ______    ______  \n/        |/  \\     /  |/       \\ /       \\ /        | /      \\  /      \\ \n$$$$$$$$/ $$  \\   /$$ |$$$$$$$  |$$$$$$$  |$$$$$$$$/ /$$$$$$  |/$$$$$$  |\n$$ |__    $$$  \\ /$$$ |$$ |__$$ |$$ |__$$ |$$ |__    $$ \\__$$/ $$ \\__$$/ \n$$    |   $$$$  /$$$$ |$$    $$/ $$    $$< $$    |   $$      \\ $$      \\ \n$$$$$/    $$ $$ $$/$$ |$$$$$$$/  $$$$$$$  |$$$$$/     $$$$$$  | $$$$$$  |\n$$ |_____ $$ |$$$/ $$ |$$ |      $$ |  $$ |$$ |_____ /  \\__$$ |/  \\__$$ |\n$$       |$$ | $/  $$ |$$ |      $$ |  $$ |$$       |$$    $$/ $$    $$/ \n$$$$$$$$/ $$/      $$/ $$/       $$/   $$/ $$$$$$$$/  $$$$$$/   $$$$$$/  \n");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Empress Spawn Browser 4.0 loaded. Press {_toggleKey.Value} to open the Empress control suite.");
		}

		private void Update()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (_state == null || _actions == null || _scene == null || _toggleKey == null)
			{
				return;
			}
			bool flag = _ui?.IsCapturingToggleKey ?? false;
			if (!flag && Input.GetKeyDown(_toggleKey.Value))
			{
				bool num = !_state.Visible;
				_state.Visible = !_state.Visible;
				if (num)
				{
					_scene.MarkSceneCacheDirty();
				}
				_state.PushToast(_state.Visible ? "Empress Spawn Browser opened." : "Empress Spawn Browser hidden.");
			}
			if (_state.Visible && !flag && Input.GetKeyDown((KeyCode)27))
			{
				_state.Visible = false;
			}
			_actions.Tick();
			_scene.Tick(_state.Visible);
			UpdatePhotonCallbackState();
			if (_state.Visible)
			{
				ApplySectorCursor();
			}
			else
			{
				RestoreCursorState();
			}
		}

		private void OnGUI()
		{
			_ui?.Draw();
			_scene?.DrawOverlay();
		}

		private void OnDisable()
		{
			DetachPhotonCallbacks();
		}

		public void OnEvent(EventData photonEvent)
		{
			if (_state != null && _state.Visible && PhotonNetwork.InRoom)
			{
				SectorNetwork.HandleEvent(photonEvent, _state);
			}
		}

		private void OnDestroy()
		{
			DetachPhotonCallbacks();
			RestoreCursorState();
			_scene?.Reset();
			_actions?.ResetLocalPowerState();
		}

		private void UpdatePhotonCallbackState()
		{
			if (_state != null && _state.Visible && PhotonNetwork.InRoom)
			{
				AttachPhotonCallbacks();
			}
			else
			{
				DetachPhotonCallbacks();
			}
		}

		private void AttachPhotonCallbacks()
		{
			if (!_photonCallbacksAttached)
			{
				PhotonNetwork.AddCallbackTarget((object)this);
				_photonCallbacksAttached = true;
			}
		}

		private void DetachPhotonCallbacks()
		{
			if (_photonCallbacksAttached)
			{
				PhotonNetwork.RemoveCallbackTarget((object)this);
				_photonCallbacksAttached = false;
			}
		}

		private void CaptureCursorState()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!_cursorCaptured)
			{
				_previousCursorVisible = Cursor.visible;
				_previousCursorLockState = Cursor.lockState;
				_cursorCaptured = true;
			}
		}

		private void RestoreCursorState()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (_cursorCaptured)
			{
				Cursor.SetCursor((Texture2D)null, Vector2.zero, (CursorMode)0);
				Cursor.visible = _previousCursorVisible;
				Cursor.lockState = _previousCursorLockState;
				if ((_previousCursorVisible || (int)_previousCursorLockState == 0) && (Object)(object)MenuCursor.instance != (Object)null)
				{
					MenuCursor.instance.Show();
				}
				_cursorCaptured = false;
			}
		}

		private void ApplySectorCursor()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			CaptureCursorState();
			EnsureSectorCursorTexture();
			SuppressGameCursorSystems();
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			Cursor.SetCursor(_sectorCursorTexture, new Vector2((float)((Texture)_sectorCursorTexture).width * 0.5f, (float)((Texture)_sectorCursorTexture).height * 0.5f), (CursorMode)0);
		}

		private void SuppressGameCursorSystems()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			SectorAccess.SetCursorUnlockTimer(CursorManager.instance, -1234f);
			if (!((Object)(object)MenuCursor.instance == (Object)null))
			{
				SectorAccess.SetMenuCursorShowTimer(MenuCursor.instance, 0f);
				SectorAccess.SetMenuCursorOverridePosTimer(MenuCursor.instance, 0f);
				GameObject menuCursorMesh = SectorAccess.GetMenuCursorMesh(MenuCursor.instance);
				if ((Object)(object)menuCursorMesh != (Object)null && menuCursorMesh.activeSelf)
				{
					menuCursorMesh.SetActive(false);
				}
				((Component)MenuCursor.instance).transform.localScale = Vector3.zero;
			}
		}

		private void EnsureSectorCursorTexture()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_sectorCursorTexture != (Object)null)
			{
				return;
			}
			_sectorCursorTexture = new Texture2D(32, 32, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				hideFlags = (HideFlags)61
			};
			for (int i = 0; i < ((Texture)_sectorCursorTexture).height; i++)
			{
				for (int j = 0; j < ((Texture)_sectorCursorTexture).width; j++)
				{
					float num = (float)j - 15.5f;
					float num2 = (float)i - 15.5f;
					float num3 = Mathf.Sqrt(num * num + num2 * num2);
					Color clear = Color.clear;
					if (num3 <= 2.25f)
					{
						((Color)(ref clear))..ctor(1f, 0.94f, 0.94f, 1f);
					}
					else if (num3 <= 5.2f)
					{
						((Color)(ref clear))..ctor(0.98f, 0.22f, 0.16f, 1f);
					}
					else if (num3 <= 7.4f)
					{
						((Color)(ref clear))..ctor(1f, 0.2f, 0.16f, 0.4f);
					}
					_sectorCursorTexture.SetPixel(j, i, clear);
				}
			}
			_sectorCursorTexture.Apply();
		}
	}
	internal sealed class SectorSceneController
	{
		private readonly struct PlacementState
		{
			public Vector3 Position { get; }

			public Quaternion Rotation { get; }

			public PlacementState(Vector3 position, Quaternion rotation)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				Position = position;
				Rotation = rotation;
			}
		}

		private const HideFlags RuntimeHideFlags = 61;

		private const float FreezeRefresh = 0.2f;

		private const int MaxBrowserEntries = 140;

		private const int MaxLabelEntries = 48;

		private const int MaxBoundsEntries = 28;

		private readonly ManualLogSource _logger;

		private readonly SectorOverlayState _state;

		private readonly List<SectorSceneObjectInfo> _sceneObjects = new List<SectorSceneObjectInfo>();

		private readonly Dictionary<int, WeakReference<GameObject>> _sceneObjectRefs = new Dictionary<int, WeakReference<GameObject>>();

		private bool _sceneCacheDirty = true;

		private Transform? _freecamRoot;

		private Transform? _freecamRestoreParent;

		private Vector3 _freecamRestoreLocalPosition;

		private Quaternion _freecamRestoreLocalRotation;

		private float _freecamYaw;

		private float _freecamPitch;

		private bool _freecamActive;

		private int _copySourceId;

		private string _copySourceName = string.Empty;

		private GameObject? _copyPreview;

		private float _copyDistance = 5f;

		private float _copyHeightOffset;

		private Vector3 _copyRotationEuler;

		private GUIStyle? _overlayLabelStyle;

		private GUIStyle? _overlayHintStyle;

		private Texture2D? _overlayLineTexture;

		private Texture2D? _blueOrbGlowTexture;

		private Texture2D? _blueOrbCoreTexture;

		private Texture2D? _orangeOrbGlowTexture;

		private Texture2D? _orangeOrbCoreTexture;

		private GameObject? _worldVisualRoot;

		private Material? _worldLineMaterial;

		private Material? _worldOrbMaterial;

		private readonly List<LineRenderer> _worldLinePool = new List<LineRenderer>();

		private readonly List<GameObject> _worldOrbPool = new List<GameObject>();

		private bool IsCopyForgeActive
		{
			get
			{
				if ((Object)(object)_copyPreview != (Object)null)
				{
					return _copySourceId != 0;
				}
				return false;
			}
		}

		public SectorSceneController(ManualLogSource logger, SectorOverlayState state)
		{
			_logger = logger;
			_state = state;
		}

		public void MarkSceneCacheDirty()
		{
			_sceneCacheDirty = true;
		}

		public void RefreshSceneCacheNow()
		{
			RefreshSceneCache(force: true);
			_state.PushToast("Scene object browser refreshed.");
		}

		public SectorSceneSnapshot GetSnapshot()
		{
			EnsureSceneCache();
			List<LevelPoint> list = SemiFunc.LevelPointsGetAll();
			int meshObjects = _sceneObjects.Count((SectorSceneObjectInfo info) => info.RendererCount > 0);
			string modeLabel = (IsCopyForgeActive ? ("COPY FORGE: " + _copySourceName) : (_freecamActive ? "FREECAM ACTIVE" : "SCENE TOOLING READY"));
			return new SectorSceneSnapshot(_freecamActive, IsCopyForgeActive, _sceneObjects.Count, list?.Count ?? 0, meshObjects, modeLabel);
		}

		public SectorSceneQueryResult QueryObjects(string search)
		{
			EnsureSceneCache();
			IEnumerable<SectorSceneObjectInfo> source = _sceneObjects;
			string text = (search ?? string.Empty).Trim();
			if (!string.IsNullOrEmpty(text))
			{
				string lowered = text.ToLowerInvariant();
				source = source.Where((SectorSceneObjectInfo info) => info.Name.Contains(lowered, StringComparison.OrdinalIgnoreCase) || info.Path.Contains(lowered, StringComparison.OrdinalIgnoreCase) || info.Category.Contains(lowered, StringComparison.OrdinalIgnoreCase));
			}
			List<SectorSceneObjectInfo> list = source.ToList();
			return new SectorSceneQueryResult(list.Take(140).ToList(), list.Count);
		}

		public SectorSceneObjectInfo? GetSelectedObject()
		{
			if (_state.SelectedSceneObjectId == 0)
			{
				return null;
			}
			GameObject val = ResolveSceneObject(_state.SelectedSceneObjectId);
			if (!((Object)(object)val == (Object)null))
			{
				return BuildSceneInfo(val);
			}
			return null;
		}

		public void Tick(bool menuVisible)
		{
			try
			{
				if (!SectorGame.IsInPlayableRun())
				{
					SetWorldVisualsVisible(visible: false);
					if (_freecamActive || IsCopyForgeActive)
					{
						Reset();
					}
					return;
				}
				if (menuVisible || _freecamActive || IsCopyForgeActive)
				{
					KeepPlayerFrozen();
				}
				if (IsCopyForgeActive)
				{
					EnsureFreecamCamera();
					UpdateFreecamMotion(menuVisible);
					UpdateCopyForge(menuVisible);
				}
				else if (_freecamActive)
				{
					EnsureFreecamCamera();
					UpdateFreecamMotion(menuVisible);
					if (!menuVisible && Input.GetKeyDown((KeyCode)27))
					{
						ExitFreecam();
						_state.PushToast("Freecam disengaged.");
					}
				}
				else if ((Object)(object)_freecamRoot != (Object)null)
				{
					RestoreMainCamera();
				}
				UpdateWorldVisuals();
			}
			catch (Exception ex)
			{
				_logger.LogError((object)ex);
				Reset();
				_state.PushToast("Scene tooling hit an error and reset safely.");
			}
		}

		public void DrawOverlay()
		{
			if (SectorGame.IsInPlayableRun())
			{
				EnsureOverlayStyles();
				if (_freecamActive)
				{
					DrawHintBox(IsCopyForgeActive ? ("COPY FORGE: " + _copySourceName + "  |  Left Click place  |  Right Click / Esc cancel  |  Mouse Wheel distance  |  Q/E rotate  |  R/F height") : "FREECAM ACTIVE  |  WASD move  |  Space / Ctrl vertical  |  Shift boost  |  Esc exit  |  F8 reopen Empress Spawn Browser", 16f);
				}
				_ = IsCopyForgeActive;
			}
		}

		public void ToggleFreecam()
		{
			if (_freecamActive)
			{
				bool isCopyForgeActive = IsCopyForgeActive;
				ExitFreecam();
				_state.PushToast(isCopyForgeActive ? "Copy forge aborted." : "Freecam disengaged.");
			}
			else if (!EnsureFreecamCamera())
			{
				_state.PushToast("Main camera is unavailable for freecam.");
			}
			else
			{
				_freecamActive = true;
				_state.Visible = false;
				_state.PushToast("Freecam engaged. Press F8 to reopen Empress Spawn Browser.");
			}
		}

		public void FocusObject(int instanceId)
		{
			GameObject val = ResolveSceneObject(instanceId);
			if ((Object)(object)val == (Object)null)
			{
				RefreshSceneCache(force: true);
				_state.PushToast("That scene object is no longer available.");
				return;
			}
			if (!EnsureFreecamCamera())
			{
				_state.PushToast("Main camera is unavailable for focus jump.");
				return;
			}
			_state.SelectedSceneObjectId = instanceId;
			_freecamActive = true;
			PositionFreecamForTarget(val);
			_state.Visible = false;
			_state.PushToast("Focused freecam on " + ((Object)val).name + ".");
		}

		public void DeleteObject(int instanceId)
		{
			GameObject val = ResolveSceneObject(instanceId);
			if ((Object)(object)val == (Object)null)
			{
				RefreshSceneCache(force: true);
				_state.PushToast("That scene object is already gone.");
				return;
			}
			if (IsProtectedObject(val))
			{
				_state.PushToast(((Object)val).name + " is protected from deletion.");
				return;
			}
			_state.SelectedSceneObjectId = instanceId;
			try
			{
				PhotonView component = val.GetComponent<PhotonView>();
				if (SemiFunc.IsMultiplayer() && (Object)(object)component != (Object)null)
				{
					PhotonNetwork.Destroy(val);
				}
				else
				{
					Object.Destroy((Object)(object)val);
				}
				RefreshSceneCache(force: true);
				_state.PushToast("Deleted " + ((Object)val).name + ".");
			}
			catch (Exception ex)
			{
				_logger.LogError((object)ex);
				_state.PushToast("Could not delete " + ((Object)val).name + ".");
			}
		}

		public void BeginCopyForge(int instanceId)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = ResolveSceneObject(instanceId);
			if ((Object)(object)val == (Object)null)
			{
				RefreshSceneCache(force: true);
				_state.PushToast("That scene object is no longer available.");
				return;
			}
			if (!HasRenderableGeometry(val))
			{
				_state.PushToast(((Object)val).name + " has no visible mesh data to forge from.");
				return;
			}
			if (SemiFunc.IsMultiplayer())
			{
				_state.PushToast("Copy forge creates a local visual clone in multiplayer right now.");
			}
			if (!EnsureFreecamCamera())
			{
				_state.PushToast("Main camera is unavailable for copy forge.");
				return;
			}
			ClearCopyForgeState();
			GameObject val2 = CreateVisualClone(val, preview: true);
			if ((Object)(object)val2 == (Object)null)
			{
				_state.PushToast("Could not build a forge preview for " + ((Object)val).name + ".");
				return;
			}
			_state.SelectedSceneObjectId = 0;
			_copySourceId = instanceId;
			_copySourceName = ((Object)val).name;
			_copyPreview = val2;
			_copyHeightOffset = 0f;
			Quaternion rotation = val.transform.rotation;
			_copyRotationEuler = ((Quaternion)(ref rotation)).eulerAngles;
			_copyDistance = Mathf.Clamp(GetSuggestedDistance(val), 2.2f, 14f);
			_freecamActive = true;
			PositionFreecamForTarget(val);
			_state.Visible = false;
			_state.PushToast("Copy forge armed for " + ((Object)val).name + ".");
		}

		public void Reset()
		{
			ClearCopyForgeState();
			_freecamActive = false;
			RestoreMainCamera();
			SetWorldVisualsVisible(visible: false);
		}

		private void UpdateWorldVisuals()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0522: Unknown result type (might be due to invalid IL or missing references)
			//IL_0524: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: 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_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: 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_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: 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_03e5: Unknown result type (might be due to invalid IL or miss