Decompiled source of ShiftAtMidnightHostMenu v1.0.0

BepInEx/plugins/ShiftAtMidnightMenu/ShiftAtMidnightMenu.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Fusion;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ShiftAtMidnightMenu")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShiftAtMidnightMenu")]
[assembly: AssemblyTitle("ShiftAtMidnightMenu")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ShiftAtMidnightDevTools
{
	internal static class CheatsMenuBridge
	{
		private static CheatsMenu _instance;

		private static float _nextSearchTime;

		private static bool _missingWarningShown;

		internal static bool IsReady => (Object)(object)Get(logIfMissing: false) != (Object)null;

		internal static void Register(CheatsMenu instance)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				bool flag = (Object)(object)_instance != (Object)(object)instance;
				_instance = instance;
				try
				{
					_instance.allowCheatsEvenIfReleaseBuild = true;
					((Behaviour)_instance).enabled = true;
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogWarning((object)("Não foi possível habilitar completamente o CheatsMenu interno: " + ex.Message));
				}
				_missingWarningShown = false;
				if (flag)
				{
					Plugin.Logger.LogInfo((object)"CheatsMenu interno encontrado e habilitado!");
				}
			}
		}

		internal static CheatsMenu Get(bool logIfMissing)
		{
			if ((Object)(object)_instance != (Object)null)
			{
				try
				{
					_instance.allowCheatsEvenIfReleaseBuild = true;
				}
				catch
				{
				}
				return _instance;
			}
			if (Time.unscaledTime < _nextSearchTime)
			{
				return null;
			}
			_nextSearchTime = Time.unscaledTime + 1f;
			try
			{
				Il2CppArrayBase<CheatsMenu> val = Resources.FindObjectsOfTypeAll<CheatsMenu>();
				if (val != null)
				{
					for (int i = 0; i < val.Length; i++)
					{
						CheatsMenu val2 = val[i];
						if (!((Object)(object)val2 == (Object)null))
						{
							Register(val2);
							return _instance;
						}
					}
				}
			}
			catch (Exception ex)
			{
				if (logIfMissing)
				{
					Plugin.Logger.LogWarning((object)("Busca alternativa pelo CheatsMenu falhou: " + ex.Message));
				}
			}
			if (logIfMissing && !_missingWarningShown)
			{
				_missingWarningShown = true;
				Plugin.Logger.LogWarning((object)"CheatsMenu ainda não foi encontrado. Entre em uma partida e tente novamente.");
			}
			return null;
		}

		internal static string GetStatusText()
		{
			return IsReady ? "CONNECTED" : "WAITING FOR GAME";
		}
	}
	[HarmonyPatch(typeof(CheatsMenu), "Awake")]
	internal static class CheatsMenuAwakePatch
	{
		private static void Prefix(CheatsMenu __instance)
		{
			CheatsMenuBridge.Register(__instance);
			__instance.allowCheatsEvenIfReleaseBuild = true;
		}

		private static void Postfix(CheatsMenu __instance)
		{
			CheatsMenuBridge.Register(__instance);
			__instance.allowCheatsEvenIfReleaseBuild = true;
		}
	}
	internal static class DevToolsAccess
	{
		internal static bool CanOpenPublicMenu(out string reason)
		{
			if (!IsInGameScene())
			{
				reason = "The Dev Tools menu is only available during a match.";
				return false;
			}
			if (!IsLocalPlayerHost())
			{
				reason = "The public Dev Tools menu is restricted to the host.";
				return false;
			}
			reason = "";
			return true;
		}

		internal static bool EnsureHost(string actionName)
		{
			if (CanOpenPublicMenu(out var reason))
			{
				return true;
			}
			Plugin.Logger.LogWarning((object)("Action blocked: " + actionName + ". " + reason));
			return false;
		}

		internal static bool IsInGameScene()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (!((Scene)(ref activeScene)).IsValid())
				{
					return false;
				}
				if (!((Scene)(ref activeScene)).isLoaded)
				{
					return false;
				}
				return string.Equals(((Scene)(ref activeScene)).name, "Game", StringComparison.OrdinalIgnoreCase);
			}
			catch
			{
				return false;
			}
		}

		internal static bool IsLocalPlayerHost()
		{
			try
			{
				if (TryGetAuthorityFromLocalPlayer(out var playerFound, out var playerIsHost))
				{
					return playerIsHost;
				}
				if (playerFound)
				{
					return false;
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Could not inspect local player authority: " + ex.Message));
			}
			try
			{
				HuntManager instance = HuntManager.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					return ((NetworkBehaviour)instance).HasStateAuthority;
				}
			}
			catch
			{
			}
			try
			{
				PurchaseManager instance2 = PurchaseManager.Instance;
				if ((Object)(object)instance2 != (Object)null)
				{
					return ((NetworkBehaviour)instance2).HasStateAuthority;
				}
			}
			catch
			{
			}
			try
			{
				StoreManager instance3 = StoreManager.Instance;
				if ((Object)(object)instance3 != (Object)null)
				{
					return ((NetworkBehaviour)instance3).HasStateAuthority;
				}
			}
			catch
			{
			}
			try
			{
				CheatsMenu val = CheatsMenuBridge.Get(logIfMissing: false);
				if ((Object)(object)val != (Object)null)
				{
					return ((NetworkBehaviour)val).HasStateAuthority;
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool TryGetAuthorityFromLocalPlayer(out bool playerFound, out bool playerIsHost)
		{
			playerFound = false;
			playerIsHost = false;
			Il2CppArrayBase<PlayerManager> val = Resources.FindObjectsOfTypeAll<PlayerManager>();
			if (val == null)
			{
				return false;
			}
			for (int i = 0; i < val.Length; i++)
			{
				PlayerManager val2 = val[i];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				try
				{
					if ((Object)(object)((Component)val2).gameObject == (Object)null || !((Component)val2).gameObject.activeInHierarchy || !((NetworkBehaviour)val2).HasInputAuthority)
					{
						continue;
					}
					playerFound = true;
					playerIsHost = ((NetworkBehaviour)val2).HasStateAuthority;
					return true;
				}
				catch
				{
				}
			}
			return false;
		}

		internal static string GetAccessStatusText()
		{
			if (!IsInGameScene())
			{
				return "OUTSIDE GAME";
			}
			if (!IsLocalPlayerHost())
			{
				return "CLIENT - BLOCKED";
			}
			return "HOST";
		}
	}
	internal static class DevToolsActions
	{
		private const float PublicMoneyAmount = 10f;

		private const int PublicTokenAmount = 10;

		private const float ItemOrderCooldown = 0.75f;

		private static float _nextItemOrderTime;

		internal static void AddPublicMoney()
		{
			if (!DevToolsAccess.EnsureHost("Add Money") || !TryGetCheatsMenu("Add Money", out var menu))
			{
				return;
			}
			try
			{
				menu.ChangeMoney(10f);
				Plugin.Logger.LogInfo((object)"Public money bonus requested: +$10.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while adding money:\n" + ex));
			}
		}

		internal static void AddPublicTokens()
		{
			if (!DevToolsAccess.EnsureHost("Add Tokens"))
			{
				return;
			}
			try
			{
				StoreManager instance = StoreManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"StoreManager.Instance is not available.");
					return;
				}
				instance.ChangeTokenBalance(10);
				Plugin.Logger.LogInfo((object)"Public token bonus requested: +10.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while adding tokens:\n" + ex));
			}
		}

		internal static void SpawnNpc(string npcId)
		{
			if (!DevToolsAccess.EnsureHost("Spawn NPC") || !TryGetCheatsMenu("Spawn NPC", out var menu))
			{
				return;
			}
			if (string.IsNullOrWhiteSpace(npcId))
			{
				Plugin.Logger.LogWarning((object)"NPC ID is empty.");
				return;
			}
			try
			{
				string text = npcId.Trim();
				menu.Rpc_CMD_SpawnCustomer(text);
				Plugin.Logger.LogInfo((object)("NPC spawn requested. ID=" + text));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while spawning NPC:\n" + ex));
			}
		}

		internal static void SpawnRandomBrowsingCustomer()
		{
			if (!DevToolsAccess.EnsureHost("Spawn Random Browsing Customer"))
			{
				return;
			}
			try
			{
				StoreManager instance = StoreManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"StoreManager.Instance is not available.");
					return;
				}
				instance.SpawnBrowsingNPC();
				Plugin.Logger.LogInfo((object)"Random browsing customer requested.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while spawning browsing customer:\n" + ex));
			}
		}

		internal static void SpawnRandomNuisanceCustomer()
		{
			if (!DevToolsAccess.EnsureHost("Spawn Random Nuisance Customer"))
			{
				return;
			}
			try
			{
				StoreManager instance = StoreManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"StoreManager.Instance is not available.");
					return;
				}
				instance.SpawnNuisanceNPC();
				Plugin.Logger.LogInfo((object)"Random nuisance customer requested.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while spawning nuisance customer:\n" + ex));
			}
		}

		internal static void QueueMonster(int monsterIndex)
		{
			if (!DevToolsAccess.EnsureHost("Queue Monster") || !TryGetCheatsMenu("Queue Monster", out var menu))
			{
				return;
			}
			try
			{
				HuntManager instance = HuntManager.Instance;
				if ((Object)(object)instance == (Object)null || instance.monsterObjs == null)
				{
					Plugin.Logger.LogWarning((object)"Monster catalog is not available.");
					return;
				}
				if (monsterIndex < 0 || monsterIndex >= ((Il2CppArrayBase<GameObject>)(object)instance.monsterObjs).Length)
				{
					Plugin.Logger.LogWarning((object)("Invalid monster index: " + monsterIndex));
					return;
				}
				menu.AddMonsterToSpawnQueue(monsterIndex);
				Plugin.Logger.LogInfo((object)("Monster added to spawn queue. Index=" + monsterIndex));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while queueing monster:\n" + ex));
			}
		}

		internal static void SpawnMonsterNow(int monsterIndex)
		{
			if (!DevToolsAccess.EnsureHost("Spawn Monster Now"))
			{
				return;
			}
			try
			{
				HuntManager instance = HuntManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"HuntManager.Instance is not available.");
					return;
				}
				if (!((NetworkBehaviour)instance).HasStateAuthority)
				{
					Plugin.Logger.LogWarning((object)"Spawn Monster Now requires State Authority.");
					return;
				}
				if (instance.monsterObjs == null || monsterIndex < 0 || monsterIndex >= ((Il2CppArrayBase<GameObject>)(object)instance.monsterObjs).Length)
				{
					Plugin.Logger.LogWarning((object)("Invalid monster index: " + monsterIndex));
					return;
				}
				GameObject val = ((Il2CppArrayBase<GameObject>)(object)instance.monsterObjs)[monsterIndex];
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"Selected monster prefab is null.");
					return;
				}
				instance.SpawnEnemy(monsterIndex);
				Plugin.Logger.LogInfo((object)("Immediate monster spawn requested. Index=" + monsterIndex + ", Prefab=" + ((Object)val).name));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while spawning monster:\n" + ex));
			}
		}

		internal static void StartHunt()
		{
			if (!DevToolsAccess.EnsureHost("Start Hunt") || !TryGetCheatsMenu("Start Hunt", out var menu))
			{
				return;
			}
			try
			{
				menu.StartHunt();
				Plugin.Logger.LogInfo((object)"Full hunt requested.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while starting hunt:\n" + ex));
			}
		}

		internal static void OrderItemFree(ItemCatalogEntry item)
		{
			if (!DevToolsAccess.EnsureHost("Order Free Item"))
			{
				return;
			}
			if (item == null)
			{
				Plugin.Logger.LogWarning((object)"No item was selected.");
				return;
			}
			if (!item.IsAvailable || item.IsSpecialOrBroken)
			{
				Plugin.Logger.LogWarning((object)("The selected item is marked as special or broken. Purchase blocked. Index=" + item.Index));
				return;
			}
			try
			{
				if (Time.unscaledTime < _nextItemOrderTime)
				{
					Plugin.Logger.LogWarning((object)"Purchase ignored to prevent duplicate clicks.");
					return;
				}
				PurchaseManager instance = PurchaseManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"PurchaseManager.Instance is not available.");
					return;
				}
				if (instance.purchaseObjects == null)
				{
					Plugin.Logger.LogWarning((object)"PurchaseManager.purchaseObjects is not available.");
					return;
				}
				int index = item.Index;
				if (index < 0 || index >= ((Il2CppArrayBase<GameObject>)(object)instance.purchaseObjects).Length)
				{
					Plugin.Logger.LogWarning((object)("Item index is outside purchaseObjects: " + index));
					return;
				}
				GameObject val = ((Il2CppArrayBase<GameObject>)(object)instance.purchaseObjects)[index];
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Logger.LogWarning((object)("Purchase blocked because purchaseObjects[" + index + "] is null."));
					return;
				}
				_nextItemOrderTime = Time.unscaledTime + 0.75f;
				instance.PurchaseItem(index, 0f);
				Plugin.Logger.LogInfo((object)("Free item purchase requested. Index=" + index + ", Object=" + ((Object)val).name));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while ordering free item:\n" + ex));
			}
		}

		private static bool TryGetCheatsMenu(string action, out CheatsMenu menu)
		{
			menu = CheatsMenuBridge.Get(logIfMissing: true);
			if ((Object)(object)menu != (Object)null)
			{
				return true;
			}
			Plugin.Logger.LogWarning((object)(action + " was not executed because CheatsMenu is unavailable."));
			return false;
		}
	}
	internal sealed class NpcCatalogEntry
	{
		internal string Id;

		internal string PrefabName;

		internal bool IsDoppelganger;

		internal int Entertainment;

		internal int Difficulty;

		internal int MinimumDay;

		internal int MaximumDay;

		internal int ForcedDay;

		internal int ForcedIndex;

		internal int MustBeAliveCount;

		internal int MustHaveSpawnedCount;
	}
	internal sealed class MonsterCatalogEntry
	{
		internal int Index;

		internal string Name;

		internal int MultiplayerDifficulty;

		internal int SingleplayerDifficulty;
	}
	internal sealed class ItemCatalogEntry
	{
		internal int Index;

		internal string Name;

		internal string PurchaseObjectName;

		internal string ScanObjectName;

		internal int Cost;

		internal int ScanMatchCount;

		internal bool HasCostConflict;

		internal bool IsAvailable;

		internal bool IsSpecialOrBroken;
	}
	internal static class DevToolsCatalogs
	{
		internal static readonly List<NpcCatalogEntry> Npcs = new List<NpcCatalogEntry>();

		internal static readonly List<MonsterCatalogEntry> Monsters = new List<MonsterCatalogEntry>();

		internal static readonly List<ItemCatalogEntry> Items = new List<ItemCatalogEntry>();

		internal static string NpcStatus = "Not scanned";

		internal static string MonsterStatus = "Not scanned";

		internal static string ItemStatus = "Not scanned";

		internal static int AvailableItemCount;

		internal static int SpecialItemCount;

		private static int _lastPurchaseObjectCount;

		internal static void RefreshAll()
		{
			RefreshNpcs();
			RefreshMonsters();
			RefreshItems();
			Plugin.Logger.LogInfo((object)("Catálogos atualizados: " + $"{Npcs.Count} NPCs, " + $"{Monsters.Count} monsters, " + $"{AvailableItemCount} available items, " + $"{SpecialItemCount} special/broken indexes."));
		}

		internal static void RefreshNpcs()
		{
			Npcs.Clear();
			try
			{
				Il2CppArrayBase<Npc> val = Resources.FindObjectsOfTypeAll<Npc>();
				Dictionary<string, bool> dictionary = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
				if (val != null)
				{
					for (int i = 0; i < val.Length; i++)
					{
						Npc val2 = val[i];
						if ((Object)(object)val2 == (Object)null)
						{
							continue;
						}
						string id = val2.id;
						if (!string.IsNullOrWhiteSpace(id))
						{
							id = id.Trim();
							if (!dictionary.ContainsKey(id))
							{
								dictionary.Add(id, value: true);
								NpcCatalogEntry npcCatalogEntry = new NpcCatalogEntry();
								npcCatalogEntry.Id = id;
								npcCatalogEntry.PrefabName = GetObjectName((Object)(object)val2.prefab, "(no prefab)");
								npcCatalogEntry.IsDoppelganger = val2.isDoppelganger;
								npcCatalogEntry.Entertainment = val2.entertainment;
								npcCatalogEntry.Difficulty = val2.difficulty;
								npcCatalogEntry.MinimumDay = val2.onlySpawnAfterThisDay;
								npcCatalogEntry.MaximumDay = val2.onlySpawnBeforeThisDay;
								npcCatalogEntry.ForcedDay = val2.alwaysOnlySpawnOnThisDay;
								npcCatalogEntry.ForcedIndex = val2.alwaysOnlySpawnOnThisIndex;
								npcCatalogEntry.MustBeAliveCount = ((val2.mustBeAliveToSpawn != null) ? ((Il2CppArrayBase<string>)(object)val2.mustBeAliveToSpawn).Length : 0);
								npcCatalogEntry.MustHaveSpawnedCount = ((val2.mustHaveSpawnedBefore != null) ? ((Il2CppArrayBase<string>)(object)val2.mustHaveSpawnedBefore).Length : 0);
								Npcs.Add(npcCatalogEntry);
							}
						}
					}
				}
				Npcs.Sort((NpcCatalogEntry left, NpcCatalogEntry right) => string.Compare(left.Id, right.Id, StringComparison.OrdinalIgnoreCase));
				NpcStatus = $"{Npcs.Count} NPCs found";
			}
			catch (Exception ex)
			{
				NpcStatus = "Scan failed";
				Plugin.Logger.LogError((object)("Erro ao escanear NPCs:\n" + ex));
			}
		}

		internal static void RefreshMonsters()
		{
			Monsters.Clear();
			try
			{
				HuntManager instance = HuntManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					MonsterStatus = "HuntManager not ready";
					return;
				}
				Il2CppReferenceArray<GameObject> monsterObjs = instance.monsterObjs;
				if (monsterObjs == null)
				{
					MonsterStatus = "monsterObjs is null";
					return;
				}
				for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)monsterObjs).Length; i++)
				{
					MonsterCatalogEntry monsterCatalogEntry = new MonsterCatalogEntry();
					monsterCatalogEntry.Index = i;
					monsterCatalogEntry.Name = GetObjectName((Object)(object)((Il2CppArrayBase<GameObject>)(object)monsterObjs)[i], "Monster " + i);
					monsterCatalogEntry.MultiplayerDifficulty = GetMonsterDifficulty(instance.monsterDifficultyPoints, i);
					monsterCatalogEntry.SingleplayerDifficulty = GetMonsterDifficulty(instance.monsterSingleplayerDifficultyPoints, i);
					Monsters.Add(monsterCatalogEntry);
				}
				MonsterStatus = $"{Monsters.Count} monsters found";
			}
			catch (Exception ex)
			{
				MonsterStatus = "Scan failed";
				Plugin.Logger.LogError((object)("Erro ao escanear monsters:\n" + ex));
			}
		}

		internal static void RefreshItems()
		{
			Items.Clear();
			AvailableItemCount = 0;
			SpecialItemCount = 0;
			_lastPurchaseObjectCount = 0;
			try
			{
				PurchaseManager instance = PurchaseManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					ItemStatus = "PurchaseManager not ready";
					return;
				}
				Il2CppReferenceArray<GameObject> purchaseObjects = instance.purchaseObjects;
				if (purchaseObjects == null)
				{
					ItemStatus = "purchaseObjects is null";
					return;
				}
				_lastPurchaseObjectCount = ((Il2CppArrayBase<GameObject>)(object)purchaseObjects).Length;
				for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)purchaseObjects).Length; i++)
				{
					GameObject val = ((Il2CppArrayBase<GameObject>)(object)purchaseObjects)[i];
					if (!((Object)(object)val == (Object)null))
					{
						ItemCatalogEntry item = CreateAvailableItemEntry(i, val);
						Items.Add(item);
						AvailableItemCount++;
					}
				}
				for (int j = 0; j < ((Il2CppArrayBase<GameObject>)(object)purchaseObjects).Length; j++)
				{
					GameObject val2 = ((Il2CppArrayBase<GameObject>)(object)purchaseObjects)[j];
					if (!((Object)(object)val2 != (Object)null))
					{
						ItemCatalogEntry item2 = CreateSpecialItemEntry(j);
						Items.Add(item2);
						SpecialItemCount++;
					}
				}
				ItemStatus = $"{AvailableItemCount} available | {SpecialItemCount} special/broken | total {_lastPurchaseObjectCount}";
				Plugin.Logger.LogInfo((object)"Item Browser carregado diretamente de PurchaseManager.purchaseObjects.");
				Plugin.Logger.LogInfo((object)("Item Browser report: " + $"total={_lastPurchaseObjectCount}, " + $"available={AvailableItemCount}, " + $"specialOrBroken={SpecialItemCount}."));
			}
			catch (Exception ex)
			{
				ItemStatus = "Scan failed";
				Plugin.Logger.LogError((object)("Erro ao carregar purchaseObjects:\n" + ex));
			}
		}

		private static ItemCatalogEntry CreateAvailableItemEntry(int index, GameObject purchaseObject)
		{
			string objectName = GetObjectName((Object)(object)purchaseObject, "Purchase Object " + index);
			ItemCatalogEntry itemCatalogEntry = new ItemCatalogEntry();
			itemCatalogEntry.Index = index;
			itemCatalogEntry.Name = objectName;
			itemCatalogEntry.PurchaseObjectName = objectName;
			itemCatalogEntry.ScanObjectName = "Not used";
			itemCatalogEntry.Cost = -1;
			itemCatalogEntry.ScanMatchCount = 0;
			itemCatalogEntry.HasCostConflict = false;
			itemCatalogEntry.IsAvailable = true;
			itemCatalogEntry.IsSpecialOrBroken = false;
			return itemCatalogEntry;
		}

		private static ItemCatalogEntry CreateSpecialItemEntry(int index)
		{
			ItemCatalogEntry itemCatalogEntry = new ItemCatalogEntry();
			itemCatalogEntry.Index = index;
			itemCatalogEntry.Name = "[SPECIAL / BROKEN] Index " + index.ToString("000");
			itemCatalogEntry.PurchaseObjectName = "(null / internally handled purchase)";
			itemCatalogEntry.ScanObjectName = "Not used";
			itemCatalogEntry.Cost = -1;
			itemCatalogEntry.ScanMatchCount = 0;
			itemCatalogEntry.HasCostConflict = false;
			itemCatalogEntry.IsAvailable = false;
			itemCatalogEntry.IsSpecialOrBroken = true;
			return itemCatalogEntry;
		}

		internal static void DumpItemBrowserDebugToLog()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			Plugin.Logger.LogInfo((object)"");
			Plugin.Logger.LogInfo((object)"============================================================");
			Plugin.Logger.LogInfo((object)"                 ITEM BROWSER DEBUG REPORT");
			Plugin.Logger.LogInfo((object)"============================================================");
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("purchaseObjects.Length : ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_lastPurchaseObjectCount);
			}
			logger.LogInfo(val);
			ManualLogSource logger2 = Plugin.Logger;
			val = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Available items        : ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(AvailableItemCount);
			}
			logger2.LogInfo(val);
			ManualLogSource logger3 = Plugin.Logger;
			val = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Special/broken indexes : ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(SpecialItemCount);
			}
			logger3.LogInfo(val);
			Plugin.Logger.LogInfo((object)"");
			Plugin.Logger.LogInfo((object)"---------- AVAILABLE PURCHASE ITEMS ----------");
			bool flag2 = false;
			for (int i = 0; i < Items.Count; i++)
			{
				ItemCatalogEntry itemCatalogEntry = Items[i];
				if (itemCatalogEntry.IsAvailable)
				{
					flag2 = true;
					Plugin.Logger.LogInfo((object)($"[AVAILABLE {itemCatalogEntry.Index:000}] " + itemCatalogEntry.PurchaseObjectName));
				}
			}
			if (!flag2)
			{
				Plugin.Logger.LogWarning((object)"No available purchase items found.");
			}
			Plugin.Logger.LogInfo((object)"");
			Plugin.Logger.LogInfo((object)"---------- SPECIAL / BROKEN INDEXES ----------");
			bool flag3 = false;
			for (int j = 0; j < Items.Count; j++)
			{
				ItemCatalogEntry itemCatalogEntry2 = Items[j];
				if (itemCatalogEntry2.IsSpecialOrBroken)
				{
					flag3 = true;
					Plugin.Logger.LogWarning((object)($"[SPECIAL {itemCatalogEntry2.Index:000}] " + "purchaseObjects[index] is null"));
				}
			}
			if (!flag3)
			{
				Plugin.Logger.LogInfo((object)"No special or broken indexes found.");
			}
			Plugin.Logger.LogInfo((object)"");
			DumpRepeatedPurchaseNamesToLog();
			Plugin.Logger.LogInfo((object)"============================================================");
			Plugin.Logger.LogInfo((object)"                  END ITEM DEBUG REPORT");
			Plugin.Logger.LogInfo((object)"============================================================");
			Plugin.Logger.LogInfo((object)"");
		}

		private static void DumpRepeatedPurchaseNamesToLog()
		{
			Plugin.Logger.LogInfo((object)"---------- REPEATED PURCHASE NAMES ----------");
			Dictionary<string, List<int>> dictionary = new Dictionary<string, List<int>>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < Items.Count; i++)
			{
				ItemCatalogEntry itemCatalogEntry = Items[i];
				if (itemCatalogEntry.IsAvailable && !string.IsNullOrWhiteSpace(itemCatalogEntry.PurchaseObjectName))
				{
					if (!dictionary.TryGetValue(itemCatalogEntry.PurchaseObjectName, out var value))
					{
						value = new List<int>();
						dictionary.Add(itemCatalogEntry.PurchaseObjectName, value);
					}
					value.Add(itemCatalogEntry.Index);
				}
			}
			bool flag = false;
			foreach (KeyValuePair<string, List<int>> item in dictionary)
			{
				if (item.Value.Count > 1)
				{
					flag = true;
					Plugin.Logger.LogWarning((object)("Repeated name: " + item.Key + " | indexes: " + JoinIndexes(item.Value)));
				}
			}
			if (!flag)
			{
				Plugin.Logger.LogInfo((object)"No repeated purchase object names.");
			}
		}

		internal static NpcCatalogEntry FindNpc(string id)
		{
			if (string.IsNullOrWhiteSpace(id))
			{
				return null;
			}
			for (int i = 0; i < Npcs.Count; i++)
			{
				if (string.Equals(Npcs[i].Id, id, StringComparison.OrdinalIgnoreCase))
				{
					return Npcs[i];
				}
			}
			return null;
		}

		internal static MonsterCatalogEntry FindMonster(int index)
		{
			for (int i = 0; i < Monsters.Count; i++)
			{
				if (Monsters[i].Index == index)
				{
					return Monsters[i];
				}
			}
			return null;
		}

		internal static ItemCatalogEntry FindItem(int index)
		{
			for (int i = 0; i < Items.Count; i++)
			{
				if (Items[i].Index == index)
				{
					return Items[i];
				}
			}
			return null;
		}

		internal static void DumpNpcsToLog()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			Plugin.Logger.LogInfo((object)"========== NPC CATALOG ==========");
			bool flag = default(bool);
			for (int i = 0; i < Npcs.Count; i++)
			{
				NpcCatalogEntry npcCatalogEntry = Npcs[i];
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(46, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(i);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ID=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(npcCatalogEntry.Id);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Prefab=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(npcCatalogEntry.PrefabName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Difficulty=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(npcCatalogEntry.Difficulty);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Doppelganger=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(npcCatalogEntry.IsDoppelganger);
				}
				logger.LogInfo(val);
			}
			Plugin.Logger.LogInfo((object)"=================================");
		}

		internal static void DumpMonstersToLog()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			Plugin.Logger.LogInfo((object)"======== MONSTER CATALOG ========");
			bool flag = default(bool);
			for (int i = 0; i < Monsters.Count; i++)
			{
				MonsterCatalogEntry monsterCatalogEntry = Monsters[i];
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(15, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(monsterCatalogEntry.Index);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(monsterCatalogEntry.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("MP=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(monsterCatalogEntry.MultiplayerDifficulty);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("SP=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(monsterCatalogEntry.SingleplayerDifficulty);
				}
				logger.LogInfo(val);
			}
			Plugin.Logger.LogInfo((object)"=================================");
		}

		internal static void DumpItemsToLog()
		{
			DumpItemBrowserDebugToLog();
		}

		private static int GetMonsterDifficulty(Il2CppStructArray<int> values, int index)
		{
			if (values == null)
			{
				return -1;
			}
			if (index < 0 || index >= ((Il2CppArrayBase<int>)(object)values).Length)
			{
				return -1;
			}
			return ((Il2CppArrayBase<int>)(object)values)[index];
		}

		private static string GetObjectName(Object obj, string fallback)
		{
			if (obj == (Object)null)
			{
				return fallback;
			}
			try
			{
				string name = obj.name;
				return string.IsNullOrWhiteSpace(name) ? fallback : name;
			}
			catch
			{
				return fallback;
			}
		}

		private static string JoinIndexes(List<int> indexes)
		{
			string text = "";
			for (int i = 0; i < indexes.Count; i++)
			{
				if (i > 0)
				{
					text += ", ";
				}
				text += indexes[i];
			}
			return text;
		}
	}
	internal static class DevToolsInputBlocker
	{
		private sealed class PlayerInputSnapshot
		{
			internal PlayerManager Player;

			internal PlayerInput Input;

			internal bool InputWasEnabled;

			internal bool DontAllowLockCursorWasEnabled;
		}

		private static readonly FieldInfo MenuOpenField = AccessTools.Field(typeof(DevToolsMenu), "_menuOpen");

		private static readonly List<PlayerInputSnapshot> BlockedInputs = new List<PlayerInputSnapshot>();

		private static bool _blockingInput;

		private static float _nextPlayerSearchTime;

		private static bool _missingMenuFieldLogged;

		private static bool _missingPlayerInputLogged;

		internal static void Sync(DevToolsMenu menu)
		{
			try
			{
				if (IsMenuOpen(menu))
				{
					if (!_blockingInput)
					{
						BeginBlocking();
					}
					MaintainBlocking();
				}
				else if (_blockingInput)
				{
					StopBlocking();
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Erro no bloqueador de input do Dev Tools:\n" + ex));
			}
		}

		internal static void EnforceCursor(DevToolsMenu menu)
		{
			try
			{
				if (IsMenuOpen(menu))
				{
					ForceCursorUnlocked();
				}
			}
			catch
			{
			}
		}

		internal static void ForceRelease()
		{
			try
			{
				if (_blockingInput)
				{
					StopBlocking();
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Erro ao liberar input no encerramento: " + ex.Message));
			}
		}

		private static bool IsMenuOpen(DevToolsMenu menu)
		{
			if ((Object)(object)menu == (Object)null)
			{
				return false;
			}
			if (MenuOpenField == null)
			{
				if (!_missingMenuFieldLogged)
				{
					_missingMenuFieldLogged = true;
					Plugin.Logger.LogError((object)"Campo _menuOpen não foi encontrado no DevToolsMenu.");
				}
				return false;
			}
			if (!(MenuOpenField.GetValue(menu) is bool result))
			{
				return false;
			}
			return result;
		}

		private static void BeginBlocking()
		{
			_blockingInput = true;
			_nextPlayerSearchTime = 0f;
			_missingPlayerInputLogged = false;
			ForceCursorUnlocked();
			FindAndBlockPlayerInputs();
			Plugin.Logger.LogInfo((object)"Input do jogo bloqueado enquanto o Dev Tools está aberto.");
		}

		private static void MaintainBlocking()
		{
			ForceCursorUnlocked();
			if (Time.unscaledTime >= _nextPlayerSearchTime)
			{
				_nextPlayerSearchTime = Time.unscaledTime + 0.5f;
				FindAndBlockPlayerInputs();
			}
			for (int i = 0; i < BlockedInputs.Count; i++)
			{
				PlayerInputSnapshot playerInputSnapshot = BlockedInputs[i];
				if (playerInputSnapshot == null)
				{
					continue;
				}
				try
				{
					if ((Object)(object)playerInputSnapshot.Player != (Object)null)
					{
						playerInputSnapshot.Player.dontAllowLockCursor = true;
					}
					if ((Object)(object)playerInputSnapshot.Input != (Object)null && ((Behaviour)playerInputSnapshot.Input).enabled)
					{
						((Behaviour)playerInputSnapshot.Input).enabled = false;
					}
				}
				catch
				{
				}
			}
		}

		private static void FindAndBlockPlayerInputs()
		{
			try
			{
				Il2CppArrayBase<PlayerManager> val = Resources.FindObjectsOfTypeAll<PlayerManager>();
				if (val == null)
				{
					return;
				}
				int num = 0;
				for (int i = 0; i < val.Length; i++)
				{
					PlayerManager val2 = val[i];
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					try
					{
						if (!((Object)(object)((Component)val2).gameObject == (Object)null) && ((Component)val2).gameObject.activeInHierarchy)
						{
							PlayerInput playerInput = val2.playerInput;
							if (!((Object)(object)playerInput == (Object)null))
							{
								num++;
								TrackAndBlock(val2, playerInput);
							}
						}
					}
					catch
					{
					}
				}
				if (num == 0 && BlockedInputs.Count == 0 && !_missingPlayerInputLogged)
				{
					_missingPlayerInputLogged = true;
					Plugin.Logger.LogWarning((object)"Nenhum PlayerInput ativo foi encontrado. O cursor continuará sendo mantido livre.");
				}
			}
			catch (Exception ex)
			{
				if (!_missingPlayerInputLogged)
				{
					_missingPlayerInputLogged = true;
					Plugin.Logger.LogWarning((object)("Não foi possível procurar PlayerInput: " + ex.Message));
				}
			}
		}

		private static void TrackAndBlock(PlayerManager player, PlayerInput playerInput)
		{
			if (IsAlreadyTracked(player, playerInput))
			{
				player.dontAllowLockCursor = true;
				if (((Behaviour)playerInput).enabled)
				{
					((Behaviour)playerInput).enabled = false;
				}
				return;
			}
			PlayerInputSnapshot playerInputSnapshot = new PlayerInputSnapshot();
			playerInputSnapshot.Player = player;
			playerInputSnapshot.Input = playerInput;
			playerInputSnapshot.InputWasEnabled = ((Behaviour)playerInput).enabled;
			playerInputSnapshot.DontAllowLockCursorWasEnabled = player.dontAllowLockCursor;
			BlockedInputs.Add(playerInputSnapshot);
			player.dontAllowLockCursor = true;
			((Behaviour)playerInput).enabled = false;
			Plugin.Logger.LogInfo((object)("PlayerInput bloqueado: " + GetPlayerName(player)));
		}

		private static bool IsAlreadyTracked(PlayerManager player, PlayerInput playerInput)
		{
			for (int i = 0; i < BlockedInputs.Count; i++)
			{
				PlayerInputSnapshot playerInputSnapshot = BlockedInputs[i];
				if (playerInputSnapshot != null && ((Object)(object)playerInputSnapshot.Player == (Object)(object)player || (Object)(object)playerInputSnapshot.Input == (Object)(object)playerInput))
				{
					return true;
				}
			}
			return false;
		}

		private static void StopBlocking()
		{
			for (int num = BlockedInputs.Count - 1; num >= 0; num--)
			{
				PlayerInputSnapshot playerInputSnapshot = BlockedInputs[num];
				if (playerInputSnapshot != null)
				{
					try
					{
						if ((Object)(object)playerInputSnapshot.Player != (Object)null)
						{
							playerInputSnapshot.Player.dontAllowLockCursor = playerInputSnapshot.DontAllowLockCursorWasEnabled;
						}
						if ((Object)(object)playerInputSnapshot.Input != (Object)null)
						{
							((Behaviour)playerInputSnapshot.Input).enabled = playerInputSnapshot.InputWasEnabled;
						}
					}
					catch
					{
					}
				}
			}
			BlockedInputs.Clear();
			_blockingInput = false;
			_nextPlayerSearchTime = 0f;
			_missingPlayerInputLogged = false;
			Plugin.Logger.LogInfo((object)"Input do jogo restaurado.");
		}

		private static void ForceCursorUnlocked()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Cursor.lockState > 0)
			{
				Cursor.lockState = (CursorLockMode)0;
			}
			if (!Cursor.visible)
			{
				Cursor.visible = true;
			}
		}

		private static string GetPlayerName(PlayerManager player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return "Unknown Player";
			}
			try
			{
				if ((Object)(object)((Component)player).gameObject != (Object)null)
				{
					string name = ((Object)((Component)player).gameObject).name;
					if (!string.IsNullOrWhiteSpace(name))
					{
						return name;
					}
				}
			}
			catch
			{
			}
			return "PlayerManager";
		}
	}
	[HarmonyPatch(typeof(DevToolsMenu), "Update")]
	internal static class DevToolsMenuInputUpdatePatch
	{
		private static void Postfix(DevToolsMenu __instance)
		{
			DevToolsInputBlocker.Sync(__instance);
		}
	}
	[HarmonyPatch(typeof(DevToolsMenu), "OnGUI")]
	internal static class DevToolsMenuInputOnGuiPatch
	{
		private static void Prefix(DevToolsMenu __instance)
		{
			DevToolsInputBlocker.EnforceCursor(__instance);
		}

		private static void Postfix(DevToolsMenu __instance)
		{
			DevToolsInputBlocker.EnforceCursor(__instance);
		}
	}
	[HarmonyPatch(typeof(DevToolsMenu), "OnDestroy")]
	internal static class DevToolsMenuInputDestroyPatch
	{
		private static void Prefix()
		{
			DevToolsInputBlocker.ForceRelease();
		}
	}
	public sealed class DevToolsMenu : MonoBehaviour
	{
		private const int WindowId = 847216;

		private const int PageSize = 9;

		private bool _menuOpen;

		private Rect _windowRect = new Rect(30f, 30f, 650f, 720f);

		private int _selectedTab;

		private int _npcPage;

		private int _monsterPage;

		private int _itemPage;

		private string _npcSearch = "";

		private string _monsterSearch = "";

		private string _itemSearch = "";

		private string _selectedNpcId = "";

		private int _selectedMonsterIndex = -1;

		private int _selectedItemIndex = -1;

		private CursorLockMode _previousCursorLock;

		private bool _previousCursorVisible;

		public DevToolsMenu(IntPtr pointer)
			: base(pointer)
		{
		}//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)


		private void Update()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.MenuKey != null)
			{
				if (_menuOpen && !CanContinueUsingMenu())
				{
					CloseMenu("Dev Tools closed because host or game-scene access was lost.");
				}
				else if (Input.GetKeyDown(Plugin.MenuKey.Value))
				{
					ToggleMenu();
				}
			}
		}

		private void OnDestroy()
		{
			if (_menuOpen)
			{
				_menuOpen = false;
				RestoreCursor();
			}
		}

		private void ToggleMenu()
		{
			string reason;
			if (_menuOpen)
			{
				CloseMenu("Dev Tools Menu closed.");
			}
			else if (!DevToolsAccess.CanOpenPublicMenu(out reason))
			{
				Plugin.Logger.LogWarning((object)("Dev Tools Menu access blocked. " + reason));
			}
			else
			{
				OpenMenu();
			}
		}

		private void OpenMenu()
		{
			_menuOpen = true;
			UnlockCursor();
			DevToolsCatalogs.RefreshAll();
			Plugin.Logger.LogInfo((object)"Public host-only Dev Tools Menu opened.");
		}

		private void CloseMenu(string logMessage)
		{
			_menuOpen = false;
			RestoreCursor();
			Plugin.Logger.LogInfo((object)logMessage);
		}

		private bool CanContinueUsingMenu()
		{
			string reason;
			return DevToolsAccess.CanOpenPublicMenu(out reason);
		}

		private void UnlockCursor()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			_previousCursorLock = Cursor.lockState;
			_previousCursorVisible = Cursor.visible;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
		}

		private void RestoreCursor()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Cursor.lockState = _previousCursorLock;
			Cursor.visible = _previousCursorVisible;
		}

		private void OnGUI()
		{
			//IL_0017: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			if (_menuOpen)
			{
				_windowRect = GUI.Window(847216, _windowRect, WindowFunction.op_Implicit((Action<int>)DrawWindow), "Shift At Midnight Dev Tools Public v0.4");
			}
		}

		private void DrawWindow(int windowId)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				DrawHeader();
				DrawTabs();
				if (_selectedTab == 0)
				{
					DrawPublicTab();
				}
				else if (_selectedTab == 1)
				{
					DrawNpcTab();
				}
				else if (_selectedTab == 2)
				{
					DrawMonsterTab();
				}
				else
				{
					DrawItemTab();
				}
				if (GUI.Button(new Rect(20f, 675f, 610f, 28f), "Close Dev Tools"))
				{
					CloseMenu("Dev Tools Menu closed.");
				}
				GUI.DragWindow(new Rect(0f, 0f, 10000f, 25f));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while drawing Dev Tools menu:\n" + ex));
				_menuOpen = false;
				RestoreCursor();
			}
		}

		private void DrawHeader()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(new Rect(15f, 30f, 620f, 22f), "Access: " + DevToolsAccess.GetAccessStatusText() + " | NPCs: " + DevToolsCatalogs.Npcs.Count + " | Monsters: " + DevToolsCatalogs.Monsters.Count + " | Items: " + DevToolsCatalogs.Items.Count);
		}

		private void DrawTabs()
		{
			DrawTabButton(20f, "Public Tools", 0);
			DrawTabButton(172f, "NPC Browser", 1);
			DrawTabButton(324f, "Monster Browser", 2);
			DrawTabButton(476f, "Item Browser", 3);
		}

		private void DrawTabButton(float x, string label, int tab)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			string text = ((_selectedTab == tab) ? ("[ " + label + " ]") : label);
			if (GUI.Button(new Rect(x, 58f, 144f, 28f), text))
			{
				_selectedTab = tab;
			}
		}

		private void DrawPublicTab()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			float y = 110f;
			DrawSectionTitle(ref y, "PUBLIC RELEASE");
			GUI.Label(new Rect(20f, y, 610f, 45f), "Gameplay-changing actions are restricted to the host.\nThis experimental tool may affect progression or game events.");
			y += 55f;
			DrawSectionTitle(ref y, "LIMITED ECONOMY");
			GUI.Label(new Rect(20f, y, 610f, 42f), "Large economy cheats were removed from the public release.\nOnly small fixed bonuses are available.");
			y += 50f;
			if (GUI.Button(new Rect(20f, y, 300f, 32f), "Add $10"))
			{
				DevToolsActions.AddPublicMoney();
			}
			if (GUI.Button(new Rect(330f, y, 300f, 32f), "Add 10 Tokens"))
			{
				DevToolsActions.AddPublicTokens();
			}
			y += 50f;
			DrawSectionTitle(ref y, "DISABLED IN PUBLIC BUILD");
			GUI.Label(new Rect(20f, y, 610f, 150f), "• God Mode\n• Player speed modification\n• Infinite money\n• Infinite refreshes\n• Day skipping\n• Original developer cheat menu\n• Normal-price item purchases");
			y += 165f;
			DrawSectionTitle(ref y, "AVAILABLE BROWSERS");
			GUI.Label(new Rect(20f, y, 610f, 90f), "NPC Browser: spawn specific customers.\nMonster Browser: queue or spawn hunt enemies.\nItem Browser: order valid items for free.\nSpecial or broken purchase indexes remain blocked.");
		}

		private void DrawNpcTab()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			float num = 103f;
			GUI.Label(new Rect(20f, num, 60f, 24f), "Search:");
			string text = GUI.TextField(new Rect(80f, num, 360f, 24f), _npcSearch);
			if (text != _npcSearch)
			{
				_npcSearch = text;
				_npcPage = 0;
			}
			if (GUI.Button(new Rect(450f, num, 180f, 24f), "Refresh NPCs"))
			{
				DevToolsCatalogs.RefreshNpcs();
				_npcPage = 0;
			}
			num += 29f;
			GUI.Label(new Rect(20f, num, 610f, 22f), DevToolsCatalogs.NpcStatus);
			num += 27f;
			List<int> list = BuildNpcMatches();
			ClampPage(ref _npcPage, list.Count);
			int num2 = _npcPage * 9;
			for (int i = 0; i < 9; i++)
			{
				int num3 = num2 + i;
				if (num3 >= list.Count)
				{
					break;
				}
				NpcCatalogEntry npcCatalogEntry = DevToolsCatalogs.Npcs[list[num3]];
				string text2 = npcCatalogEntry.Id + " | " + npcCatalogEntry.PrefabName;
				if (string.Equals(npcCatalogEntry.Id, _selectedNpcId, StringComparison.OrdinalIgnoreCase))
				{
					text2 = "> " + text2;
				}
				if (GUI.Button(new Rect(20f, num, 610f, 24f), Truncate(text2, 90)))
				{
					_selectedNpcId = npcCatalogEntry.Id;
				}
				num += 26f;
			}
			num = 401f;
			DrawPager(ref _npcPage, list.Count, num);
			NpcCatalogEntry npcCatalogEntry2 = DevToolsCatalogs.FindNpc(_selectedNpcId);
			if (npcCatalogEntry2 == null && list.Count > 0)
			{
				npcCatalogEntry2 = DevToolsCatalogs.Npcs[list[0]];
				_selectedNpcId = npcCatalogEntry2.Id;
			}
			num = 438f;
			DrawSectionTitle(ref num, "SELECTED NPC");
			if (npcCatalogEntry2 == null)
			{
				GUI.Label(new Rect(20f, num, 610f, 22f), "No NPC was found or selected.");
				return;
			}
			DrawInfoLine(ref num, "ID", npcCatalogEntry2.Id);
			DrawInfoLine(ref num, "Prefab", npcCatalogEntry2.PrefabName);
			DrawInfoLine(ref num, "Doppelganger", npcCatalogEntry2.IsDoppelganger ? "Yes" : "No");
			DrawInfoLine(ref num, "Difficulty / Entertainment", npcCatalogEntry2.Difficulty + " / " + npcCatalogEntry2.Entertainment);
			DrawInfoLine(ref num, "Day range", npcCatalogEntry2.MinimumDay + " to " + npcCatalogEntry2.MaximumDay);
			DrawInfoLine(ref num, "Requirements", "Alive: " + npcCatalogEntry2.MustBeAliveCount + " | Previous: " + npcCatalogEntry2.MustHaveSpawnedCount);
			if (GUI.Button(new Rect(20f, num + 4f, 300f, 28f), "Spawn Selected NPC"))
			{
				DevToolsActions.SpawnNpc(npcCatalogEntry2.Id);
			}
			if (GUI.Button(new Rect(330f, num + 4f, 300f, 28f), "Dump NPC List To Log"))
			{
				DevToolsCatalogs.DumpNpcsToLog();
			}
			num += 38f;
			if (GUI.Button(new Rect(20f, num, 300f, 28f), "Spawn Random Browsing Customer"))
			{
				DevToolsActions.SpawnRandomBrowsingCustomer();
			}
			if (GUI.Button(new Rect(330f, num, 300f, 28f), "Spawn Random Nuisance Customer"))
			{
				DevToolsActions.SpawnRandomNuisanceCustomer();
			}
		}

		private void DrawMonsterTab()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			float num = 103f;
			GUI.Label(new Rect(20f, num, 60f, 24f), "Search:");
			string text = GUI.TextField(new Rect(80f, num, 360f, 24f), _monsterSearch);
			if (text != _monsterSearch)
			{
				_monsterSearch = text;
				_monsterPage = 0;
			}
			if (GUI.Button(new Rect(450f, num, 180f, 24f), "Refresh Monsters"))
			{
				DevToolsCatalogs.RefreshMonsters();
				_monsterPage = 0;
			}
			num += 29f;
			GUI.Label(new Rect(20f, num, 610f, 22f), DevToolsCatalogs.MonsterStatus);
			num += 27f;
			List<int> list = BuildMonsterMatches();
			ClampPage(ref _monsterPage, list.Count);
			int num2 = _monsterPage * 9;
			for (int i = 0; i < 9; i++)
			{
				int num3 = num2 + i;
				if (num3 >= list.Count)
				{
					break;
				}
				MonsterCatalogEntry monsterCatalogEntry = DevToolsCatalogs.Monsters[list[num3]];
				string text2 = "[" + monsterCatalogEntry.Index + "] " + monsterCatalogEntry.Name;
				if (monsterCatalogEntry.Index == _selectedMonsterIndex)
				{
					text2 = "> " + text2;
				}
				if (GUI.Button(new Rect(20f, num, 610f, 24f), Truncate(text2, 95)))
				{
					_selectedMonsterIndex = monsterCatalogEntry.Index;
				}
				num += 26f;
			}
			num = 401f;
			DrawPager(ref _monsterPage, list.Count, num);
			MonsterCatalogEntry monsterCatalogEntry2 = DevToolsCatalogs.FindMonster(_selectedMonsterIndex);
			if (monsterCatalogEntry2 == null && list.Count > 0)
			{
				monsterCatalogEntry2 = DevToolsCatalogs.Monsters[list[0]];
				_selectedMonsterIndex = monsterCatalogEntry2.Index;
			}
			num = 438f;
			DrawSectionTitle(ref num, "SELECTED MONSTER");
			if (monsterCatalogEntry2 == null)
			{
				GUI.Label(new Rect(20f, num, 610f, 22f), "HuntManager or monsterObjs is unavailable.");
				return;
			}
			DrawInfoLine(ref num, "Index", monsterCatalogEntry2.Index.ToString());
			DrawInfoLine(ref num, "Prefab", monsterCatalogEntry2.Name);
			DrawInfoLine(ref num, "Multiplayer Difficulty", FormatUnknownInt(monsterCatalogEntry2.MultiplayerDifficulty));
			DrawInfoLine(ref num, "Singleplayer Difficulty", FormatUnknownInt(monsterCatalogEntry2.SingleplayerDifficulty));
			if (GUI.Button(new Rect(20f, num + 5f, 195f, 29f), "Queue Monster"))
			{
				DevToolsActions.QueueMonster(monsterCatalogEntry2.Index);
			}
			if (GUI.Button(new Rect(225f, num + 5f, 195f, 29f), "Spawn Now"))
			{
				DevToolsActions.SpawnMonsterNow(monsterCatalogEntry2.Index);
			}
			if (GUI.Button(new Rect(430f, num + 5f, 200f, 29f), "Start Full Hunt"))
			{
				DevToolsActions.StartHunt();
			}
			num += 44f;
			if (GUI.Button(new Rect(20f, num, 610f, 28f), "Dump Monster List To Log"))
			{
				DevToolsCatalogs.DumpMonstersToLog();
			}
		}

		private void DrawItemTab()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: 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)
			float num = 103f;
			GUI.Label(new Rect(20f, num, 60f, 24f), "Search:");
			string text = GUI.TextField(new Rect(80f, num, 360f, 24f), _itemSearch);
			if (text != _itemSearch)
			{
				_itemSearch = text;
				_itemPage = 0;
			}
			if (GUI.Button(new Rect(450f, num, 180f, 24f), "Refresh Items"))
			{
				DevToolsCatalogs.RefreshItems();
				_itemPage = 0;
				_selectedItemIndex = -1;
			}
			num += 29f;
			GUI.Label(new Rect(20f, num, 610f, 22f), DevToolsCatalogs.ItemStatus);
			num += 27f;
			List<int> list = BuildItemMatches();
			ClampPage(ref _itemPage, list.Count);
			int num2 = _itemPage * 9;
			for (int i = 0; i < 9; i++)
			{
				int num3 = num2 + i;
				if (num3 >= list.Count)
				{
					break;
				}
				ItemCatalogEntry itemCatalogEntry = DevToolsCatalogs.Items[list[num3]];
				string text2 = (itemCatalogEntry.IsSpecialOrBroken ? " | SPECIAL / BROKEN" : " | FREE");
				string text3 = "[" + itemCatalogEntry.Index + "] " + itemCatalogEntry.Name + text2;
				if (itemCatalogEntry.Index == _selectedItemIndex)
				{
					text3 = "> " + text3;
				}
				if (GUI.Button(new Rect(20f, num, 610f, 24f), Truncate(text3, 95)))
				{
					_selectedItemIndex = itemCatalogEntry.Index;
				}
				num += 26f;
			}
			num = 401f;
			DrawPager(ref _itemPage, list.Count, num);
			ItemCatalogEntry itemCatalogEntry2 = DevToolsCatalogs.FindItem(_selectedItemIndex);
			if (itemCatalogEntry2 == null && list.Count > 0)
			{
				itemCatalogEntry2 = DevToolsCatalogs.Items[list[0]];
				_selectedItemIndex = itemCatalogEntry2.Index;
			}
			num = 438f;
			DrawSectionTitle(ref num, "SELECTED ITEM");
			if (itemCatalogEntry2 == null)
			{
				GUI.Label(new Rect(20f, num, 610f, 22f), "No purchase item was found.");
				return;
			}
			DrawInfoLine(ref num, "Purchase index", itemCatalogEntry2.Index.ToString());
			DrawInfoLine(ref num, "Purchase object", itemCatalogEntry2.PurchaseObjectName);
			DrawInfoLine(ref num, "Status", itemCatalogEntry2.IsSpecialOrBroken ? "Special / broken - blocked" : "Available");
			DrawInfoLine(ref num, "Public price", itemCatalogEntry2.IsSpecialOrBroken ? "Blocked" : "Free");
			if (itemCatalogEntry2.IsAvailable)
			{
				if (GUI.Button(new Rect(20f, num + 6f, 400f, 30f), "Order Selected Item For Free"))
				{
					DevToolsActions.OrderItemFree(itemCatalogEntry2);
				}
			}
			else
			{
				GUI.Label(new Rect(20f, num + 10f, 400f, 24f), "This purchase index is blocked.");
			}
			if (GUI.Button(new Rect(430f, num + 6f, 200f, 30f), "Dump Items To Log"))
			{
				DevToolsCatalogs.DumpItemsToLog();
			}
			num += 48f;
			GUI.Label(new Rect(20f, num, 610f, 55f), "Normal-price purchases were removed from the public build.\nOnly valid non-null purchaseObjects may be ordered.");
		}

		private List<int> BuildNpcMatches()
		{
			List<int> list = new List<int>();
			for (int i = 0; i < DevToolsCatalogs.Npcs.Count; i++)
			{
				NpcCatalogEntry npcCatalogEntry = DevToolsCatalogs.Npcs[i];
				if (MatchesSearch(npcCatalogEntry.Id, _npcSearch) || MatchesSearch(npcCatalogEntry.PrefabName, _npcSearch))
				{
					list.Add(i);
				}
			}
			return list;
		}

		private List<int> BuildMonsterMatches()
		{
			List<int> list = new List<int>();
			for (int i = 0; i < DevToolsCatalogs.Monsters.Count; i++)
			{
				MonsterCatalogEntry monsterCatalogEntry = DevToolsCatalogs.Monsters[i];
				if (MatchesSearch(monsterCatalogEntry.Name, _monsterSearch) || MatchesSearch(monsterCatalogEntry.Index.ToString(), _monsterSearch))
				{
					list.Add(i);
				}
			}
			return list;
		}

		private List<int> BuildItemMatches()
		{
			List<int> list = new List<int>();
			for (int i = 0; i < DevToolsCatalogs.Items.Count; i++)
			{
				ItemCatalogEntry itemCatalogEntry = DevToolsCatalogs.Items[i];
				if (MatchesSearch(itemCatalogEntry.Name, _itemSearch) || MatchesSearch(itemCatalogEntry.PurchaseObjectName, _itemSearch) || MatchesSearch(itemCatalogEntry.Index.ToString(), _itemSearch))
				{
					list.Add(i);
				}
			}
			return list;
		}

		private bool MatchesSearch(string value, string search)
		{
			if (string.IsNullOrWhiteSpace(search))
			{
				return true;
			}
			if (string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			return value.IndexOf(search.Trim(), StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private void DrawPager(ref int page, int itemCount, float y)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			ClampPage(ref page, itemCount);
			int num = Math.Max(1, (itemCount + 9 - 1) / 9);
			if (GUI.Button(new Rect(20f, y, 150f, 26f), "Previous"))
			{
				page--;
				ClampPage(ref page, itemCount);
			}
			GUI.Label(new Rect(180f, y + 3f, 290f, 22f), "Page " + (page + 1) + " / " + num + " | Results: " + itemCount);
			if (GUI.Button(new Rect(480f, y, 150f, 26f), "Next"))
			{
				page++;
				ClampPage(ref page, itemCount);
			}
		}

		private void ClampPage(ref int page, int itemCount)
		{
			int num = Math.Max(1, (itemCount + 9 - 1) / 9);
			if (page < 0)
			{
				page = 0;
			}
			if (page >= num)
			{
				page = num - 1;
			}
		}

		private void DrawInfoLine(ref float y, string label, string value)
		{
			//IL_0012: 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)
			GUI.Label(new Rect(20f, y, 170f, 21f), label + ":");
			GUI.Label(new Rect(190f, y, 440f, 21f), Truncate(value, 75));
			y += 21f;
		}

		private void DrawSectionTitle(ref float y, string title)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(new Rect(15f, y, 620f, 22f), "---------------- " + title + " ----------------");
			y += 25f;
		}

		private string Truncate(string value, int maximumLength)
		{
			if (string.IsNullOrEmpty(value))
			{
				return "";
			}
			if (value.Length <= maximumLength)
			{
				return value;
			}
			return value.Substring(0, maximumLength - 3) + "...";
		}

		private string FormatUnknownInt(int value)
		{
			return (value < 0) ? "Unknown" : value.ToString();
		}
	}
	internal static class DevToolsState
	{
		internal static bool GodMode;

		internal static bool InfiniteMoney;

		internal static bool InfiniteRefreshes;

		internal const int InfiniteMoneyGrant = 1000000;

		internal const int InfiniteRefreshGrant = 9999;

		internal const int DefaultMoneyAmount = 1000;

		internal const int DefaultTokenAmount = 100;

		internal const int DefaultRefreshAmount = 10;

		internal const float DefaultPlayerSpeed = 5f;
	}
	internal static class ItemPurchaseRuntimeDebug
	{
		private static int _traceId;

		private static int _activeTraceId;

		private static float _lastScanTime;

		private static string _lastScanName = "(none)";

		private static int _lastScanIndex = -1;

		private static int _lastScanCost;

		internal static void LogScanInteraction(ScanItem scanItem, string stage)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Expected O, but got Unknown
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Expected O, but got Unknown
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Expected O, but got Unknown
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Expected O, but got Unknown
			try
			{
				if ((Object)(object)scanItem == (Object)null)
				{
					Plugin.Logger.LogWarning((object)("[ITEM TRACE] " + stage + " recebeu ScanItem nulo."));
					return;
				}
				_traceId++;
				_activeTraceId = _traceId;
				_lastScanTime = Time.unscaledTime;
				_lastScanName = GetComponentName((Component)(object)scanItem);
				_lastScanIndex = scanItem.objectIndex;
				_lastScanCost = scanItem.cost;
				Plugin.Logger.LogInfo((object)"");
				Plugin.Logger.LogInfo((object)"====================================================");
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(21, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ITEM RUNTIME TRACE #");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_activeTraceId, "000");
				}
				logger.LogInfo(val);
				Plugin.Logger.LogInfo((object)"====================================================");
				ManualLogSource logger2 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Stage        : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(stage);
				}
				logger2.LogInfo(val);
				ManualLogSource logger3 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Object name  : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_lastScanName);
				}
				logger3.LogInfo(val);
				ManualLogSource logger4 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Object index : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_lastScanIndex);
				}
				logger4.LogInfo(val);
				ManualLogSource logger5 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Cost         : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_lastScanCost);
				}
				logger5.LogInfo(val);
				ManualLogSource logger6 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Instance ID  : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(GetInstanceId((Object)(object)scanItem));
				}
				logger6.LogInfo(val);
				ManualLogSource logger7 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Active       : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(GetActiveState((Component)(object)scanItem));
				}
				logger7.LogInfo(val);
				ManualLogSource logger8 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Scene        : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(GetSceneName((Component)(object)scanItem));
				}
				logger8.LogInfo(val);
				ManualLogSource logger9 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Position     : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(GetPosition((Component)(object)scanItem));
				}
				logger9.LogInfo(val);
				LogPurchaseObjectLookup(_lastScanIndex, "ScanItem lookup");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Erro no runtime debug do ScanItem:\n" + ex));
			}
		}

		internal static void LogPurchaseCall(int index, float cost, string stage)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected O, but got Unknown
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			try
			{
				int currentTraceId = GetCurrentTraceId();
				Plugin.Logger.LogInfo((object)"");
				Plugin.Logger.LogInfo((object)"----------------------------------------------------");
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(21, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ITEM PURCHASE CALL #");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(currentTraceId, "000");
				}
				logger.LogInfo(val);
				Plugin.Logger.LogInfo((object)"----------------------------------------------------");
				ManualLogSource logger2 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Stage        : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(stage);
				}
				logger2.LogInfo(val);
				ManualLogSource logger3 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Index        : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(index);
				}
				logger3.LogInfo(val);
				ManualLogSource logger4 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Cost         : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(cost);
				}
				logger4.LogInfo(val);
				ManualLogSource logger5 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Last scan    : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_lastScanName);
				}
				logger5.LogInfo(val);
				ManualLogSource logger6 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Scan index   : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_lastScanIndex);
				}
				logger6.LogInfo(val);
				ManualLogSource logger7 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Scan cost    : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_lastScanCost);
				}
				logger7.LogInfo(val);
				ManualLogSource logger8 = Plugin.Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(16, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Age          : ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(GetTraceAge(), "0.000");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("s");
				}
				logger8.LogInfo(val);
				if (index != _lastScanIndex && GetTraceAge() <= 2f)
				{
					Plugin.Logger.LogWarning((object)"INDEX CHANGED ENTRE SCANITEM E PURCHASE!");
				}
				LogPurchaseObjectLookup(index, stage);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Erro no runtime debug da compra:\n" + ex));
			}
		}

		internal static void LogHealthUpgrade(float hp)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			Plugin.Logger.LogWarning((object)"");
			Plugin.Logger.LogWarning((object)"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
			Plugin.Logger.LogWarning((object)" PLAYER MAX HEALTH PURCHASE DETECTED");
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(12, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Trace ID : #");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(GetCurrentTraceId(), "000");
			}
			logger.LogWarning(val);
			ManualLogSource logger2 = Plugin.Logger;
			val = new BepInExWarningLogInterpolatedStringHandler(11, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("HP value : ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(hp);
			}
			logger2.LogWarning(val);
			ManualLogSource logger3 = Plugin.Logger;
			val = new BepInExWarningLogInterpolatedStringHandler(11, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Last item: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_lastScanName);
			}
			logger3.LogWarning(val);
			ManualLogSource logger4 = Plugin.Logger;
			val = new BepInExWarningLogInterpolatedStringHandler(11, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Index    : ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_lastScanIndex);
			}
			logger4.LogWarning(val);
			Plugin.Logger.LogWarning((object)"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
		}

		internal static void LogTruckPurchase(TruckManager truck)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			try
			{
				if (!((Object)(object)truck == (Object)null))
				{
					int purchaseIndex = truck.purchaseIndex;
					string deliveryItemName = GetDeliveryItemName(truck, purchaseIndex);
					Plugin.Logger.LogInfo((object)"");
					Plugin.Logger.LogInfo((object)"---------------- TRUCK DELIVERY ----------------");
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(18, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Trace ID       : #");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(GetCurrentTraceId(), "000");
					}
					logger.LogInfo(val);
					ManualLogSource logger2 = Plugin.Logger;
					val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("purchaseIndex  : ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(purchaseIndex);
					}
					logger2.LogInfo(val);
					ManualLogSource logger3 = Plugin.Logger;
					val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Delivery item  : ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(deliveryItemName);
					}
					logger3.LogInfo(val);
					ManualLogSource logger4 = Plugin.Logger;
					val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Last scan item : ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_lastScanName);
					}
					logger4.LogInfo(val);
					ManualLogSource logger5 = Plugin.Logger;
					val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Last scan index: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_lastScanIndex);
					}
					logger5.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Erro ao registrar entrega do caminhão: " + ex.Message));
			}
		}

		private static void LogPurchaseObjectLookup(int index, string source)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			PurchaseManager instance = PurchaseManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				Plugin.Logger.LogWarning((object)(source + ": PurchaseManager.Instance está nulo."));
				return;
			}
			if (instance.purchaseObjects == null)
			{
				Plugin.Logger.LogWarning((object)(source + ": purchaseObjects está nulo."));
				return;
			}
			Plugin.Logger.LogInfo((object)("purchaseObjects.Length: " + ((Il2CppArrayBase<GameObject>)(object)instance.purchaseObjects).Length));
			if (index < 0 || index >= ((Il2CppArrayBase<GameObject>)(object)instance.purchaseObjects).Length)
			{
				Plugin.Logger.LogWarning((object)(source + ": índice fora de purchaseObjects."));
				return;
			}
			GameObject val = ((Il2CppArrayBase<GameObject>)(object)instance.purchaseObjects)[index];
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(43, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("purchaseObjects[");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(index);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] = NULL / SPECIAL PURCHASE");
				}
				logger.LogWarning(val2);
			}
			else
			{
				Plugin.Logger.LogInfo((object)($"purchaseObjects[{index}] = " + ((Object)val).name));
			}
		}

		private static int GetCurrentTraceId()
		{
			if (Time.unscaledTime - _lastScanTime <= 2f)
			{
				return _activeTraceId;
			}
			_traceId++;
			_activeTraceId = _traceId;
			return _activeTraceId;
		}

		private static float GetTraceAge()
		{
			if (_lastScanTime <= 0f)
			{
				return -1f;
			}
			return Time.unscaledTime - _lastScanTime;
		}

		private static string GetComponentName(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return "(null)";
			}
			try
			{
				if ((Object)(object)component.gameObject != (Object)null)
				{
					return ((Object)component.gameObject).name;
				}
				return ((Object)component).name;
			}
			catch
			{
				return "(unknown)";
			}
		}

		private static int GetInstanceId(Object obj)
		{
			if (obj == (Object)null)
			{
				return 0;
			}
			try
			{
				return obj.GetInstanceID();
			}
			catch
			{
				return 0;
			}
		}

		private static bool GetActiveState(Component component)
		{
			if ((Object)(object)component == (Object)null || (Object)(object)component.gameObject == (Object)null)
			{
				return false;
			}
			try
			{
				return component.gameObject.activeInHierarchy;
			}
			catch
			{
				return false;
			}
		}

		private static string GetSceneName(Component component)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)component == (Object)null || (Object)(object)component.gameObject == (Object)null)
			{
				return "(unknown)";
			}
			try
			{
				Scene scene = component.gameObject.scene;
				string name = ((Scene)(ref scene)).name;
				return string.IsNullOrWhiteSpace(name) ? "(asset or prefab)" : name;
			}
			catch
			{
				return "(unknown)";
			}
		}

		private static string GetPosition(Component component)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)component == (Object)null || (Object)(object)component.transform == (Object)null)
			{
				return "(unknown)";
			}
			try
			{
				Vector3 position = component.transform.position;
				return $"({position.x:0.00}, {position.y:0.00}, {position.z:0.00})";
			}
			catch
			{
				return "(unknown)";
			}
		}

		private static string GetDeliveryItemName(TruckManager truck, int index)
		{
			if ((Object)(object)truck == (Object)null || truck.deliveryItems == null)
			{
				return "(deliveryItems unavailable)";
			}
			if (index < 0 || index >= ((Il2CppArrayBase<GameObject>)(object)truck.deliveryItems).Length)
			{
				return "(index outside deliveryItems)";
			}
			GameObject val = ((Il2CppArrayBase<GameObject>)(object)truck.deliveryItems)[index];
			if ((Object)(object)val == (Object)null)
			{
				return "(null delivery item)";
			}
			try
			{
				return ((Object)val).name;
			}
			catch
			{
				return "(unknown delivery item)";
			}
		}
	}
	[HarmonyPatch(typeof(ScanItem), "Interact", new Type[] { typeof(PlayerManager) })]
	internal static class ScanItemInteractDebugPatch
	{
		private static void Prefix(ScanItem __instance)
		{
			ItemPurchaseRuntimeDebug.LogScanInteraction(__instance, "ScanItem.Interact");
		}
	}
	[HarmonyPatch(typeof(ScanItem), "Rpc_CMD_Interact")]
	internal static class ScanItemCommandDebugPatch
	{
		private static void Prefix(ScanItem __instance)
		{
			ItemPurchaseRuntimeDebug.LogScanInteraction(__instance, "ScanItem.Rpc_CMD_Interact");
		}
	}
	[HarmonyPatch(typeof(PurchaseManager), "PurchaseItem", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	internal static class PurchaseItemDebugPatch
	{
		private static void Prefix(int index, float cost)
		{
			ItemPurchaseRuntimeDebug.LogPurchaseCall(index, cost, "PurchaseManager.PurchaseItem");
		}
	}
	[HarmonyPatch(typeof(PurchaseManager), "Rpc_CMD_PurchaseObj", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	internal static class PurchaseCommandDebugPatch
	{
		private static void Prefix(int index, float cost)
		{
			ItemPurchaseRuntimeDebug.LogPurchaseCall(index, cost, "PurchaseManager.Rpc_CMD_PurchaseObj");
		}
	}
	[HarmonyPatch(typeof(PurchaseManager), "Rpc_PurchaseObj", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	internal static class PurchaseResultDebugPatch
	{
		private static void Prefix(int index, float cost)
		{
			ItemPurchaseRuntimeDebug.LogPurchaseCall(index, cost, "PurchaseManager.Rpc_PurchaseObj");
		}
	}
	[HarmonyPatch(typeof(PurchaseManager), "Rpc_BuyPlayerMaxHealthRpc")]
	internal static class PlayerHealthPurchaseDebugPatch
	{
		private static void Prefix(float hp)
		{
			ItemPurchaseRuntimeDebug.LogHealthUpgrade(hp);
		}
	}
	[HarmonyPatch(typeof(TruckManager), "DropPurchase")]
	internal static class TruckDropPurchaseDebugPatch
	{
		private static void Prefix(TruckManager __instance)
		{
			ItemPurchaseRuntimeDebug.LogTruckPurchase(__instance);
		}
	}
	[BepInPlugin("dev.fuzs.shiftatmidnight.devtools", "Shift At Midnight Dev Tools Public", "0.4.0")]
	public sealed class Plugin : BasePlugin
	{
		public const string PluginGuid = "dev.fuzs.shiftatmidnight.devtools";

		public const string PluginName = "Shift At Midnight Dev Tools Public";

		public const string PluginVersion = "0.4.0";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<KeyCode> MenuKey;

		private Harmony _harmony;

		public override void Load()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BasePlugin)this).Log;
			try
			{
				MenuKey = ((BasePlugin)this).Config.Bind<KeyCode>("General", "MenuKey", (KeyCode)286, "Key used to open and close the host-only Dev Tools menu.");
				_harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "dev.fuzs.shiftatmidnight.devtools");
				((BasePlugin)this).AddComponent<DevToolsMenu>();
				ManualLogSource logger = Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(10, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Shift At Midnight Dev Tools Public");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.4.0");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded.");
				}
				logger.LogInfo(val);
				ManualLogSource logger2 = Logger;
				val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Press ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<KeyCode>(MenuKey.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" during a match to open the menu.");
				}
				logger2.LogInfo(val);
				Logger.LogInfo((object)"Public release restrictions enabled.");
				Logger.LogInfo((object)"The menu is available only to the host while in the Game scene.");
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error while loading Dev Tools:\n" + ex));
			}
		}
	}
}