Decompiled source of LuckyTest v1.1.3

LuckyTest.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using OpenShot.Core;
using OpenShot.UI;
using Shooterlatro.DebugTools;
using Shooterlatro.Game;
using Shooterlatro.Gameplay.RunSetup;
using Shooterlatro.Score;
using Shooterlatro.Shop;
using Shooterlatro.Upgrades;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("LuckyTest")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Sandbox build tester for Lucky Shot. Pick holos/bullets/charms/drinks, then jump into endless. Configure via OpenShot MODS hub.")]
[assembly: AssemblyFileVersion("1.1.3.0")]
[assembly: AssemblyInformationalVersion("1.1.3+4135dd1490a61fe647f2a0e54287f36471f5cf7f")]
[assembly: AssemblyProduct("LuckyTest")]
[assembly: AssemblyTitle("LuckyTest")]
[assembly: AssemblyVersion("1.1.3.0")]
[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 LuckyTest
{
	internal sealed class CatalogEntry
	{
		public string Id;

		public string Label;

		public Object Asset;
	}
	internal static class CatalogCache
	{
		public static List<CatalogEntry> Holos { get; private set; } = new List<CatalogEntry>();

		public static List<CatalogEntry> Bullets { get; private set; } = new List<CatalogEntry>();

		public static List<CatalogEntry> Charms { get; private set; } = new List<CatalogEntry>();

		public static List<CatalogEntry> Drinks { get; private set; } = new List<CatalogEntry>();

		public static void Refresh()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0020: Expected O, but got Unknown
			UnityDeveloperConsoleRuntime val = new UnityDeveloperConsoleRuntime();
			Holos = BuildHolos(val);
			Bullets = BuildBullets(val);
			Charms = BuildCharms(val);
			Drinks = BuildDrinks();
		}

		private static List<CatalogEntry> BuildHolos(UnityDeveloperConsoleRuntime runtime)
		{
			List<CatalogEntry> list = new List<CatalogEntry>();
			HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			IReadOnlyList<HoloItemData> readOnlyList = null;
			try
			{
				readOnlyList = runtime.GetHolos();
			}
			catch
			{
			}
			if (readOnlyList != null)
			{
				foreach (HoloItemData item in readOnlyList)
				{
					TryAddHolo(list, seen, runtime, item);
				}
			}
			HoloItemData[] array = Resources.FindObjectsOfTypeAll<HoloItemData>();
			foreach (HoloItemData holo in array)
			{
				TryAddHolo(list, seen, runtime, holo);
			}
			return list.OrderBy<CatalogEntry, string>((CatalogEntry e) => e.Id, StringComparer.OrdinalIgnoreCase).ToList();
		}

		private static void TryAddHolo(List<CatalogEntry> list, HashSet<string> seen, UnityDeveloperConsoleRuntime runtime, HoloItemData holo)
		{
			if ((Object)(object)holo == (Object)null)
			{
				return;
			}
			string text = ((!string.IsNullOrEmpty(holo.catalogId)) ? holo.catalogId : ((Object)holo).name);
			if (!string.IsNullOrEmpty(text) && seen.Add(text))
			{
				string text2 = null;
				try
				{
					text2 = runtime.GetHoloTitle(holo);
				}
				catch
				{
				}
				if (string.IsNullOrWhiteSpace(text2))
				{
					text2 = ((Object)holo).name;
				}
				list.Add(new CatalogEntry
				{
					Id = text,
					Label = text + "  " + text2,
					Asset = (Object)(object)holo
				});
			}
		}

		private static List<CatalogEntry> BuildBullets(UnityDeveloperConsoleRuntime runtime)
		{
			List<CatalogEntry> list = new List<CatalogEntry>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			BulletItemData[] array = Resources.FindObjectsOfTypeAll<BulletItemData>();
			foreach (BulletItemData val in array)
			{
				if (!((Object)(object)val == (Object)null) && !val.isNormalBullet)
				{
					string name = ((Object)val).name;
					if (!string.IsNullOrEmpty(name) && hashSet.Add(name))
					{
						list.Add(new CatalogEntry
						{
							Id = name,
							Label = name,
							Asset = (Object)(object)val
						});
					}
				}
			}
			return list.OrderBy<CatalogEntry, string>((CatalogEntry e) => e.Label, StringComparer.OrdinalIgnoreCase).ToList();
		}

		private static List<CatalogEntry> BuildCharms(UnityDeveloperConsoleRuntime runtime)
		{
			List<CatalogEntry> list = new List<CatalogEntry>();
			HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			IReadOnlyList<CharmItemData> readOnlyList = null;
			try
			{
				readOnlyList = runtime.GetTrinkets();
			}
			catch
			{
			}
			if (readOnlyList != null)
			{
				foreach (CharmItemData item in readOnlyList)
				{
					TryAddCharm(list, seen, runtime, item);
				}
			}
			CharmItemData[] array = Resources.FindObjectsOfTypeAll<CharmItemData>();
			foreach (CharmItemData charm in array)
			{
				TryAddCharm(list, seen, runtime, charm);
			}
			return list.OrderBy<CatalogEntry, string>((CatalogEntry e) => e.Label, StringComparer.OrdinalIgnoreCase).ToList();
		}

		private static void TryAddCharm(List<CatalogEntry> list, HashSet<string> seen, UnityDeveloperConsoleRuntime runtime, CharmItemData charm)
		{
			if ((Object)(object)charm == (Object)null)
			{
				return;
			}
			string name = ((Object)charm).name;
			if (!string.IsNullOrEmpty(name) && seen.Add(name))
			{
				string text = null;
				try
				{
					text = runtime.GetTrinketTitle(charm);
				}
				catch
				{
				}
				if (string.IsNullOrWhiteSpace(text))
				{
					text = name;
				}
				list.Add(new CatalogEntry
				{
					Id = name,
					Label = text,
					Asset = (Object)(object)charm
				});
			}
		}

		private static List<CatalogEntry> BuildDrinks()
		{
			List<CatalogEntry> list = new List<CatalogEntry>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			EnergyDrinkItemData[] array = Resources.FindObjectsOfTypeAll<EnergyDrinkItemData>();
			foreach (EnergyDrinkItemData val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string name = ((Object)val).name;
					if (!string.IsNullOrEmpty(name) && hashSet.Add(name))
					{
						list.Add(new CatalogEntry
						{
							Id = name,
							Label = name,
							Asset = (Object)(object)val
						});
					}
				}
			}
			return list.OrderBy<CatalogEntry, string>((CatalogEntry e) => e.Label, StringComparer.OrdinalIgnoreCase).ToList();
		}
	}
	internal static class LoadoutApplier
	{
		public static bool IsLaunching { get; private set; }

		public static void BeginLaunch(MonoBehaviour host, HashSet<string> holoIds, HashSet<string> bulletNames, HashSet<string> charmNames, HashSet<string> drinkNames)
		{
			if (!((Object)(object)host == (Object)null) && !IsLaunching)
			{
				host.StartCoroutine(LaunchRoutine(holoIds, bulletNames, charmNames, drinkNames));
			}
		}

		private static IEnumerator LaunchRoutine(HashSet<string> holoIds, HashSet<string> bulletNames, HashSet<string> charmNames, HashSet<string> drinkNames)
		{
			IsLaunching = true;
			UnityDeveloperConsoleRuntime runtime = new UnityDeveloperConsoleRuntime();
			try
			{
				PersistSelection(holoIds, bulletNames, charmNames, drinkNames);
				GameManager gm = GameManager.Instance;
				if ((Object)(object)gm == (Object)null)
				{
					LuckyTestPlugin.Log.LogError((object)"[LuckyTest] GameManager missing.");
					yield break;
				}
				if ((int)gm.Phase == 7 || (int)gm.Phase == 8)
				{
					if ((int)gm.Phase == 7)
					{
						gm.ShowRunSetup();
					}
					yield return null;
					yield return null;
					RunSetupSelectionManager instance = RunSetupSelectionManager.Instance;
					bool flag = false;
					if ((Object)(object)instance != (Object)null)
					{
						flag = instance.TryCommitAndStartRun();
					}
					if (!flag)
					{
						gm.StartGameFromRunSetup();
					}
					float wait = 20f;
					while (wait > 0f)
					{
						gm = GameManager.Instance;
						if ((Object)(object)gm != (Object)null && ((int)gm.Phase == 3 || (int)gm.Phase == 5 || (int)gm.Phase == 1 || (int)gm.Phase == 0 || (int)gm.Phase == 2))
						{
							break;
						}
						wait -= Time.unscaledDeltaTime;
						yield return null;
					}
					if (wait <= 0f)
					{
						LuckyTestPlugin.Log.LogWarning((object)"[LuckyTest] Timed out waiting for run start; applying loadout anyway.");
					}
				}
				yield return null;
				int num = 0;
				int num2 = 0;
				string text = default(string);
				runtime.TryExpandHoloSlots(Mathf.Max(0, LuckyTestPlugin.ExtraHoloSlots.Value), ref num, ref num2, ref text);
				HoloItemManager instance2 = HoloItemManager.Instance;
				if ((Object)(object)instance2 != (Object)null)
				{
					instance2.ClearAllEquipped();
					AccessTools.Method(typeof(HoloItemManager), "ClearAllGrantedNonPhysical", (Type[])null, (Type[])null)?.Invoke(instance2, null);
				}
				int equipped = 0;
				foreach (string item in holoIds.OrderBy<string, string>((string s) => s, StringComparer.OrdinalIgnoreCase))
				{
					HoloItemData val = ResolveHolo(runtime, item);
					if ((Object)(object)val == (Object)null)
					{
						LuckyTestPlugin.Log.LogWarning((object)("[LuckyTest] Holo not found: " + item));
					}
					else if (runtime.TryEquipHolo(val, ref text))
					{
						equipped++;
					}
					else
					{
						LuckyTestPlugin.Log.LogWarning((object)("[LuckyTest] Equip failed " + item + ": " + text));
					}
				}
				int bulletsAdded = 0;
				int num3 = Mathf.Max(1, LuckyTestPlugin.DefaultBulletAmount.Value);
				foreach (string bulletName in bulletNames)
				{
					BulletItemData val2 = runtime.FindBullet(bulletName) ?? FindBulletByAssetName(bulletName);
					if ((Object)(object)val2 == (Object)null)
					{
						LuckyTestPlugin.Log.LogWarning((object)("[LuckyTest] Bullet not found: " + bulletName));
					}
					else
					{
						bulletsAdded += runtime.AddBullets(val2, num3);
					}
				}
				int charms = 0;
				foreach (string charmName in charmNames)
				{
					CharmItemData val3 = runtime.FindTrinket(charmName) ?? FindCharmByAssetName(charmName);
					if ((Object)(object)val3 == (Object)null)
					{
						LuckyTestPlugin.Log.LogWarning((object)("[LuckyTest] Charm not found: " + charmName));
					}
					else if (runtime.TryEquipTrinket(val3, ref text))
					{
						charms++;
					}
					else
					{
						LuckyTestPlugin.Log.LogWarning((object)("[LuckyTest] Charm failed " + charmName + ": " + text));
					}
				}
				int drinks = 0;
				string text2 = default(string);
				foreach (string drinkName in drinkNames)
				{
					if (runtime.TryDrink(drinkName, ref text2, ref text))
					{
						drinks++;
					}
					else
					{
						LuckyTestPlugin.Log.LogWarning((object)("[LuckyTest] Drink failed " + drinkName + ": " + text));
					}
				}
				int num4 = Mathf.Max(0, LuckyTestPlugin.StartingMoney.Value);
				int num5 = default(int);
				if (num4 > 0 && !runtime.TryAddMoney(num4, ref num5, ref text))
				{
					LuckyTestPlugin.Log.LogWarning((object)("[LuckyTest] Money failed: " + text));
				}
				yield return null;
				int num6 = Mathf.Clamp(LuckyTestPlugin.StartingRound.Value, 1, 99);
				if (!runtime.TryGoToLevel(num6, ref text))
				{
					LuckyTestPlugin.Log.LogWarning((object)$"[LuckyTest] TryGoToLevel({num6}) failed: {text}. Falling back to round index.");
					ForceRoundIndex(num6);
				}
				gm = GameManager.Instance;
				if ((Object)(object)gm != (Object)null)
				{
					try
					{
						gm.TryContinueAfterWinIntoEndless();
					}
					catch (Exception ex)
					{
						LuckyTestPlugin.Log.LogInfo((object)("[LuckyTest] TryContinueAfterWinIntoEndless: " + ex.Message));
					}
				}
				runtime.MarkRunCheated("LuckyTest sandbox launch");
				LuckyTestPlugin.Log.LogInfo((object)$"[LuckyTest] Ready — holos={equipped}, bullets={bulletsAdded}, charms={charms}, drinks={drinks}, level={num6}");
			}
			finally
			{
				IsLaunching = false;
			}
		}

		private static void ForceRoundIndex(int oneBasedLevel)
		{
			ScoreManager instance = ScoreManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			int roundIndex = Mathf.Max(0, oneBasedLevel - 1);
			instance.SetRoundIndex(roundIndex);
			ShopManager instance2 = ShopManager.Instance;
			if (!((Object)(object)instance2 != (Object)null))
			{
				return;
			}
			try
			{
				AccessTools.Method(typeof(ShopManager), "DebugSetAnteForDeveloperTools", (Type[])null, (Type[])null)?.Invoke(instance2, new object[1] { oneBasedLevel });
			}
			catch (Exception ex)
			{
				LuckyTestPlugin.Log.LogInfo((object)("[LuckyTest] DebugSetAnte: " + ex.Message));
			}
		}

		private static HoloItemData ResolveHolo(UnityDeveloperConsoleRuntime runtime, string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return null;
			}
			HoloItemData val = runtime.FindHolo(id);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			foreach (CatalogEntry holo in CatalogCache.Holos)
			{
				if (string.Equals(holo.Id, id, StringComparison.OrdinalIgnoreCase))
				{
					Object asset = holo.Asset;
					HoloItemData val2 = (HoloItemData)(object)((asset is HoloItemData) ? asset : null);
					if (val2 != null)
					{
						return val2;
					}
				}
			}
			HoloItemData[] array = Resources.FindObjectsOfTypeAll<HoloItemData>();
			foreach (HoloItemData val3 in array)
			{
				if ((Object)(object)val3 != (Object)null && (string.Equals(val3.catalogId, id, StringComparison.OrdinalIgnoreCase) || string.Equals(((Object)val3).name, id, StringComparison.OrdinalIgnoreCase)))
				{
					return val3;
				}
			}
			return null;
		}

		private static BulletItemData FindBulletByAssetName(string name)
		{
			BulletItemData[] array = Resources.FindObjectsOfTypeAll<BulletItemData>();
			foreach (BulletItemData val in array)
			{
				if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, name, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		private static CharmItemData FindCharmByAssetName(string name)
		{
			CharmItemData[] array = Resources.FindObjectsOfTypeAll<CharmItemData>();
			foreach (CharmItemData val in array)
			{
				if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, name, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		private static void PersistSelection(HashSet<string> holos, HashSet<string> bullets, HashSet<string> charms, HashSet<string> drinks)
		{
			LuckyTestPlugin.SavedHoloIds.Value = string.Join(",", holos.OrderBy((string s) => s));
			LuckyTestPlugin.SavedBulletNames.Value = string.Join(",", bullets.OrderBy((string s) => s));
			LuckyTestPlugin.SavedCharmNames.Value = string.Join(",", charms.OrderBy((string s) => s));
			LuckyTestPlugin.SavedDrinkNames.Value = string.Join(",", drinks.OrderBy((string s) => s));
			((BaseUnityPlugin)LuckyTestPlugin.Instance).Config.Save();
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.liamgaming.luckytest", "LuckyTest", "1.1.3")]
	public class LuckyTestPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.liamgaming.luckytest";

		public const string PluginName = "LuckyTest";

		public const string PluginVersion = "1.1.3";

		private TesterPanel _panel;

		private KeyCode _boundKey;

		private static readonly KeyCode[] HotkeyCycle;

		public static LuckyTestPlugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static ConfigEntry<bool> Enabled { get; private set; }

		public static ConfigEntry<int> StartingRound { get; private set; }

		public static ConfigEntry<int> StartingMoney { get; private set; }

		public static ConfigEntry<int> ExtraHoloSlots { get; private set; }

		public static ConfigEntry<int> DefaultBulletAmount { get; private set; }

		public static ConfigEntry<bool> OpenPanelOnMainMenu { get; private set; }

		public static ConfigEntry<KeyCode> ToggleKey { get; private set; }

		public static ConfigEntry<string> SavedHoloIds { get; private set; }

		public static ConfigEntry<string> SavedBulletNames { get; private set; }

		public static ConfigEntry<string> SavedCharmNames { get; private set; }

		public static ConfigEntry<string> SavedDrinkNames { get; private set; }

		private void Awake()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Expected O, but got Unknown
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: 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_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for LuckyTest.");
			OpenPanelOnMainMenu = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OpenPanelOnMainMenu", true, "When shooting the LUCKY TEST main-menu card, open the builder panel.");
			StartingRound = ((BaseUnityPlugin)this).Config.Bind<int>("Launch", "StartingRound", 9, new ConfigDescription("1-based level/ante to jump to after applying the loadout (endless-friendly).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 99), Array.Empty<object>()));
			StartingMoney = ((BaseUnityPlugin)this).Config.Bind<int>("Launch", "StartingMoney", 1000, new ConfigDescription("Money granted when launching a test run.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999999), Array.Empty<object>()));
			ExtraHoloSlots = ((BaseUnityPlugin)this).Config.Bind<int>("Launch", "ExtraHoloSlots", 20, new ConfigDescription("Extra holo slots unlocked before equipping.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>()));
			DefaultBulletAmount = ((BaseUnityPlugin)this).Config.Bind<int>("Launch", "DefaultBulletAmount", 8, new ConfigDescription("How many of each selected special bullet to grant.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 64), Array.Empty<object>()));
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ToggleKey", (KeyCode)288, "Keyboard key to open/close the LuckyTest panel.");
			SavedHoloIds = ((BaseUnityPlugin)this).Config.Bind<string>("SavedLoadout", "HoloIds", "", "Comma-separated holo catalog IDs remembered between sessions.");
			SavedBulletNames = ((BaseUnityPlugin)this).Config.Bind<string>("SavedLoadout", "BulletNames", "", "Comma-separated bullet asset names.");
			SavedCharmNames = ((BaseUnityPlugin)this).Config.Bind<string>("SavedLoadout", "CharmNames", "", "Comma-separated charm/trinket asset names.");
			SavedDrinkNames = ((BaseUnityPlugin)this).Config.Bind<string>("SavedLoadout", "DrinkNames", "", "Comma-separated energy drink asset names.");
			ModMenu.Tab("LuckyTest").Toggle(Enabled).Info("— Launch —")
				.Int("Start Round", StartingRound, 1)
				.Int("Start Money", StartingMoney, 50)
				.Int("Extra Holo Slots", ExtraHoloSlots, 1)
				.Int("Bullet Amount", DefaultBulletAmount, 1)
				.Info("— Panel —")
				.Bool("Menu Card Opens Panel", OpenPanelOnMainMenu)
				.Cycle("Hotkey", (Func<string>)(() => ((object)ToggleKey.Value/*cast due to .constrained prefix*/).ToString()), (Action)CycleToggleKey)
				.Button("Open Panel", (Action)delegate
				{
					if ((Object)(object)_panel != (Object)null)
					{
						_panel.Toggle();
					}
				});
			GameObject val = new GameObject("LuckyTest");
			Object.DontDestroyOnLoad((Object)(object)val);
			_panel = val.AddComponent<TesterPanel>();
			_boundKey = ToggleKey.Value;
			InputAPI.RegisterKeyCallback(_boundKey, (Action)OnHotkey);
			ToggleKey.SettingChanged += delegate
			{
			};
			MainMenu.WhenReady((Action)delegate
			{
				MainMenu.AddButton("LUCKY TEST", (Action)delegate
				{
					if (Enabled.Value && OpenPanelOnMainMenu.Value)
					{
						_panel?.Open();
					}
				});
			});
			new Harmony("com.liamgaming.luckytest").PatchAll(typeof(LuckyTestPlugin).Assembly);
			Log.LogInfo((object)string.Format("{0} v{1} loaded (OpenShot {2}). Hotkey {3}.", "LuckyTest", "1.1.3", "2.0.3", ToggleKey.Value));
		}

		private void OnHotkey()
		{
			if (Enabled.Value && !((Object)(object)_panel == (Object)null))
			{
				_panel.Toggle();
			}
		}

		private static void CycleToggleKey()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			int num = Array.IndexOf(HotkeyCycle, ToggleKey.Value);
			if (num < 0)
			{
				num = 0;
			}
			ToggleKey.Value = HotkeyCycle[(num + 1) % HotkeyCycle.Length];
		}

		static LuckyTestPlugin()
		{
			KeyCode[] array = new KeyCode[7];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			HotkeyCycle = (KeyCode[])(object)array;
		}
	}
	internal sealed class TesterPanel : MonoBehaviour
	{
		private enum Tab
		{
			Holos,
			Bullets,
			Charms,
			Drinks,
			Launch
		}

		private bool _visible;

		private Tab _tab;

		private Vector2 _scroll;

		private string _filter = "";

		private string _status = "Pick a loadout, then Launch.";

		private Rect _window = new Rect(80f, 60f, 820f, 560f);

		private readonly HashSet<string> _holos = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<string> _bullets = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<string> _charms = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<string> _drinks = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private CursorLockMode _prevLock;

		private bool _prevCursor;

		private bool _catalogReady;

		public void Open()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!_visible)
			{
				_prevLock = Cursor.lockState;
				_prevCursor = Cursor.visible;
				_visible = true;
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				EnsureCatalog();
				LoadSavedSelection();
			}
		}

		public void Close()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (_visible)
			{
				_visible = false;
				Cursor.lockState = _prevLock;
				Cursor.visible = _prevCursor;
			}
		}

		public void Toggle()
		{
			if (_visible)
			{
				Close();
			}
			else
			{
				Open();
			}
		}

		private void Update()
		{
			if (_visible && InputAPI.WasPressedThisFrame((KeyCode)27))
			{
				Close();
			}
		}

		private void OnGUI()
		{
			//IL_001c: 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_0037: Expected O, but got Unknown
			//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 (_visible && LuckyTestPlugin.Enabled.Value)
			{
				_window = GUI.Window(8742101, _window, new WindowFunction(DrawWindow), "LuckyTest — Build Sandbox");
			}
		}

		private void DrawWindow(int id)
		{
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawTabButton(Tab.Holos, $"Holos ({_holos.Count})");
			DrawTabButton(Tab.Bullets, $"Bullets ({_bullets.Count})");
			DrawTabButton(Tab.Charms, $"Charms ({_charms.Count})");
			DrawTabButton(Tab.Drinks, $"Drinks ({_drinks.Count})");
			DrawTabButton(Tab.Launch, "Launch");
			GUILayout.EndHorizontal();
			GUILayout.Space(6f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Filter", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) });
			_filter = GUILayout.TextField(_filter ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			if (GUILayout.Button("Refresh", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				CatalogCache.Refresh();
				_catalogReady = true;
				_status = $"Catalog refreshed — holos={CatalogCache.Holos.Count}, bullets={CatalogCache.Bullets.Count}";
			}
			if (GUILayout.Button("Clear Tab", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
			{
				ClearCurrentTab();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			switch (_tab)
			{
			case Tab.Holos:
				DrawPicker(CatalogCache.Holos, _holos);
				break;
			case Tab.Bullets:
				DrawPicker(CatalogCache.Bullets, _bullets);
				break;
			case Tab.Charms:
				DrawPicker(CatalogCache.Charms, _charms);
				break;
			case Tab.Drinks:
				DrawPicker(CatalogCache.Drinks, _drinks);
				break;
			case Tab.Launch:
				DrawLaunchTab();
				break;
			}
			GUILayout.EndScrollView();
			GUILayout.Space(4f);
			GUILayout.Label(_status, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
			{
				Close();
			}
			GUI.enabled = !LoadoutApplier.IsLaunching;
			if (GUILayout.Button(LoadoutApplier.IsLaunching ? "Launching…" : "START TEST RUN", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
			{
				StartTest();
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
		}

		private void DrawTabButton(Tab tab, string label)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			Color backgroundColor = GUI.backgroundColor;
			if (_tab == tab)
			{
				GUI.backgroundColor = new Color(0.2f, 0.75f, 0.55f);
			}
			if (GUILayout.Button(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }))
			{
				_tab = tab;
			}
			GUI.backgroundColor = backgroundColor;
		}

		private void DrawPicker(List<CatalogEntry> entries, HashSet<string> selected)
		{
			if (entries == null || entries.Count == 0)
			{
				GUILayout.Label("No items found yet. Enter a run once, or hit Refresh after the game has loaded assets.", Array.Empty<GUILayoutOption>());
				return;
			}
			string value = (_filter ?? "").Trim();
			foreach (CatalogEntry entry in entries)
			{
				if (!string.IsNullOrEmpty(value) && entry.Label.IndexOf(value, StringComparison.OrdinalIgnoreCase) < 0 && entry.Id.IndexOf(value, StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				bool flag = selected.Contains(entry.Id);
				bool flag2 = GUILayout.Toggle(flag, entry.Label, Array.Empty<GUILayoutOption>());
				if (flag2 != flag)
				{
					if (flag2)
					{
						selected.Add(entry.Id);
					}
					else
					{
						selected.Remove(entry.Id);
					}
				}
			}
		}

		private void DrawLaunchTab()
		{
			GUILayout.Label("Launch jumps into a run (if needed), equips your picks, then GoToLevel(StartingRound).", Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			GUILayout.Label($"Starting round (1-based): {LuckyTestPlugin.StartingRound.Value}", Array.Empty<GUILayoutOption>());
			LuckyTestPlugin.StartingRound.Value = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)LuckyTestPlugin.StartingRound.Value, 1f, 40f, Array.Empty<GUILayoutOption>()));
			GUILayout.Label($"Starting money: {LuckyTestPlugin.StartingMoney.Value}", Array.Empty<GUILayoutOption>());
			LuckyTestPlugin.StartingMoney.Value = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)LuckyTestPlugin.StartingMoney.Value, 0f, 5000f, Array.Empty<GUILayoutOption>()) / 50f) * 50;
			GUILayout.Label($"Extra holo slots: {LuckyTestPlugin.ExtraHoloSlots.Value}", Array.Empty<GUILayoutOption>());
			LuckyTestPlugin.ExtraHoloSlots.Value = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)LuckyTestPlugin.ExtraHoloSlots.Value, 0f, 40f, Array.Empty<GUILayoutOption>()));
			GUILayout.Label($"Bullets per type: {LuckyTestPlugin.DefaultBulletAmount.Value}", Array.Empty<GUILayoutOption>());
			LuckyTestPlugin.DefaultBulletAmount.Value = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)LuckyTestPlugin.DefaultBulletAmount.Value, 1f, 32f, Array.Empty<GUILayoutOption>()));
			GUILayout.Space(8f);
			GUILayout.Label($"Selected — Holos {_holos.Count} | Bullets {_bullets.Count} | Charms {_charms.Count} | Drinks {_drinks.Count}", Array.Empty<GUILayoutOption>());
			GUILayout.Label("Tip: set Starting Round past the normal win ante (default 9) to land in endless scoring.", Array.Empty<GUILayoutOption>());
		}

		private void StartTest()
		{
			EnsureCatalog();
			_status = "Launching test run…";
			Close();
			LoadoutApplier.BeginLaunch((MonoBehaviour)(object)this, Clone(_holos), Clone(_bullets), Clone(_charms), Clone(_drinks));
		}

		private static HashSet<string> Clone(HashSet<string> src)
		{
			return new HashSet<string>(src, StringComparer.OrdinalIgnoreCase);
		}

		private void ClearCurrentTab()
		{
			switch (_tab)
			{
			case Tab.Holos:
				_holos.Clear();
				break;
			case Tab.Bullets:
				_bullets.Clear();
				break;
			case Tab.Charms:
				_charms.Clear();
				break;
			case Tab.Drinks:
				_drinks.Clear();
				break;
			}
		}

		private void EnsureCatalog()
		{
			if (!_catalogReady || CatalogCache.Holos.Count <= 0)
			{
				CatalogCache.Refresh();
				_catalogReady = true;
			}
		}

		private void LoadSavedSelection()
		{
			Fill(_holos, LuckyTestPlugin.SavedHoloIds.Value);
			Fill(_bullets, LuckyTestPlugin.SavedBulletNames.Value);
			Fill(_charms, LuckyTestPlugin.SavedCharmNames.Value);
			Fill(_drinks, LuckyTestPlugin.SavedDrinkNames.Value);
		}

		private static void Fill(HashSet<string> set, string csv)
		{
			set.Clear();
			if (string.IsNullOrWhiteSpace(csv))
			{
				return;
			}
			string[] array = csv.Split(new char[3] { ',', ';', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					set.Add(text);
				}
			}
		}
	}
}