Decompiled source of AdminMenu v1.0.0

AdminMenu.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using AdminMenu.Access;
using AdminMenu.Actions;
using AdminMenu.Catalog;
using AdminMenu.Configuration;
using AdminMenu.Features;
using AdminMenu.Interop;
using AdminMenu.Localization;
using AdminMenu.Menu;
using AdminMenu.Targeting;
using AdminMenu.Upgrades;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using REPOLib.Modules;
using TMPro;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AdminMenu")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e23b1c43e89b062d80bfa6937434360b6b05ca2a")]
[assembly: AssemblyProduct("AdminMenu")]
[assembly: AssemblyTitle("AdminMenu")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AdminMenu
{
	internal static class MyPluginInfo
	{
		internal const string PLUGIN_GUID = "DarkSpider90.AdminMenu";

		internal const string PLUGIN_NAME = "Admin Menu";

		internal const string PLUGIN_VERSION = "1.0.0";
	}
	[BepInPlugin("DarkSpider90.AdminMenu", "Admin Menu", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			AdminMenuSettings.Bind(((BaseUnityPlugin)this).Config);
			LanguageFiles.LoadEmbedded();
			LanguageFiles.LoadAll();
			AdminMenuSettings.WriteLanguageTemplate.SettingChanged += delegate
			{
				if ((Object)(object)LocalizationManager.instance != (Object)null)
				{
					LanguageFiles.WriteTemplateIfRequested();
				}
			};
			ApplyPatches();
			Log.LogInfo((object)"Admin Menu v1.0.0 loaded for R.E.P.O. v0.5.0.");
		}

		private void OnDestroy()
		{
			LocaleWatcher.Unsubscribe();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal static void LogVerbose(string message)
		{
			if (AdminMenuSettings.VerboseLogging != null && AdminMenuSettings.VerboseLogging.Value)
			{
				Log.LogInfo((object)message);
			}
		}

		private void ApplyPatches()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_harmony = new Harmony("DarkSpider90.AdminMenu");
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(Assembly.GetExecutingAssembly());
			foreach (Type type in typesFromAssembly)
			{
				try
				{
					List<MethodInfo> list = _harmony.CreateClassProcessor(type).Patch();
					if ((list == null || list.Count <= 0) && DeclaresPatchMethods(type))
					{
						Log.LogError((object)(type.FullName + " declares Harmony patch methods but carries no [HarmonyPatch] attribute on the class itself, so none of them were applied."));
					}
				}
				catch (Exception arg)
				{
					Log.LogError((object)$"Failed to apply patches from {type.FullName}; continuing. {arg}");
				}
			}
		}

		private static bool DeclaresPatchMethods(Type type)
		{
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
			{
				if (((MemberInfo)declaredMethod).GetCustomAttribute<HarmonyPrefix>() != null || ((MemberInfo)declaredMethod).GetCustomAttribute<HarmonyPostfix>() != null || ((MemberInfo)declaredMethod).GetCustomAttribute<HarmonyTranspiler>() != null || ((MemberInfo)declaredMethod).GetCustomAttribute<HarmonyFinalizer>() != null)
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace AdminMenu.Upgrades
{
	internal static class UpgradeApplier
	{
		internal static bool SetLevel(string upgradeId, TargetPlayer player, int level)
		{
			if (string.IsNullOrEmpty(upgradeId) || !player.IsValid)
			{
				return false;
			}
			if (!PunBridge.CanAct)
			{
				Plugin.Log.LogWarning((object)("Only the host can change upgrades, so \"" + upgradeId + "\" was left alone."));
				return false;
			}
			level = Mathf.Max(level, 0);
			int level2 = UpgradeLevelReader.GetLevel(upgradeId, player);
			if (level2 == level)
			{
				return true;
			}
			if (!(RepoLibBridge.IsModdedUpgrade(upgradeId) ? ApplyModded(upgradeId, player.SteamId, level) : ApplyVanilla(upgradeId, player.SteamId, level, level2)))
			{
				return false;
			}
			int level3 = UpgradeLevelReader.GetLevel(upgradeId, player);
			if (level3 != level)
			{
				Plugin.Log.LogWarning((object)$"Upgrade \"{upgradeId}\" for {player.Name} was set to {level} but reads back as {level3}.");
				return false;
			}
			Plugin.LogVerbose($"Upgrade \"{upgradeId}\" for {player.Name}: {level2} -> {level}.");
			return true;
		}

		internal static bool AddLevel(string upgradeId, TargetPlayer player, int amount = 1)
		{
			return SetLevel(upgradeId, player, UpgradeLevelReader.GetLevel(upgradeId, player) + amount);
		}

		internal static bool RemoveLevel(string upgradeId, TargetPlayer player, int amount = 1)
		{
			return AddLevel(upgradeId, player, -amount);
		}

		internal static bool Clear(string upgradeId, TargetPlayer player)
		{
			return SetLevel(upgradeId, player, 0);
		}

		internal static int ClearAll(TargetPlayer player)
		{
			int num = 0;
			foreach (CatalogEntry<string> item in UpgradeCatalog.All)
			{
				if (UpgradeLevelReader.GetLevel(item.Id, player) > 0 && Clear(item.Id, player))
				{
					num++;
				}
			}
			return num;
		}

		private static bool ApplyVanilla(string upgradeId, string steamId, int level, int current)
		{
			return PunBridge.ApplyVanillaUpgradeDelta(steamId, upgradeId, level - current);
		}

		private static bool ApplyModded(string upgradeId, string steamId, int level)
		{
			UpgradeDictionaryLink.Ensure(upgradeId);
			if (!RepoLibBridge.TrySetModdedUpgradeLevel(upgradeId, steamId, level))
			{
				return false;
			}
			StatsDictionaryAccess.SetValue(UpgradeCatalog.StatsKeyFor(upgradeId), steamId, level);
			PunBridge.SyncAllDictionaries();
			return true;
		}
	}
	internal static class UpgradeDictionaryLink
	{
		private static readonly HashSet<string> Linked = new HashSet<string>(StringComparer.Ordinal);

		internal static bool Ensure(string upgradeId)
		{
			if (string.IsNullOrEmpty(upgradeId) || !RepoLibBridge.IsModdedUpgrade(upgradeId))
			{
				return true;
			}
			if (!RepoLibBridge.TryGetModdedUpgradeTable(upgradeId, out var table))
			{
				return false;
			}
			IDictionary<string, Dictionary<string, int>> registry = StatsDictionaryAccess.GetRegistry(StatsManager.instance);
			if (registry == null)
			{
				return false;
			}
			string key = UpgradeCatalog.StatsKeyFor(upgradeId);
			if (!registry.TryGetValue(key, out var value) || value == null)
			{
				registry[key] = table;
				Report(upgradeId, "registered REPOLib's table with the game");
				return true;
			}
			if (value == table)
			{
				return true;
			}
			foreach (KeyValuePair<string, int> item in table)
			{
				if (!value.ContainsKey(item.Key))
				{
					value[item.Key] = item.Value;
				}
			}
			if (!RepoLibBridge.TrySetModdedUpgradeTable(upgradeId, value))
			{
				return false;
			}
			Report(upgradeId, "pointed REPOLib at the game's table");
			return true;
		}

		internal static void EnsureAll()
		{
			foreach (string moddedUpgradeId in RepoLibBridge.GetModdedUpgradeIds())
			{
				Ensure(moddedUpgradeId);
			}
		}

		internal static void Reset()
		{
			Linked.Clear();
		}

		private static void Report(string upgradeId, string what)
		{
			if (Linked.Add(upgradeId))
			{
				Plugin.LogVerbose("Upgrade \"" + upgradeId + "\": " + what + ".");
			}
		}
	}
	internal static class UpgradeLevelReader
	{
		internal static int GetLevel(string upgradeId, TargetPlayer player)
		{
			if (!player.IsValid)
			{
				return 0;
			}
			return GetLevel(upgradeId, player.SteamId);
		}

		internal static int GetLevel(string upgradeId, string steamId)
		{
			if (string.IsNullOrEmpty(upgradeId) || string.IsNullOrEmpty(steamId))
			{
				return 0;
			}
			UpgradeDictionaryLink.Ensure(upgradeId);
			int value = StatsDictionaryAccess.GetValue(UpgradeCatalog.StatsKeyFor(upgradeId), steamId);
			if (!RepoLibBridge.IsModdedUpgrade(upgradeId))
			{
				return value;
			}
			if (!RepoLibBridge.TryGetModdedUpgradeLevel(upgradeId, steamId, out var level))
			{
				return value;
			}
			if (level != value && StatsDictionaryAccess.ContainsTable(UpgradeCatalog.StatsKeyFor(upgradeId)))
			{
				Plugin.LogVerbose($"Upgrade \"{upgradeId}\": REPOLib says {level}, the game says {value}; " + "using the game's value.");
				return value;
			}
			return level;
		}

		internal static bool HasUpgrade(string upgradeId, TargetPlayer player)
		{
			return GetLevel(upgradeId, player) > 0;
		}
	}
}
namespace AdminMenu.Targeting
{
	internal readonly struct TargetPlayer : IEquatable<TargetPlayer>
	{
		internal static readonly TargetPlayer None;

		internal string SteamId { get; }

		internal string Name { get; }

		internal bool IsValid => !string.IsNullOrEmpty(SteamId);

		private TargetPlayer(string steamId, string name)
		{
			SteamId = steamId;
			Name = name;
		}

		internal static TargetPlayer From(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return None;
			}
			string text = SemiFunc.PlayerGetSteamID(avatar);
			if (!string.IsNullOrEmpty(text))
			{
				return new TargetPlayer(text, SemiFunc.PlayerGetName(avatar) ?? text);
			}
			return None;
		}

		internal static TargetPlayer FromSteamId(string steamId, string name = null)
		{
			if (!string.IsNullOrEmpty(steamId))
			{
				return new TargetPlayer(steamId, name ?? steamId);
			}
			return None;
		}

		internal bool TryResolve(out PlayerAvatar avatar)
		{
			avatar = (IsValid ? SemiFunc.PlayerAvatarGetFromSteamID(SteamId) : null);
			return (Object)(object)avatar != (Object)null;
		}

		public bool Equals(TargetPlayer other)
		{
			return string.Equals(SteamId, other.SteamId, StringComparison.Ordinal);
		}

		public override bool Equals(object obj)
		{
			if (obj is TargetPlayer other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			if (SteamId != null)
			{
				return StringComparer.Ordinal.GetHashCode(SteamId);
			}
			return 0;
		}

		public override string ToString()
		{
			if (!IsValid)
			{
				return "no target";
			}
			return Name + " [" + SteamId + "]";
		}
	}
	internal static class TargetPlayerResolver
	{
		private const float SpawnUpOffset = 0.6f;

		private const float SpawnForwardOffset = 0.8f;

		internal static List<TargetPlayer> ListPlayers()
		{
			List<TargetPlayer> list = new List<TargetPlayer>();
			List<PlayerAvatar> list2 = SemiFunc.PlayerGetAll();
			if (list2 == null)
			{
				return list;
			}
			foreach (PlayerAvatar item3 in list2)
			{
				TargetPlayer item = TargetPlayer.From(item3);
				if (item.IsValid && !list.Contains(item))
				{
					list.Add(item);
				}
			}
			TargetPlayer item2 = Host();
			int num = (item2.IsValid ? list.IndexOf(item2) : (-1));
			if (num > 0)
			{
				list.RemoveAt(num);
				list.Insert(0, item2);
			}
			return list;
		}

		internal static TargetPlayer Host()
		{
			if (!SemiFunc.IsMultiplayer())
			{
				return Local();
			}
			if (PhotonNetwork.MasterClient != null)
			{
				return TargetPlayer.From(SemiFunc.PlayerAvatarGetFromPhotonPlayer(PhotonNetwork.MasterClient));
			}
			return TargetPlayer.None;
		}

		internal static bool IsHost(TargetPlayer player)
		{
			TargetPlayer targetPlayer = Host();
			if (targetPlayer.IsValid)
			{
				return targetPlayer.Equals(player);
			}
			return false;
		}

		internal static TargetPlayer Local()
		{
			return TargetPlayer.From(SemiFunc.PlayerAvatarLocal());
		}

		internal static TargetPlayer LocalOrSpectated()
		{
			PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
			if ((Object)(object)val != (Object)null && !PlayerAvatarAccess.IsDead(val))
			{
				return TargetPlayer.From(val);
			}
			PlayerAvatar spectatedPlayer = PlayerAvatarAccess.GetSpectatedPlayer();
			if ((Object)(object)spectatedPlayer != (Object)null && (Object)(object)spectatedPlayer != (Object)(object)val)
			{
				return TargetPlayer.From(spectatedPlayer);
			}
			return TargetPlayer.From(val);
		}

		internal static bool IsLocal(TargetPlayer player)
		{
			PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
			if ((Object)(object)val != (Object)null)
			{
				return player.Equals(TargetPlayer.From(val));
			}
			return false;
		}

		internal static bool IsDead(TargetPlayer player)
		{
			if (player.TryResolve(out var avatar))
			{
				return PlayerAvatarAccess.IsDead(avatar);
			}
			return false;
		}

		internal static bool TryGetPose(TargetPlayer player, out Vector3 position, out Quaternion rotation)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			rotation = Quaternion.identity;
			if (!player.TryResolve(out var avatar))
			{
				return false;
			}
			if (PlayerAvatarAccess.IsDead(avatar))
			{
				PlayerDeathHead deathHead = PlayerAvatarAccess.GetDeathHead(avatar);
				if ((Object)(object)deathHead != (Object)null)
				{
					position = ((Component)deathHead).transform.position;
					rotation = ((Component)deathHead).transform.rotation;
					return true;
				}
			}
			position = ((Component)avatar).transform.position;
			rotation = ((Component)avatar).transform.rotation;
			return true;
		}

		internal static bool TryGetSpawnPoint(TargetPlayer player, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			if (!TryGetPose(player, out var position2, out var rotation))
			{
				return TryGetObservedPosition(out position);
			}
			position = position2 + Vector3.up * 0.6f + rotation * Vector3.forward * 0.8f;
			return true;
		}

		internal static bool TryGetObservedPosition(out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			try
			{
				if ((Object)(object)AudioListenerFollow.instance == (Object)null || (Object)(object)AudioListenerFollow.instance.TargetPositionTransform == (Object)null)
				{
					return false;
				}
				position = SemiFunc.PlayerGetObservedPosition() + Vector3.up * 0.6f;
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class TargetPlayerService
	{
		private static TargetPlayer _selected = TargetPlayer.None;

		internal static TargetPlayer Current
		{
			get
			{
				if (_selected.IsValid && _selected.TryResolve(out var _))
				{
					return _selected;
				}
				return TargetPlayerResolver.LocalOrSpectated();
			}
		}

		internal static bool IsFollowingLocal
		{
			get
			{
				PlayerAvatar avatar;
				if (_selected.IsValid)
				{
					return !_selected.TryResolve(out avatar);
				}
				return true;
			}
		}

		internal static event Action Changed;

		internal static void Select(TargetPlayer player)
		{
			if (!_selected.Equals(player))
			{
				_selected = player;
				Plugin.LogVerbose($"Admin target is now {Current}.");
				TargetPlayerService.Changed?.Invoke();
			}
		}

		internal static void Select(PlayerAvatar avatar)
		{
			Select(TargetPlayer.From(avatar));
		}

		internal static void FollowLocal()
		{
			Select(TargetPlayer.None);
		}

		internal static void Reset()
		{
			_selected = TargetPlayer.None;
		}

		internal static List<TargetPlayer> ListPlayers()
		{
			return TargetPlayerResolver.ListPlayers();
		}

		internal static bool TryResolveCurrent(out PlayerAvatar avatar)
		{
			return Current.TryResolve(out avatar);
		}

		internal static bool TryGetSpawnPoint(out Vector3 position)
		{
			return TargetPlayerResolver.TryGetSpawnPoint(Current, out position);
		}
	}
}
namespace AdminMenu.Patches
{
	[HarmonyPatch(typeof(EnemyHealth))]
	internal static class EnemyHealthPatches
	{
		private const int FallbackDamage = 100;

		[HarmonyPatch("Hurt")]
		[HarmonyPrefix]
		private static void Hurt_Prefix(ref int _damage, int ___healthCurrent)
		{
			if (AdminFlags.OneShotEnemies)
			{
				_damage = ((___healthCurrent > 0) ? ___healthCurrent : 100);
			}
		}
	}
	[HarmonyPatch(typeof(ItemAttributes))]
	internal static class ItemAttributesPatches
	{
		[HarmonyPatch("GetValue")]
		[HarmonyPostfix]
		private static void GetValue_Postfix(ItemAttributes __instance, ref int ___value)
		{
			if (!AdminFlags.FreeShopItems || ___value == 0)
			{
				return;
			}
			___value = 0;
			if (SemiFunc.IsMultiplayer())
			{
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				if ((Object)(object)component != (Object)null && component.ViewID != 0)
				{
					component.RPC("GetValueRPC", (RpcTarget)1, new object[1] { 0 });
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemBattery))]
	internal static class ItemBatteryPatches
	{
		private const float FullCharge = 100f;

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void Update_Postfix(ItemBattery __instance, ref int ___batteryLifeInt)
		{
			if (AdminFlags.InfiniteAmmo)
			{
				__instance.batteryLife = 100f;
				___batteryLifeInt = __instance.batteryBars;
			}
		}
	}
	[HarmonyPatch(typeof(LocalizationManager))]
	internal static class LocalizationManagerPatches
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void Start_Postfix()
		{
			LanguageFiles.WriteTemplateIfRequested();
		}
	}
	[HarmonyPatch(typeof(RunManager))]
	internal static class MenuHotkeyPatches
	{
		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void Update_Postfix()
		{
			AdminTick.Run();
		}
	}
	[HarmonyPatch(typeof(PlayerController))]
	internal static class PlayerControllerPatches
	{
		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void Update_Postfix(PlayerController __instance)
		{
			if (AdminFlags.LocalInfiniteStamina)
			{
				__instance.EnergyCurrent = __instance.EnergyStart;
			}
			FreeFlight.Drive();
		}
	}
	[HarmonyPatch(typeof(PlayerHealth))]
	internal static class PlayerHealthPatches
	{
		[HarmonyPatch("Hurt")]
		[HarmonyPrefix]
		private static bool Hurt_Prefix(PlayerAvatar ___playerAvatar)
		{
			return !AdminFlags.IsImmortal(___playerAvatar);
		}

		[HarmonyPatch("HurtOther")]
		[HarmonyPrefix]
		private static bool HurtOther_Prefix(PlayerAvatar ___playerAvatar)
		{
			return !AdminFlags.IsImmortal(___playerAvatar);
		}
	}
	[HarmonyPatch(typeof(RunManager))]
	internal static class RunManagerPatches
	{
		[HarmonyPatch("SetRunLevel")]
		[HarmonyPrefix]
		private static bool SetRunLevel_Prefix(RunManager __instance, ref Level ___previousRunLevel)
		{
			Level val = LevelActions.ConsumePendingLevel();
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			___previousRunLevel = null;
			__instance.levelCurrent = val;
			Plugin.LogVerbose("Level forced to \"" + ((Object)val).name + "\".");
			return false;
		}

		[HarmonyPatch("ChangeLevel")]
		[HarmonyPostfix]
		private static void ChangeLevel_Postfix(RunManager __instance)
		{
			if ((Object)(object)__instance.levelCurrent != (Object)null && (Object)(object)__instance.levelCurrent == (Object)(object)__instance.levelMainMenu)
			{
				AdminSession.Reset();
			}
		}
	}
}
namespace AdminMenu.Menu
{
	internal static class AdminMenuController
	{
		internal static bool IsOpen => MenuNavigator.IsOpen;

		internal static void Toggle()
		{
			if (IsOpen)
			{
				Close();
			}
			else
			{
				Open();
			}
		}

		internal static void Open()
		{
			if (SemiFunc.MenuLevel())
			{
				Plugin.Log.LogInfo((object)"The admin menu only opens during a run.");
			}
			else if (!AdminAccess.CanOpenMenu)
			{
				Plugin.Log.LogInfo((object)AdminAccess.RefusalReason());
			}
			else
			{
				MenuNavigator.Start(RootPage.Build);
			}
		}

		internal static void Close()
		{
			MenuNavigator.CloseAll();
		}
	}
	internal static class CatalogListPage
	{
		internal static void Open<TPayload>(string title, IReadOnlyList<CatalogGroup<TPayload>> groups, IReadOnlyList<CatalogEntry<TPayload>> all, Func<CatalogEntry<TPayload>, bool> onPick)
		{
			MenuNavigator.Go(() => Build(title, groups, all, onPick, null));
		}

		private static REPOPopupPage Build<TPayload>(string title, IReadOnlyList<CatalogGroup<TPayload>> groups, IReadOnlyList<CatalogEntry<TPayload>> all, Func<CatalogEntry<TPayload>, bool> onPick, string query)
		{
			REPOPopupPage val = MenuBuilder.CreatePage(title);
			MenuBuilder.InputField(val, Strings.Get("menu.search"), query, delegate(string submitted)
			{
				MenuNavigator.Replace(() => Build(title, groups, all, onPick, submitted));
			});
			MenuBuilder.Spacer(val);
			bool flag = !string.IsNullOrWhiteSpace(query);
			if (!flag && groups != null && groups.Count > 1)
			{
				AddCategories(title, val, groups, onPick);
			}
			else
			{
				IReadOnlyList<CatalogEntry<TPayload>> entries;
				if (!flag)
				{
					entries = all;
				}
				else
				{
					IReadOnlyList<CatalogEntry<TPayload>> readOnlyList = CatalogSearch.Filter(all, query);
					entries = readOnlyList;
				}
				AddEntries(val, entries, onPick);
			}
			return val;
		}

		private static void AddCategories<TPayload>(string title, REPOPopupPage page, IReadOnlyList<CatalogGroup<TPayload>> groups, Func<CatalogEntry<TPayload>, bool> onPick)
		{
			foreach (CatalogGroup<TPayload> group in groups)
			{
				CatalogGroup<TPayload> captured = group;
				MenuBuilder.Button(page, $"{captured.Category} ({captured.Count})", delegate
				{
					MenuNavigator.Go(() => BuildCategory(title, captured, onPick));
				});
			}
		}

		private static REPOPopupPage BuildCategory<TPayload>(string title, CatalogGroup<TPayload> group, Func<CatalogEntry<TPayload>, bool> onPick)
		{
			REPOPopupPage obj = MenuBuilder.CreatePage(title + " - " + group.Category);
			AddEntries(obj, group.Entries, onPick);
			return obj;
		}

		private static void AddEntries<TPayload>(REPOPopupPage page, IReadOnlyList<CatalogEntry<TPayload>> entries, Func<CatalogEntry<TPayload>, bool> onPick)
		{
			foreach (CatalogEntry<TPayload> entry in entries)
			{
				CatalogEntry<TPayload> captured = entry;
				MenuBuilder.Button(page, Label(captured), delegate
				{
					if (onPick(captured) && AdminMenuSettings.CloseMenuOnSpawn.Value)
					{
						AdminMenuController.Close();
					}
				});
			}
		}

		private static string Label<TPayload>(CatalogEntry<TPayload> entry)
		{
			if (!entry.IsModded)
			{
				return entry.DisplayName;
			}
			return "(" + Strings.Get("source.mod") + ") " + entry.DisplayName;
		}
	}
	internal static class EnemyListPage
	{
		private const int MaxCount = 20;

		private static int _count = 1;

		internal static void Open()
		{
			EnemyCatalog.EnsureBuilt();
			MenuNavigator.Go(() => Build(null));
		}

		internal static void Reset()
		{
			_count = 1;
		}

		private static REPOPopupPage Build(string query)
		{
			REPOPopupPage val = MenuBuilder.CreatePage(MenuTitle.ForKey("tab.spawn", "spawn.enemies"));
			MenuBuilder.IntSlider(val, Strings.Get("spawn.count"), 1, 20, _count, delegate(int count)
			{
				_count = count;
			});
			MenuBuilder.InputField(val, Strings.Get("menu.search"), query, delegate(string submitted)
			{
				MenuNavigator.Replace(() => Build(submitted));
			});
			MenuBuilder.Spacer(val);
			IReadOnlyList<CatalogEntry<EnemySetup>> readOnlyList2;
			if (!string.IsNullOrWhiteSpace(query))
			{
				IReadOnlyList<CatalogEntry<EnemySetup>> readOnlyList = CatalogSearch.Filter(EnemyCatalog.All, query);
				readOnlyList2 = readOnlyList;
			}
			else
			{
				readOnlyList2 = EnemyCatalog.All;
			}
			foreach (CatalogEntry<EnemySetup> item in readOnlyList2)
			{
				CatalogEntry<EnemySetup> captured = item;
				MenuBuilder.Button(val, Label(captured), delegate
				{
					SpawnCountdown.Begin(captured, _count);
				});
			}
			return val;
		}

		private static string Label(CatalogEntry<EnemySetup> entry)
		{
			if (!entry.IsModded)
			{
				return entry.DisplayName;
			}
			return "(" + Strings.Get("source.mod") + ") " + entry.DisplayName;
		}
	}
	internal static class LevelPage
	{
		private const int MaxLevelsCompleted = 500;

		internal static REPOPopupPage Build()
		{
			REPOPopupPage obj = MenuBuilder.CreatePage(MenuTitle.ForKey("tab.level"));
			MenuBuilder.IntSlider(obj, Strings.Get("level.completed"), 0, 500, LevelActions.LevelsCompleted, delegate(int completed)
			{
				LevelActions.SetLevelsCompleted(completed);
			});
			MenuBuilder.Spacer(obj);
			MenuBuilder.Button(obj, Strings.Get("level.select"), delegate
			{
				LevelCatalog.EnsureBuilt();
				CatalogListPage.Open(MenuTitle.ForKey("tab.level", "level.select"), LevelCatalog.Groups, LevelCatalog.All, LevelActions.ChangeTo);
			});
			MenuBuilder.Button(obj, Strings.Get("level.shop"), delegate
			{
				MenuNavigator.Go(ShopPage.Build);
			});
			MenuBuilder.Spacer(obj);
			MenuBuilder.Button(obj, Strings.Get("level.extraction_open"), delegate
			{
				ExtractionActions.OpenNext();
			});
			MenuBuilder.Button(obj, Strings.Get("level.extraction_complete"), delegate
			{
				ExtractionActions.CompleteCurrent();
			});
			MenuBuilder.Spacer(obj);
			MenuBuilder.Button(obj, Strings.Get("level.reveal_valuables"), delegate
			{
				RevealActions.RevealValuables();
			});
			MenuBuilder.Button(obj, Strings.Get("level.reveal_boxes"), delegate
			{
				RevealActions.RevealCosmeticBoxes();
			});
			return obj;
		}
	}
	internal static class MenuBuilder
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ScrollViewBuilderDelegate <>9__12_0;

			internal RectTransform <Spacer>b__12_0(Transform scrollView)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				Vector2 spacerSize = SpacerSize;
				return ((REPOElement)MenuAPI.CreateREPOSpacer(scrollView, default(Vector2), spacerSize)).rectTransform;
			}
		}

		private const float Spacing = 0f;

		private static readonly Vector2 SpacerSize = new Vector2(0f, 8f);

		private static readonly Vector2 RowButtonSize = new Vector2(110f, 26f);

		private const float RowStep = 125f;

		internal static REPOPopupPage CreatePage(string title)
		{
			REPOPopupPage obj = MenuAPI.CreateREPOPopupPage(Strings.ForDisplay(title), (PresetSide)0, false, true, 0f);
			MenuFont.ApplyToHeader(obj.headerTMP);
			return obj;
		}

		internal static void Button(REPOPopupPage page, string text, Action onClick)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_0014: 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)
				REPOButton obj = MenuAPI.CreateREPOButton(Strings.ForDisplay(text), onClick, scrollView, default(Vector2));
				MenuFont.Apply(obj.labelTMP);
				return ((REPOElement)obj).rectTransform;
			}, 0f, 0f);
		}

		internal static void ButtonRow(REPOPopupPage page, params (string Text, Action OnClick)[] buttons)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (buttons == null || buttons.Length == 0)
			{
				return;
			}
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Expected O, but got Unknown
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				RectTransform val = (RectTransform)new GameObject("Button Row", new Type[1] { typeof(RectTransform) }).transform;
				((Transform)val).SetParent(scrollView, false);
				val.sizeDelta = new Vector2(125f * (float)buttons.Length, RowButtonSize.y);
				for (int i = 0; i < buttons.Length; i++)
				{
					REPOButton obj = MenuAPI.CreateREPOButton(Strings.ForDisplay(buttons[i].Text), buttons[i].OnClick, (Transform)(object)val, new Vector2(125f * (float)i, 0f));
					MenuFont.Apply(obj.labelTMP);
					obj.overrideButtonSize = RowButtonSize;
				}
				return val;
			}, 0f, 0f);
		}

		internal static void Toggle(REPOPopupPage page, string text, bool value, Action<bool> onToggle)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				string text2 = Strings.ForDisplay(text);
				Action<bool> action = onToggle;
				bool flag = value;
				return ((REPOElement)MenuAPI.CreateREPOToggle(text2, action, scrollView, default(Vector2), "ON", "OFF", flag)).rectTransform;
			}, 0f, 0f);
		}

		internal static void Label(REPOPopupPage page, string text)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			float width = (((Object)(object)page.maskRectTransform == (Object)null) ? 0f : page.maskRectTransform.sizeDelta.x);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				REPOLabel obj = MenuAPI.CreateREPOLabel(Strings.ForDisplay(text), scrollView, default(Vector2));
				MenuFont.ApplyToLabel(obj, width);
				return ((REPOElement)obj).rectTransform;
			}, 0f, 0f);
		}

		internal static void IntSlider(REPOPopupPage page, string text, int min, int max, int value, Action<int> onChanged)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				string text2 = Strings.ForDisplay(text);
				string empty = string.Empty;
				Action<int> action = onChanged;
				int num = min;
				int num2 = max;
				int num3 = Mathf.Clamp(value, min, max);
				return ((REPOElement)MenuAPI.CreateREPOSlider(text2, empty, action, scrollView, default(Vector2), num, num2, num3, "", "", (BarBehavior)0)).rectTransform;
			}, 0f, 0f);
		}

		internal static void OptionSlider(REPOPopupPage page, string text, string[] options, int selected, Action<int> onChanged)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			if (options != null && options.Length != 0)
			{
				int index = Mathf.Clamp(selected, 0, options.Length - 1);
				string[] shown = Array.ConvertAll(options, Strings.ForDisplay);
				page.AddElementToScrollView((ScrollViewBuilderDelegate)((Transform scrollView) => ((REPOElement)MenuAPI.CreateREPOSlider(Strings.ForDisplay(text), string.Empty, onChanged, scrollView, shown, shown[index], default(Vector2), "", "", (BarBehavior)0)).rectTransform), 0f, 0f);
			}
		}

		internal static void InputField(REPOPopupPage page, string label, string value, Action<string> onSubmit)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_0030: 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)
				string text = Strings.ForDisplay(label);
				Action<string> action = onSubmit;
				string text2 = Strings.ForDisplay(label);
				string text3 = value ?? string.Empty;
				return ((REPOElement)MenuAPI.CreateREPOInputField(text, action, scrollView, default(Vector2), true, text2, text3)).rectTransform;
			}, 0f, 0f);
		}

		internal static void Spacer(REPOPopupPage page)
		{
			//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)
			//IL_0020: Expected O, but got Unknown
			object obj = <>c.<>9__12_0;
			if (obj == null)
			{
				ScrollViewBuilderDelegate val = delegate(Transform scrollView)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_0009: 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)
					//IL_0010: Unknown result type (might be due to invalid IL or missing references)
					Vector2 spacerSize = SpacerSize;
					return ((REPOElement)MenuAPI.CreateREPOSpacer(scrollView, default(Vector2), spacerSize)).rectTransform;
				};
				<>c.<>9__12_0 = val;
				obj = (object)val;
			}
			page.AddElementToScrollView((ScrollViewBuilderDelegate)obj, 0f, 0f);
		}
	}
	internal static class MenuFont
	{
		private const float MinSize = 8f;

		private const float MaxSize = 32f;

		private const float MinHeaderSize = 11f;

		private static float? _rowFontSize;

		private static float RowFontSize
		{
			get
			{
				float valueOrDefault = _rowFontSize.GetValueOrDefault();
				if (!_rowFontSize.HasValue)
				{
					valueOrDefault = ReadTemplateFontSize();
					_rowFontSize = valueOrDefault;
				}
				return _rowFontSize.Value;
			}
		}

		private static float Wanted
		{
			get
			{
				int num = ((AdminMenuSettings.MenuFontSize != null) ? AdminMenuSettings.MenuFontSize.Value : 0);
				if (num <= 0)
				{
					return RowFontSize;
				}
				return Mathf.Clamp((float)num, 8f, 32f);
			}
		}

		internal static void Apply(TextMeshProUGUI label)
		{
			float wanted = Wanted;
			if (!((Object)(object)label == (Object)null) && !(wanted <= 0f))
			{
				((TMP_Text)label).enableAutoSizing = false;
				((TMP_Text)label).fontSize = wanted;
			}
		}

		internal static void ApplyToLabel(REPOLabel label, float availableWidth)
		{
			//IL_004a: 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)
			if (!((Object)(object)label == (Object)null))
			{
				Apply(label.labelTMP);
				float num = Mathf.Max(((TMP_Text)label.labelTMP).fontSize + 4f, 16f);
				Vector2 sizeDelta = default(Vector2);
				((Vector2)(ref sizeDelta))..ctor(Mathf.Max(availableWidth, 200f), num);
				((REPOElement)label).rectTransform.sizeDelta = sizeDelta;
				((TMP_Text)label.labelTMP).rectTransform.sizeDelta = sizeDelta;
			}
		}

		internal static void ApplyToHeader(TextMeshProUGUI header)
		{
			if (!((Object)(object)header == (Object)null))
			{
				float num = (((TMP_Text)header).enableAutoSizing ? ((TMP_Text)header).fontSizeMax : ((TMP_Text)header).fontSize);
				if (!(num <= 11f))
				{
					((TMP_Text)header).textWrappingMode = (TextWrappingModes)0;
					((TMP_Text)header).enableAutoSizing = true;
					((TMP_Text)header).fontSizeMin = 11f;
					((TMP_Text)header).fontSizeMax = num;
				}
			}
		}

		private static float ReadTemplateFontSize()
		{
			try
			{
				Type type = AccessTools.TypeByName("MenuLib.REPOTemplates");
				object? obj = ((type == null) ? null : AccessTools.Field(type, "toggleTemplate"))?.GetValue(null);
				RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null);
				if (val == null)
				{
					return 0f;
				}
				TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true);
				if ((Object)(object)componentInChildren == (Object)null)
				{
					return 0f;
				}
				float num = ((((TMP_Text)componentInChildren).enableAutoSizing && ((TMP_Text)componentInChildren).fontSizeMin > 1f) ? ((TMP_Text)componentInChildren).fontSizeMin : ((TMP_Text)componentInChildren).fontSize);
				return (num > 8f) ? Mathf.Clamp(num, 8f, 32f) : 0f;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read the size of a settings row, so the menu keeps MenuLib's own sizes. " + ex.Message));
				return 0f;
			}
		}
	}
	internal static class MenuNavigator
	{
		private const float OpenDelay = 0.05f;

		private static readonly MethodInfo PageCloseAllMethod = AccessTools.Method(typeof(MenuManager), "PageCloseAll", (Type[])null, (Type[])null);

		private static readonly Stack<Func<REPOPopupPage>> History = new Stack<Func<REPOPopupPage>>();

		private static REPOPopupPage _current;

		private static Func<REPOPopupPage> _currentBuilder;

		private static readonly Vector2 FooterPosition = new Vector2(250f, 20f);

		internal static bool IsOpen => (Object)(object)_current != (Object)null;

		internal static void Start(Func<REPOPopupPage> builder)
		{
			History.Clear();
			Show(builder);
		}

		internal static void Go(Func<REPOPopupPage> builder)
		{
			if (_currentBuilder != null)
			{
				History.Push(_currentBuilder);
			}
			Show(builder);
		}

		internal static void Refresh()
		{
			if (_currentBuilder != null)
			{
				Show(_currentBuilder);
			}
		}

		internal static void Replace(Func<REPOPopupPage> builder)
		{
			Show(builder);
		}

		internal static void Back()
		{
			if (History.Count == 0)
			{
				CloseAll();
			}
			else
			{
				Show(History.Pop());
			}
		}

		internal static void CloseAll()
		{
			Close(_current);
			_current = null;
			_currentBuilder = null;
			History.Clear();
		}

		private static void Show(Func<REPOPopupPage> builder)
		{
			Close(_current);
			_currentBuilder = builder;
			REPOPopupPage val = builder();
			AddFooter(val);
			_current = val;
			((MonoBehaviour)MenuManager.instance).StartCoroutine(OpenWhenClear(val));
		}

		private static IEnumerator OpenWhenClear(REPOPopupPage page)
		{
			yield return (object)new WaitForSeconds(0.05f);
			CloseEverything();
			page.OpenPage(false);
		}

		private static void AddFooter(REPOPopupPage page)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			bool flag = History.Count == 0;
			string text = (flag ? Strings.Get("menu.close") : ("← " + Strings.Get("menu.back")));
			Action onClick = (flag ? new Action(CloseAll) : new Action(Back));
			page.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOButton(Strings.ForDisplay(text), onClick, parent, FooterPosition);
			});
		}

		private static void Close(REPOPopupPage page)
		{
			if (!((Object)(object)page == (Object)null))
			{
				CloseEverything();
				page.ClosePage(true);
				MenuManager.instance.PageRemove(page.menuPage);
			}
		}

		private static void CloseEverything()
		{
			if (PageCloseAllMethod == null || (Object)(object)MenuManager.instance == (Object)null)
			{
				return;
			}
			try
			{
				PageCloseAllMethod.Invoke(MenuManager.instance, new object[0]);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not clear the open menu pages. " + ex.Message));
			}
		}
	}
	internal static class MenuTitle
	{
		private const string Separator = " - ";

		internal static string For(params string[] parts)
		{
			StringBuilder stringBuilder = new StringBuilder(Strings.Get("menu.short"));
			if (parts != null)
			{
				foreach (string value in parts)
				{
					if (!string.IsNullOrWhiteSpace(value))
					{
						stringBuilder.Append(" - ").Append(value);
					}
				}
			}
			return stringBuilder.ToString();
		}

		internal static string ForKey(params string[] keys)
		{
			string[] array = new string[keys.Length];
			for (int i = 0; i < keys.Length; i++)
			{
				array[i] = Strings.Get(keys[i]);
			}
			return For(array);
		}
	}
	internal static class OptionsPage
	{
		internal static REPOPopupPage Build()
		{
			REPOPopupPage obj = MenuBuilder.CreatePage(MenuTitle.ForKey("tab.options"));
			MenuBuilder.Toggle(obj, Strings.Get("player.one_shot_enemies"), AdminFlags.OneShotEnemies, AdminFlags.SetOneShotEnemies);
			MenuBuilder.Toggle(obj, Strings.Get("player.infinite_ammo"), AdminFlags.InfiniteAmmo, AdminFlags.SetInfiniteAmmo);
			return obj;
		}
	}
	internal static class PlayerLabel
	{
		internal static string For(TargetPlayer player)
		{
			List<string> list = new List<string>(2);
			if (TargetPlayerResolver.IsHost(player))
			{
				list.Add(Strings.Get("players.host"));
			}
			if (TargetPlayerResolver.IsDead(player))
			{
				list.Add(Strings.Get("players.dead"));
			}
			if (list.Count != 0)
			{
				return player.Name + " (" + string.Join(", ", list) + ")";
			}
			return player.Name;
		}
	}
	internal sealed class PlayerOptions
	{
		private readonly List<TargetPlayer> _players;

		internal string[] Labels { get; }

		internal int SelectedIndex { get; }

		internal bool IsEmpty => _players.Count == 0;

		private PlayerOptions(List<TargetPlayer> players, string[] labels, int selectedIndex)
		{
			_players = players;
			Labels = labels;
			SelectedIndex = selectedIndex;
		}

		internal static PlayerOptions Build(TargetPlayer selected)
		{
			List<TargetPlayer> list = TargetPlayerService.ListPlayers();
			string[] array = new string[list.Count];
			int selectedIndex = 0;
			for (int i = 0; i < list.Count; i++)
			{
				array[i] = PlayerLabel.For(list[i]);
				if (list[i].Equals(selected))
				{
					selectedIndex = i;
				}
			}
			return new PlayerOptions(list, array, selectedIndex);
		}

		internal TargetPlayer At(int index)
		{
			if (index < 0 || index >= _players.Count)
			{
				return TargetPlayer.None;
			}
			return _players[index];
		}
	}
	internal static class PlayerPage
	{
		internal static REPOPopupPage Build(TargetPlayer player)
		{
			REPOPopupPage obj = MenuBuilder.CreatePage(MenuTitle.For(player.Name));
			MenuBuilder.Toggle(obj, Strings.Get("player.god_mode"), AdminFlags.Has(AdminFlag.Immortal, player), delegate(bool state)
			{
				AdminFlags.Grant(AdminFlag.Immortal, player, state);
			});
			MenuBuilder.Toggle(obj, Strings.Get("player.invisible"), InvisibilityActions.IsInvisible(player), delegate(bool state)
			{
				InvisibilityActions.SetInvisible(player, state);
			});
			MenuBuilder.Toggle(obj, Strings.Get("player.infinite_stamina"), AdminFlags.Has(AdminFlag.InfiniteStamina, player), delegate(bool state)
			{
				AdminFlags.Grant(AdminFlag.InfiniteStamina, player, state);
			});
			MenuBuilder.Toggle(obj, Strings.Get("player.free_flight"), AdminFlags.Has(AdminFlag.FreeFlight, player), delegate(bool state)
			{
				AdminFlags.Grant(AdminFlag.FreeFlight, player, state);
			});
			MenuBuilder.Spacer(obj);
			MenuBuilder.Button(obj, Strings.Get("players.upgrades"), delegate
			{
				MenuNavigator.Go(() => UpgradesPage.Build(player));
			});
			MenuBuilder.Button(obj, Strings.Get("players.teleport"), delegate
			{
				MenuNavigator.Go(() => TeleportPage.Build(player));
			});
			MenuBuilder.Spacer(obj);
			MenuBuilder.Button(obj, Strings.Get("player.heal"), delegate
			{
				PlayerActions.Heal(player);
			});
			MenuBuilder.Button(obj, Strings.Get("player.kill"), delegate
			{
				PlayerActions.Kill(player);
			});
			MenuBuilder.Button(obj, Strings.Get("player.revive"), delegate
			{
				PlayerActions.Revive(player);
			});
			return obj;
		}
	}
	internal static class PlayersPage
	{
		internal static REPOPopupPage Build()
		{
			REPOPopupPage val = MenuBuilder.CreatePage(MenuTitle.ForKey("tab.players"));
			foreach (TargetPlayer item in TargetPlayerService.ListPlayers())
			{
				TargetPlayer captured = item;
				MenuBuilder.Button(val, PlayerLabel.For(captured), delegate
				{
					MenuNavigator.Go(() => PlayerPage.Build(captured));
				});
			}
			return val;
		}
	}
	internal static class RootPage
	{
		internal static REPOPopupPage Build()
		{
			REPOPopupPage obj = MenuBuilder.CreatePage(MenuTitle.For());
			MenuBuilder.Button(obj, Strings.Get("tab.players"), delegate
			{
				MenuNavigator.Go(PlayersPage.Build);
			});
			MenuBuilder.Button(obj, Strings.Get("tab.spawn"), delegate
			{
				MenuNavigator.Go(SpawnPage.Build);
			});
			MenuBuilder.Button(obj, Strings.Get("tab.level"), delegate
			{
				MenuNavigator.Go(LevelPage.Build);
			});
			MenuBuilder.Button(obj, Strings.Get("tab.options"), delegate
			{
				MenuNavigator.Go(OptionsPage.Build);
			});
			return obj;
		}
	}
	internal static class ShopPage
	{
		private const int Step = 10000;

		private const int MaxThousands = 9999;

		internal static REPOPopupPage Build()
		{
			REPOPopupPage val = MenuBuilder.CreatePage(MenuTitle.ForKey("tab.level", "level.shop"));
			MenuBuilder.Toggle(val, Strings.Get("level.free_items"), AdminFlags.FreeShopItems, delegate(bool state)
			{
				ShopActions.SetFreeItems(state);
			});
			MenuBuilder.IntSlider(val, Strings.Get("level.money"), 0, 9999, ShopActions.GetMoneyInThousands(), delegate(int thousands)
			{
				ShopActions.SetMoneyInThousands(thousands);
			});
			MenuBuilder.ButtonRow(val, ($"+${10000}", delegate
			{
				Adjust(10000);
			}), ($"-${10000}", delegate
			{
				Adjust(-10000);
			}));
			return val;
		}

		private static void Adjust(int dollars)
		{
			if (ShopActions.AddMoney(dollars))
			{
				MenuNavigator.Refresh();
			}
		}
	}
	internal static class SpawnPage
	{
		internal static REPOPopupPage Build()
		{
			REPOPopupPage obj = MenuBuilder.CreatePage(MenuTitle.ForKey("tab.spawn"));
			PlayerOptions targets = PlayerOptions.Build(TargetPlayerService.Current);
			MenuBuilder.OptionSlider(obj, Strings.Get("spawn.target"), targets.Labels, targets.SelectedIndex, delegate(int index)
			{
				TargetPlayerService.Select(targets.At(index));
			});
			MenuBuilder.Spacer(obj);
			MenuBuilder.Button(obj, Strings.Get("spawn.items"), delegate
			{
				ItemCatalog.EnsureBuilt();
				CatalogListPage.Open(MenuTitle.ForKey("tab.spawn", "spawn.items"), ItemCatalog.Groups, ItemCatalog.All, SpawnActions.SpawnItem);
			});
			MenuBuilder.Button(obj, Strings.Get("spawn.valuables"), delegate
			{
				ValuableCatalog.EnsureBuilt();
				CatalogListPage.Open(MenuTitle.ForKey("tab.spawn", "spawn.valuables"), ValuableCatalog.Groups, ValuableCatalog.All, SpawnActions.SpawnValuable);
			});
			MenuBuilder.Button(obj, Strings.Get("spawn.enemies"), EnemyListPage.Open);
			MenuBuilder.Button(obj, Strings.Get("spawn.cosmetic_boxes"), delegate
			{
				CosmeticBoxCatalog.EnsureBuilt();
				CatalogListPage.Open(MenuTitle.ForKey("tab.spawn", "spawn.cosmetic_boxes"), null, CosmeticBoxCatalog.All, SpawnActions.SpawnCosmeticBox);
			});
			return obj;
		}
	}
	internal static class TeleportPage
	{
		private static TargetPlayer _destination = TargetPlayer.None;

		internal static REPOPopupPage Build(TargetPlayer player)
		{
			REPOPopupPage val = MenuBuilder.CreatePage(MenuTitle.For(player.Name, Strings.Get("players.teleport")));
			if (!TargetPlayerResolver.IsLocal(player))
			{
				MenuBuilder.Button(val, Strings.Get("teleport.player_to_me"), delegate
				{
					PlayerActions.TeleportToMe(player);
				});
				MenuBuilder.Button(val, Strings.Get("teleport.me_to_player"), delegate
				{
					PlayerActions.TeleportMeTo(player);
				});
				MenuBuilder.Spacer(val);
			}
			PlayerOptions destinations = PlayerOptions.Build(Destination());
			MenuBuilder.OptionSlider(val, Strings.Get("teleport.player_to"), destinations.Labels, destinations.SelectedIndex, delegate(int index)
			{
				_destination = destinations.At(index);
			});
			MenuBuilder.Button(val, Strings.Get("teleport.go"), delegate
			{
				PlayerActions.TeleportTo(player, Destination());
			});
			MenuBuilder.Spacer(val);
			MenuBuilder.Button(val, Strings.Get("teleport.to_truck"), delegate
			{
				PlayerActions.TeleportToTruck(player);
			});
			MenuBuilder.Button(val, Strings.Get("teleport.to_extraction"), delegate
			{
				PlayerActions.TeleportToExtraction(player);
			});
			return val;
		}

		private static TargetPlayer Destination()
		{
			if (!_destination.IsValid || !_destination.TryResolve(out var _))
			{
				return TargetPlayerResolver.Local();
			}
			return _destination;
		}
	}
	internal static class UpgradesPage
	{
		internal static REPOPopupPage Build(TargetPlayer player)
		{
			UpgradeCatalog.EnsureBuilt();
			REPOPopupPage val = MenuBuilder.CreatePage(MenuTitle.For(player.Name, Strings.Get("players.upgrades")));
			int value = AdminMenuSettings.MaxUpgradeLevel.Value;
			foreach (CatalogEntry<string> item in UpgradeCatalog.All)
			{
				CatalogEntry<string> captured = item;
				int level = UpgradeLevelReader.GetLevel(captured.Id, player);
				MenuBuilder.IntSlider(val, Label(captured), 0, value, level, delegate(int level2)
				{
					UpgradeApplier.SetLevel(captured.Id, player, level2);
				});
			}
			MenuBuilder.Spacer(val);
			MenuBuilder.Button(val, Strings.Get("upgrades.clear_all"), delegate
			{
				UpgradeApplier.ClearAll(player);
				MenuNavigator.Refresh();
			});
			return val;
		}

		private static string Label(CatalogEntry<string> upgrade)
		{
			if (!upgrade.IsModded)
			{
				return upgrade.DisplayName;
			}
			return "(" + Strings.Get("source.mod") + ") " + upgrade.DisplayName;
		}
	}
}
namespace AdminMenu.Localization
{
	internal static class ArabicText
	{
		private enum Direction
		{
			Neutral,
			LeftToRight,
			RightToLeft
		}

		private const char Lam = 'ل';

		private const char Tatweel = 'ـ';

		private static readonly Dictionary<char, char[]> LamAlef = new Dictionary<char, char[]>
		{
			['آ'] = new char[2] { 'ﻵ', 'ﻶ' },
			['أ'] = new char[2] { 'ﻷ', 'ﻸ' },
			['إ'] = new char[2] { 'ﻹ', 'ﻺ' },
			['ا'] = new char[2] { 'ﻻ', 'ﻼ' }
		};

		private static readonly Dictionary<char, char[]> Forms = new Dictionary<char, char[]>
		{
			['ء'] = new char[1] { 'ﺀ' },
			['آ'] = new char[2] { 'ﺁ', 'ﺂ' },
			['أ'] = new char[2] { 'ﺃ', 'ﺄ' },
			['ؤ'] = new char[2] { 'ﺅ', 'ﺆ' },
			['إ'] = new char[2] { 'ﺇ', 'ﺈ' },
			['ئ'] = new char[4] { 'ﺉ', 'ﺊ', 'ﺋ', 'ﺌ' },
			['ا'] = new char[2] { 'ﺍ', 'ﺎ' },
			['ب'] = new char[4] { 'ﺏ', 'ﺐ', 'ﺑ', 'ﺒ' },
			['ة'] = new char[2] { 'ﺓ', 'ﺔ' },
			['ت'] = new char[4] { 'ﺕ', 'ﺖ', 'ﺗ', 'ﺘ' },
			['ث'] = new char[4] { 'ﺙ', 'ﺚ', 'ﺛ', 'ﺜ' },
			['ج'] = new char[4] { 'ﺝ', 'ﺞ', 'ﺟ', 'ﺠ' },
			['ح'] = new char[4] { 'ﺡ', 'ﺢ', 'ﺣ', 'ﺤ' },
			['خ'] = new char[4] { 'ﺥ', 'ﺦ', 'ﺧ', 'ﺨ' },
			['د'] = new char[2] { 'ﺩ', 'ﺪ' },
			['ذ'] = new char[2] { 'ﺫ', 'ﺬ' },
			['ر'] = new char[2] { 'ﺭ', 'ﺮ' },
			['ز'] = new char[2] { 'ﺯ', 'ﺰ' },
			['س'] = new char[4] { 'ﺱ', 'ﺲ', 'ﺳ', 'ﺴ' },
			['ش'] = new char[4] { 'ﺵ', 'ﺶ', 'ﺷ', 'ﺸ' },
			['ص'] = new char[4] { 'ﺹ', 'ﺺ', 'ﺻ', 'ﺼ' },
			['ض'] = new char[4] { 'ﺽ', 'ﺾ', 'ﺿ', 'ﻀ' },
			['ط'] = new char[4] { 'ﻁ', 'ﻂ', 'ﻃ', 'ﻄ' },
			['ظ'] = new char[4] { 'ﻅ', 'ﻆ', 'ﻇ', 'ﻈ' },
			['ع'] = new char[4] { 'ﻉ', 'ﻊ', 'ﻋ', 'ﻌ' },
			['غ'] = new char[4] { 'ﻍ', 'ﻎ', 'ﻏ', 'ﻐ' },
			['ف'] = new char[4] { 'ﻑ', 'ﻒ', 'ﻓ', 'ﻔ' },
			['ق'] = new char[4] { 'ﻕ', 'ﻖ', 'ﻗ', 'ﻘ' },
			['ك'] = new char[4] { 'ﻙ', 'ﻚ', 'ﻛ', 'ﻜ' },
			['ل'] = new char[4] { 'ﻝ', 'ﻞ', 'ﻟ', 'ﻠ' },
			['م'] = new char[4] { 'ﻡ', 'ﻢ', 'ﻣ', 'ﻤ' },
			['ن'] = new char[4] { 'ﻥ', 'ﻦ', 'ﻧ', 'ﻨ' },
			['ه'] = new char[4] { 'ﻩ', 'ﻪ', 'ﻫ', 'ﻬ' },
			['و'] = new char[2] { 'ﻭ', 'ﻮ' },
			['ى'] = new char[2] { 'ﻯ', 'ﻰ' },
			['ي'] = new char[4] { 'ﻱ', 'ﻲ', 'ﻳ', 'ﻴ' }
		};

		internal static bool IsActive
		{
			get
			{
				LocaleAsset val = Strings.ActiveLocaleAsset();
				if ((Object)(object)val != (Object)null)
				{
					return val.RightToLeft;
				}
				return false;
			}
		}

		internal static string ToVisual(string text)
		{
			if (string.IsNullOrEmpty(text) || !ContainsRightToLeft(text))
			{
				return text;
			}
			return Reorder(Shape(text));
		}

		private static bool ContainsRightToLeft(string text)
		{
			for (int i = 0; i < text.Length; i++)
			{
				if (IsRightToLeft(text[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static string Shape(string text)
		{
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (!Forms.TryGetValue(c, out var value))
				{
					stringBuilder.Append(c);
					continue;
				}
				bool flag = JoinsToFollowing(Neighbour(text, i, -1));
				int num = NeighbourIndex(text, i, 1);
				if (c == 'ل' && num >= 0 && LamAlef.TryGetValue(text[num], out var value2))
				{
					stringBuilder.Append(flag ? value2[1] : value2[0]);
					for (int j = i + 1; j < num; j++)
					{
						stringBuilder.Append(text[j]);
					}
					i = num;
					continue;
				}
				bool flag2 = value.Length == 4 && num >= 0 && JoinsToPrevious(text[num]);
				if (value.Length == 1)
				{
					stringBuilder.Append(value[0]);
				}
				else if (flag && flag2)
				{
					stringBuilder.Append(value[3]);
				}
				else if (flag)
				{
					stringBuilder.Append(value[1]);
				}
				else if (flag2)
				{
					stringBuilder.Append(value[2]);
				}
				else
				{
					stringBuilder.Append(value[0]);
				}
			}
			return stringBuilder.ToString();
		}

		private static bool JoinsToFollowing(char c)
		{
			if (c != 'ـ')
			{
				if (Forms.TryGetValue(c, out var value))
				{
					return value.Length == 4;
				}
				return false;
			}
			return true;
		}

		private static bool JoinsToPrevious(char c)
		{
			if (c != 'ـ')
			{
				if (Forms.TryGetValue(c, out var value))
				{
					return value.Length > 1;
				}
				return false;
			}
			return true;
		}

		private static char Neighbour(string text, int index, int step)
		{
			int num = NeighbourIndex(text, index, step);
			if (num >= 0)
			{
				return text[num];
			}
			return '\0';
		}

		private static int NeighbourIndex(string text, int index, int step)
		{
			for (int i = index + step; i >= 0 && i < text.Length; i += step)
			{
				if (!IsMark(text[i]))
				{
					return i;
				}
			}
			return -1;
		}

		private static bool IsMark(char c)
		{
			if (c < '\u064b' || c > '\u065f')
			{
				return c == '\u0670';
			}
			return true;
		}

		private static string Reorder(string text)
		{
			Direction[] array = new Direction[text.Length];
			for (int i = 0; i < text.Length; i++)
			{
				array[i] = Classify(text[i]);
			}
			for (int j = 0; j < text.Length; j++)
			{
				if (array[j] == Direction.Neutral)
				{
					int k;
					for (k = j; k < text.Length && array[k] == Direction.Neutral; k++)
					{
					}
					Direction direction = ((j > 0) ? array[j - 1] : Direction.RightToLeft);
					Direction direction2 = ((k < text.Length) ? array[k] : Direction.RightToLeft);
					Direction direction3 = ((direction == direction2) ? direction : Direction.RightToLeft);
					for (int l = j; l < k; l++)
					{
						array[l] = direction3;
					}
					j = k - 1;
				}
			}
			List<string> list = new List<string>();
			int num = 0;
			for (int m = 1; m <= text.Length; m++)
			{
				if (m >= text.Length || array[m] != array[num])
				{
					string text2 = text.Substring(num, m - num);
					list.Add((array[num] == Direction.RightToLeft) ? ReverseRun(text2) : text2);
					num = m;
				}
			}
			list.Reverse();
			return string.Concat(list);
		}

		private static string ReverseRun(string run)
		{
			List<string> list = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			foreach (char c in run)
			{
				if (IsMark(c) && stringBuilder.Length > 0)
				{
					stringBuilder.Append(c);
					continue;
				}
				if (stringBuilder.Length > 0)
				{
					list.Add(stringBuilder.ToString());
					stringBuilder.Clear();
				}
				stringBuilder.Append(Mirror(c));
			}
			if (stringBuilder.Length > 0)
			{
				list.Add(stringBuilder.ToString());
			}
			list.Reverse();
			return string.Concat(list);
		}

		private static char Mirror(char c)
		{
			return c switch
			{
				'(' => ')', 
				')' => '(', 
				'[' => ']', 
				']' => '[', 
				'<' => '>', 
				'>' => '<', 
				_ => c, 
			};
		}

		private static Direction Classify(char c)
		{
			if (IsRightToLeft(c))
			{
				return Direction.RightToLeft;
			}
			if (!char.IsLetterOrDigit(c))
			{
				return Direction.Neutral;
			}
			return Direction.LeftToRight;
		}

		private static bool IsRightToLeft(char c)
		{
			if ((c < '\u0590' || c > '\u08ff') && (c < 'יִ' || c > '﷿'))
			{
				if (c >= 'ﹰ')
				{
					return c <= '\ufeff';
				}
				return false;
			}
			return true;
		}
	}
	internal static class GameText
	{
		private static readonly string[] ValuableThemes = new string[5] { "Arctic", "Desert", "Manor", "Museum", "Wizard" };

		private static readonly string[] PrefabPrefixes = new string[7] { "Valuable ", "Level - ", "Enemy - ", "Enemy ", "Item ", "Cosmetic Pouch ", "Cosmetic " };

		internal static string Resolve(LocalizedAsset localized, string fallback)
		{
			if ((Object)(object)localized == (Object)null)
			{
				return fallback ?? string.Empty;
			}
			try
			{
				string localizedString = localized.GetLocalizedString((Locale)null);
				return string.IsNullOrWhiteSpace(localizedString) ? (fallback ?? string.Empty) : localizedString;
			}
			catch (Exception)
			{
				return fallback ?? string.Empty;
			}
		}

		internal static string FromPrefabName(string prefabName)
		{
			return Humanize(StripKind(prefabName));
		}

		internal static string ForValuable(string prefabName)
		{
			string text = StripKind(prefabName);
			if (!Strings.TryGetLocal("valuable." + text, out var text2))
			{
				return Humanize(text);
			}
			string[] valuableThemes = ValuableThemes;
			foreach (string text3 in valuableThemes)
			{
				if (text.StartsWith(text3 + " ", StringComparison.Ordinal) && Strings.TryGetLocal("valuable_theme." + text3, out var text4))
				{
					return Strings.Format("valuable_format", text2, text4);
				}
			}
			return text2;
		}

		internal static string ForLevel(string levelName, string fallback)
		{
			string text = StripKind(levelName);
			if (Strings.TryGetLocal("level_name." + text, out var text2))
			{
				return text2;
			}
			if (!string.IsNullOrWhiteSpace(fallback))
			{
				return fallback;
			}
			return Humanize(text);
		}

		private static string StripKind(string prefabName)
		{
			if (string.IsNullOrWhiteSpace(prefabName))
			{
				return string.Empty;
			}
			string text = prefabName.Trim();
			string[] prefabPrefixes = PrefabPrefixes;
			foreach (string text2 in prefabPrefixes)
			{
				if (text.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
				{
					return text.Substring(text2.Length).Trim();
				}
			}
			return text;
		}

		internal static string Humanize(string identifier)
		{
			if (string.IsNullOrWhiteSpace(identifier))
			{
				return string.Empty;
			}
			string text = identifier.Replace('_', ' ').Replace('-', ' ').Trim();
			StringBuilder stringBuilder = new StringBuilder(text.Length + 8);
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (i > 0 && char.IsUpper(c) && stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] != ' ')
				{
					char c2 = text[i - 1];
					bool num = char.IsLower(c2) || char.IsDigit(c2);
					bool flag = char.IsUpper(c2) && i + 1 < text.Length && char.IsLower(text[i + 1]);
					if (num || flag)
					{
						stringBuilder.Append(' ');
					}
				}
				stringBuilder.Append(c);
			}
			return stringBuilder.ToString();
		}
	}
	internal static class LanguageFiles
	{
		private const string FolderName = "Languages";

		private const string FileExtension = ".lang";

		private const string TemplateSuffix = ".template";

		private const string ResourcePrefix = "AdminMenu.Languages.";

		private const int UnknownKeysShown = 5;

		private static readonly Regex Placeholder = new Regex("\\{\\d+\\}", RegexOptions.Compiled);

		internal static void LoadEmbedded()
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			foreach (string text in manifestResourceNames)
			{
				if (!text.StartsWith("AdminMenu.Languages.", StringComparison.Ordinal) || !text.EndsWith(".lang", StringComparison.Ordinal))
				{
					continue;
				}
				string text2 = text.Substring("AdminMenu.Languages.".Length, text.Length - "AdminMenu.Languages.".Length - ".lang".Length);
				try
				{
					using Stream stream = executingAssembly.GetManifestResourceStream(text);
					if (stream != null)
					{
						using StreamReader reader = new StreamReader(stream, Encoding.UTF8);
						StringTables.Merge(text2, Parse(reader));
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Could not read the built-in language \"" + text2 + "\". " + ex.Message));
				}
			}
		}

		internal static void LoadAll()
		{
			if (LoadFolder(LegacyFolderPath()) > 0)
			{
				Plugin.Log.LogWarning((object)("Language files beside the mod will be lost on the next update. Move them to \"" + UserFolderPath() + "\"."));
			}
			LoadFolder(UserFolderPath());
		}

		internal static void WriteTemplateIfRequested()
		{
			if (AdminMenuSettings.WriteLanguageTemplate != null && AdminMenuSettings.WriteLanguageTemplate.Value && WriteTemplate(Strings.ActiveLocaleCode()))
			{
				AdminMenuSettings.WriteLanguageTemplate.Value = false;
			}
		}

		private static bool WriteTemplate(string localeCode)
		{
			string text = UserFolderPath();
			if (text == null)
			{
				return false;
			}
			try
			{
				Directory.CreateDirectory(text);
				string text2 = Path.Combine(text, localeCode + ".template.lang");
				File.WriteAllText(text2, TemplateText(localeCode), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				Plugin.Log.LogInfo((object)("Wrote the language template to \"" + text2 + "\"."));
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not write the language template. " + ex.Message));
				return false;
			}
		}

		private static string TemplateText(string localeCode)
		{
			LocaleAsset val = Strings.ActiveLocaleAsset();
			string text = (((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.NativeName)) ? localeCode : val.NativeName);
			bool flag = Strings.IsEnglish(localeCode);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# Admin Menu - " + text + " (" + localeCode + ")");
			stringBuilder.AppendLine("# Every line of the menu as it reads right now.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# To change some of them:");
			stringBuilder.AppendLine("#   1. Copy this file to \"" + localeCode + ".lang\" in this same folder.");
			stringBuilder.AppendLine("#   2. Delete the lines you do not want to change. Whatever you leave out keeps the mod's text.");
			stringBuilder.AppendLine("#   3. Edit the text after \"=\". Leave the part before it exactly as it is.");
			stringBuilder.AppendLine("#   4. Restart the game.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# {0} and {1} are filled in with names and numbers - keep them in the text.");
			stringBuilder.AppendLine("# This file itself is never read, and turning the setting on again rewrites it.");
			stringBuilder.AppendLine();
			foreach (KeyValuePair<string, string> item in SortedEnglish())
			{
				if (!flag || !IsGameNameKey(item.Key))
				{
					if (Strings.TryGetIn(localeCode, item.Key, out var text2))
					{
						stringBuilder.Append(item.Key).Append('=').AppendLine(text2);
						continue;
					}
					stringBuilder.AppendLine("# Not translated yet, shown in English:");
					stringBuilder.Append(item.Key).Append('=').AppendLine(item.Value);
				}
			}
			return stringBuilder.ToString();
		}

		private static int LoadFolder(string folder)
		{
			if (folder == null || !Directory.Exists(folder))
			{
				return 0;
			}
			string[] files;
			try
			{
				files = Directory.GetFiles(folder, "*.lang");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not list the language folder \"" + folder + "\". " + ex.Message));
				return 0;
			}
			int num = 0;
			string[] array = files;
			foreach (string text in array)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
				if (!string.IsNullOrEmpty(fileNameWithoutExtension) && !fileNameWithoutExtension.EndsWith(".template", StringComparison.OrdinalIgnoreCase) && !fileNameWithoutExtension.Equals("template", StringComparison.OrdinalIgnoreCase))
				{
					Dictionary<string, string> dictionary = Validate(Path.GetFileName(text), Read(text));
					if (dictionary.Count > 0)
					{
						StringTables.Merge(fileNameWithoutExtension, dictionary);
						Plugin.Log.LogInfo((object)$"Loaded {dictionary.Count} menu strings for \"{fileNameWithoutExtension}\" from \"{text}\".");
						num++;
					}
				}
			}
			return num;
		}

		private static Dictionary<string, string> Validate(string fileName, Dictionary<string, string> entries)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, string> entry in entries)
			{
				if (!StringTables.Fallback.TryGetValue(entry.Key, out var value))
				{
					list.Add(entry.Key);
				}
				else if (PlaceholderSignature(entry.Value) != PlaceholderSignature(value))
				{
					Plugin.Log.LogWarning((object)(fileName + ": \"" + entry.Key + "\" must contain the same markers as the English text (\"" + value + "\"), so the line is ignored."));
				}
				else
				{
					dictionary[entry.Key] = entry.Value;
				}
			}
			if (list.Count > 0)
			{
				string text = string.Join(", ", list.GetRange(0, Math.Min(list.Count, 5)));
				string text2 = ((list.Count > 5) ? $" and {list.Count - 5} more" : string.Empty);
				Plugin.Log.LogWarning((object)$"{fileName}: {list.Count} line(s) have a key the mod does not know, probably a typo: {text}{text2}.");
			}
			return dictionary;
		}

		private static string PlaceholderSignature(string text)
		{
			List<string> list = new List<string>();
			foreach (Match item in Placeholder.Matches(text))
			{
				list.Add(item.Value);
			}
			list.Sort(StringComparer.Ordinal);
			return string.Join(",", list);
		}

		private static bool IsGameNameKey(string key)
		{
			if (!key.StartsWith("valuable.", StringComparison.Ordinal) && !key.StartsWith("valuable_theme.", StringComparison.Ordinal) && !key.StartsWith("level_name.", StringComparison.Ordinal))
			{
				return key == "valuable_format";
			}
			return true;
		}

		private static Dictionary<string, string> Read(string path)
		{
			try
			{
				using StreamReader reader = new StreamReader(path, Encoding.UTF8);
				return Parse(reader);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read the language file \"" + path + "\". " + ex.Message));
				return new Dictionary<string, string>(StringComparer.Ordinal);
			}
		}

		private static Dictionary<string, string> Parse(TextReader reader)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			string text;
			while ((text = reader.ReadLine()) != null)
			{
				string text2 = text.Trim();
				if (text2.Length == 0 || text2[0] == '#')
				{
					continue;
				}
				int num = text2.IndexOf('=');
				if (num > 0)
				{
					string text3 = text2.Substring(0, num).Trim();
					string text4 = text2.Substring(num + 1).Trim();
					if (text3.Length > 0 && text4.Length > 0)
					{
						dictionary[text3] = text4;
					}
				}
			}
			return dictionary;
		}

		private static IEnumerable<KeyValuePair<string, string>> SortedEnglish()
		{
			List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>(StringTables.Fallback);
			list.Sort((KeyValuePair<string, string> left, KeyValuePair<string, string> right) => string.Compare(left.Key, right.Key, StringComparison.Ordinal));
			return list;
		}

		internal static string UserFolderPath()
		{
			try
			{
				return Path.Combine(Paths.ConfigPath, "AdminMenu", "Languages");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not find the BepInEx config folder. " + ex.Message));
				return null;
			}
		}

		private static string LegacyFolderPath()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				return string.IsNullOrEmpty(directoryName) ? null : Path.Combine(directoryName, "Languages");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not work out where the mod is installed. " + ex.Message));
				return null;
			}
		}
	}
	internal static class LocaleWatcher
	{
		private static Action _callback;

		private static bool _subscribed;

		internal static int Version { get; private set; }

		internal static void EnsureSubscribed()
		{
			if (_subscribed || (Object)(object)LocalizationManager.instance == (Object)null)
			{
				return;
			}
			try
			{
				_callback = OnLocalizationChanged;
				LocalizationManager.instance.AddLocalizationChangedCallback(_callback);
				_subscribed = true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not subscribe to language changes, so menu names may lag behind. " + ex.Message));
				_callback = null;
				_subscribed = true;
			}
		}

		internal static void Unsubscribe()
		{
			if (_subscribed && _callback != null && !((Object)(object)LocalizationManager.instance == (Object)null))
			{
				try
				{
					LocalizationManager.instance.RemoveLocalizationChangedCallback(_callback);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Could not unsubscribe from language changes. " + ex.Message));
				}
				_callback = null;
				_subscribed = false;
			}
		}

		internal static string ActiveLocaleName()
		{
			LocaleAsset val = Strings.ActiveLocaleAsset();
			string text;
			if (!((Object)(object)val == (Object)null))
			{
				text = val.NativeName;
				if (text == null)
				{
					return string.Empty;
				}
			}
			else
			{
				text = Strings.ActiveLocaleCode();
			}
			return text;
		}

		private static void OnLocalizationChanged()
		{
			Version++;
			Plugin.LogVerbose("Language changed to \"" + ActiveLocaleName() + "\"; menu names will be rebuilt.");
		}
	}
	internal static class StringKeys
	{
		internal const string MenuTitle = "menu.title";

		internal const string MenuShort = "menu.short";

		internal const string MenuClose = "menu.close";

		internal const string MenuBack = "menu.back";

		internal const string MenuSearch = "menu.search";

		internal const string MenuHostOnly = "menu.host_only";

		internal const string TabPlayers = "tab.players";

		internal const string TabSpawn = "tab.spawn";

		internal const string TabLevel = "tab.level";

		internal const string TabOptions = "tab.options";

		internal const string PlayersTarget = "players.target";

		internal const string PlayersFollowMe = "players.follow_me";

		internal const string PlayersUpgrades = "players.upgrades";

		internal const string PlayersTeleport = "players.teleport";

		internal const string PlayersDead = "players.dead";

		internal const string PlayersHost = "players.host";

		internal const string UpgradesLevel = "upgrades.level";

		internal const string UpgradesClearAll = "upgrades.clear_all";

		internal const string TeleportPlayerToMe = "teleport.player_to_me";

		internal const string TeleportPlayerTo = "teleport.player_to";

		internal const string TeleportGo = "teleport.go";

		internal const string TeleportMeToPlayer = "teleport.me_to_player";

		internal const string TeleportToTruck = "teleport.to_truck";

		internal const string TeleportToExtraction = "teleport.to_extraction";

		internal const string PlayerGodMode = "player.god_mode";

		internal const string PlayerInvisible = "player.invisible";

		internal const string PlayerInfiniteStamina = "player.infinite_stamina";

		internal const string PlayerFreeFlight = "player.free_flight";

		internal const string PlayerInfiniteAmmo = "player.infinite_ammo";

		internal const string PlayerOneShotEnemies = "player.one_shot_enemies";

		internal const string PlayerHeal = "player.heal";

		internal const string PlayerKill = "player.kill";

		internal const string PlayerRevive = "player.revive";

		internal const string SpawnItems = "spawn.items";

		internal const string SpawnValuables = "spawn.valuables";

		internal const string SpawnEnemies = "spawn.enemies";

		internal const string SpawnCosmeticBoxes = "spawn.cosmetic_boxes";

		internal const string SpawnCount = "spawn.count";

		internal const string SpawnTarget = "spawn.target";

		internal const string SpawnCountdown = "spawn.countdown";

		internal const string LevelSelect = "level.select";

		internal const string LevelCompleted = "level.completed";

		internal const string LevelShop = "level.shop";

		internal const string LevelMoney = "level.money";

		internal const string LevelFreeItems = "level.free_items";

		internal const string LevelExtractionOpen = "level.extraction_open";

		internal const string LevelExtractionComplete = "level.extraction_complete";

		internal const string LevelRevealValuables = "level.reveal_valuables";

		internal const string LevelRevealBoxes = "level.reveal_boxes";

		internal const string RarityCommon = "rarity.common";

		internal const string RarityUncommon = "rarity.uncommon";

		internal const string RarityRare = "rarity.rare";

		internal const string RarityUltraRare = "rarity.ultra_rare";

		internal const string SourceMod = "source.mod";

		internal const string CategoryLevels = "category.levels";

		internal const string CategoryShops = "category.shops";

		internal const string CategoryArenas = "category.arenas";

		internal const string CategorySpecial = "category.special";

		internal const string CategoryUpgrades = "category.upgrades";

		internal const string CategoryCosmeticBoxes = "category.cosmetic_boxes";

		internal const string CategoryDifficulty = "category.difficulty";

		internal const string ItemTypePrefix = "item_type.";

		internal const string ValuableSizePrefix = "valuable_size.";

		internal const string ValuableNamePrefix = "valuable.";

		internal const string ValuableThemePrefix = "valuable_theme.";

		internal const string LevelNamePrefix = "level_name.";

		internal const string ValuableNameFormat = "valuable_format";
	}
	internal static class Strings
	{
		internal static string Get(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return string.Empty;
			}
			string text = ActiveLocaleCode();
			if (StringTables.TryGet(text, key, out var text2))
			{
				return text2;
			}
			string text3 = BaseLocaleCode(text);
			if (text3 != null && StringTables.TryGet(text3, key, out text2))
			{
				return text2;
			}
			if (!StringTables.TryGet("en", key, out text2))
			{
				return key;
			}
			return text2;
		}

		internal static bool TryGetLocal(string key, out string text)
		{
			text = null;
			string localeCode = ActiveLocaleCode();
			if (!IsEnglish(localeCode))
			{
				return TryGetIn(localeCode, key, out text);
			}
			return false;
		}

		internal static bool TryGetIn(string localeCode, string key, out string text)
		{
			if (!StringTables.TryGet(localeCode, key, out text))
			{
				return StringTables.TryGet(BaseLocaleCode(localeCode), key, out text);
			}
			return true;
		}

		internal static bool IsEnglish(string localeCode)
		{
			return string.Equals(BaseLocaleCode(localeCode) ?? localeCode, "en", StringComparison.OrdinalIgnoreCase);
		}

		internal static string Format(string key, params object[] args)
		{
			string text = Get(key);
			try
			{
				return string.Format(text, args);
			}
			catch (FormatException)
			{
				Plugin.Log.LogWarning((object)("Text for \"" + key + "\" has a bad placeholder: " + text));
				return text;
			}
		}

		internal static string ForDisplay(string text)
		{
			if (!ArabicText.IsActive)
			{
				return text;
			}
			return ArabicText.ToVisual(text);
		}

		internal unsafe static string ForRarity(Rarity rarity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			return (int)rarity switch
			{
				0 => Get("rarity.common"), 
				1 => Get("rarity.uncommon"), 
				2 => Get("rarity.rare"), 
				3 => Get("rarity.ultra_rare"), 
				_ => GameText.Humanize(((object)(*(Rarity*)(&rarity))/*cast due to .constrained prefix*/).ToString()), 
			};
		}

		internal unsafe static string ForItemType(itemType type)
		{
			return ForEnum("item_type.", ((object)(*(itemType*)(&type))/*cast due to .constrained prefix*/).ToString());
		}

		internal unsafe static string ForValuableSize(Type size)
		{
			return ForEnum("valuable_size.", ((object)(*(Type*)(&size))/*cast due to .constrained prefix*/).ToString());
		}

		private static string ForEnum(string prefix, string valueName)
		{
			string text = prefix + valueName;
			string text2 = Get(text);
			if (!(text2 == text))
			{
				return text2;
			}
			return GameText.Humanize(valueName);
		}

		internal static string ActiveLocaleCode()
		{
			try
			{
				string text = SemiFunc.LocaleGetCode();
				return string.IsNullOrEmpty(text) ? "en" : text;
			}
			catch (Exception)
			{
				return "en";
			}
		}

		internal static LocaleAsset ActiveLocaleAsset()
		{
			try
			{
				LocalizationManager instance = LocalizationManager.instance;
				LocaleAsset value;
				return ((Object)(object)instance != (Object)null && instance.Locales.TryGetValue(ActiveLocaleCode(), out value)) ? value : null;
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static string BaseLocaleCode(string code)
		{
			if (string.IsNullOrEmpty(code))
			{
				return null;
			}
			int num = code.IndexOf('-');
			if (num <= 0)
			{
				return null;
			}
			return code.Substring(0, num);
		}
	}
	internal static class StringTables
	{
		internal const string FallbackLocaleCode = "en";

		private static readonly Dictionary<string, Dictionary<string, string>> Tables = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase) { ["en"] = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["menu.title"] = "Admin Menu",
			["menu.short"] = "Admin",
			["menu.close"] = "Close",
			["menu.back"] = "Back",
			["menu.search"] = "Search",
			["menu.host_only"] = "Only the host can use this menu.",
			["tab.players"] = "Players",
			["tab.spawn"] = "Spawn",
			["tab.level"] = "Level",
			["tab.options"] = "Options",
			["players.target"] = "Target",
			["players.follow_me"] = "Follow me",
			["players.upgrades"] = "Upgrades",
			["players.teleport"] = "Teleport",
			["players.dead"] = "dead",
			["players.host"] = "host",
			["upgrades.level"] = "Level",
			["upgrades.clear_all"] = "Remove all upgrades",
			["teleport.player_to_me"] = "Player to me",
			["teleport.player_to"] = "Send to",
			["teleport.go"] = "Teleport",
			["teleport.me_to_player"] = "Me to player",
			["teleport.to_truck"] = "To the truck",
			["teleport.to_extraction"] = "To the extraction point",
			["player.god_mode"] = "Immortality",
			["player.invisible"] = "Invisible to enemies",
			["player.infinite_stamina"] = "Infinite stamina",
			["player.free_flight"] = "Free flight",
			["player.infinite_ammo"] = "Infinite ammo",
			["player.one_shot_enemies"] = "One-shot enemies",
			["player.heal"] = "Heal",
			["player.kill"] = "Kill",
			["player.revive"] = "Revive",
			["spawn.items"] = "Shop items",
			["spawn.valuables"] = "Valuables",
			["spawn.enemies"] = "Enemies",
			["spawn.cosmetic_boxes"] = "Cosmetic boxes",
			["spawn.count"] = "Count",
			["spawn.target"] = "Spawn for",
			["spawn.countdown"] = "Spawning {0} in {1}",
			["level.select"] = "Change level",
			["level.completed"] = "Levels completed",
			["level.shop"] = "Shop",
			["level.money"] = "Money",
			["level.free_items"] = "Free items",
			["level.extraction_open"] = "Activate extraction point",
			["level.extraction_complete"] = "Complete extraction point",
			["level.reveal_valuables"] = "Reveal all valuables",
			["level.reveal_boxes"] = "Reveal all cosmetic boxes",
			["rarity.common"] = "Common",
			["rarity.uncommon"] = "Uncommon",
			["rarity.rare"] = "Rare",
			["rarity.ultra_rare"] = "Ultra rare",
			["source.mod"] = "mod",
			["category.levels"] = "Levels",
			["category.shops"] = "Shops",
			["category.arenas"] = "Arenas",
			["category.special"] = "Special",
			["category.upgrades"] = "Upgrades",
			["category.cosmetic_boxes"] = "Cosmetic boxes",
			["category.difficulty"] = "Difficulty {0}",
			["item_type.drone"] = "Drones",
			["item_type.orb"] = "Orbs",
			["item_type.cart"] = "Carts",
			["item_type.item_upgrade"] = "Item upgrades",
			["item_type.player_upgrade"] = "Player upgrades",
			["item_type.power_crystal"] = "Power crystals",
			["item_type.grenade"] = "Grenades",
			["item_type.melee"] = "Melee weapons",
			["item_type.healthPack"] = "Health packs",
			["item_type.gun"] = "Guns",
			["item_type.tracker"] = "Trackers",
			["item_type.mine"] = "Mines",
			["item_type.pocket_cart"] = "Pocket carts",
			["item_type.tool"] = "Tools",
			["item_type.vehicle"] = "Vehicles",
			["item_type.launcher"] = "Launchers",
			["valuable_size.Tiny"] = "Tiny",
			["valuable_size.Small"] = "Small",
			["valuable_size.Medium"] = "Medium",
			["valuable_size.Big"] = "Big",
			["valuable_size.Wide"] = "Wide",
			["valuable_size.Tall"] = "Tall",
			["valuable_size.VeryTall"] = "Very tall",
			["valuable_format"] = "{1} {0}"
		} };

		internal static IReadOnlyDictionary<string, string> Fallback => Tables["en"];

		internal static IEnumerable<string> LocaleCodes => Tables.Keys;

		internal static bool TryGet(string localeCode, string key, out string text)
		{
			text = null;
			if (!string.IsNullOrEmpty(localeCode) && Tables.TryGetValue(localeCode, out var value) && value.TryGetValue(key, out text))
			{
				return !string.IsNullOrEmpty(text);
			}
			return false;
		}

		internal static void Merge(string localeCode, Dictionary<string, string> entries)
		{
			if (string.IsNullOrEmpty(localeCode) || entries == null || entries.Count == 0)
			{
				return;
			}
			if (!Tables.TryGetValue(localeCode, out var value))
			{
				value = new Dictionary<string, string>(StringComparer.Ordinal);
				Tables[localeCode] = value;
			}
			foreach (KeyValuePair<string, string> entry in entries)
			{
				if (!string.IsNullOrEmpty(entry.Key) && !string.IsNullOrEmpty(entry.Value))
				{
					value[entry.Key] = entry.Value;
				}
			}
		}
	}
}
namespace AdminMenu.Interop
{
	internal static class AdminNetwork
	{
		private const string EventName = "AdminMenu Player Flag";

		private static object _event;

		private static bool _tried;

		internal static bool Available => Event() != null;

		internal static void Initialize()
		{
			Event();
		}

		internal static void Send(string steamId, AdminFlag flag, bool state)
		{
			if (string.IsNullOrEmpty(steamId))
			{
				return;
			}
			object obj = Event();
			if (obj == null)
			{
				return;
			}
			try
			{
				Raise(obj, new object[3]
				{
					steamId,
					(byte)flag,
					state
				});
				Plugin.LogVerbose($"Sent {flag}={state} for {steamId}.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)$"Could not send {flag} for {steamId}. {ex.Message}");
			}
		}

		private static void Raise(object channel, object content)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			((NetworkedEvent)channel).RaiseEvent(content, NetworkingEvents.RaiseAll, SendOptions.SendReliable);
		}

		private static object Event()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			if (_tried)
			{
				return _event;
			}
			_tried = true;
			if (!RepoLibBridge.Available)
			{
				Plugin.Log.LogWarning((object)"REPOLib is not installed, so abilities granted to other players cannot be sent to them.");
				return null;
			}
			try
			{
				_event = (object)new NetworkedEvent("AdminMenu Player Flag", (Action<EventData>)Handle);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not open the admin channel. " + ex.Message));
				_event = null;
			}
			return _event;
		}

		private static void Handle(EventData data)
		{
			try
			{
				if (data.CustomData is object[] array && array.Length >= 3)
				{
					string text = array[0] as string;
					if (!string.IsNullOrEmpty(text) && IsLocal(text))
					{
						AdminFlags.ApplyLocally((AdminFlag)Convert.ToByte(array[1]), Convert.ToBoolean(array[2]));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read an admin message. " + ex.Message));
			}
		}

		private static bool IsLocal(string steamId)
		{
			PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
			if ((Object)(object)val != (Object)null)
			{
				return string.Equals(SemiFunc.PlayerGetSteamID(val), steamId, StringComparison.Ordinal);
			}
			return false;
		}
	}
	internal static class ExtractionAccess
	{
		private static readonly FieldInfo PointActiveField = AccessTools.Field(typeof(RoundDirector), "extractionPointActive");

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

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

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

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

		private static readonly MethodInfo StateSetMethod = AccessTools.Method(typeof(ExtractionPoint), "StateSet", new Type[1] { typeof(State) }, (Type[])null);

		private static readonly HashSet<string> Reported = new HashSet<string>(StringComparer.Ordinal);

		internal static bool IsPointActive()
		{
			RoundDirector instance = RoundDirector.instance;
			bool flag = default(bool);
			int num;
			if ((Object)(object)instance != (Object)null)
			{
				object obj = Read(PointActiveField, instance, "RoundDirector.extractionPointActive");
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		internal static ExtractionPoint CurrentPoint()
		{
			RoundDirector instance = RoundDirector.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				object obj = Read(PointCurrentField, instance, "RoundDirector.extractionPointCurrent");
				return (ExtractionPoint)((obj is ExtractionPoint) ? obj : null);
			}
			return null;
		}

		internal static List<ExtractionPoint> AllPoints()
		{
			List<ExtractionPoint> list = new List<ExtractionPoint>();
			RoundDirector instance = RoundDirector.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return list;
			}
			if (!(Read(PointListField, instance, "RoundDirector.extractionPointList") is IEnumerable<GameObject> enumerable))
			{
				return list;
			}
			foreach (GameObject item in enumerable)
			{
				ExtractionPoint val = ((item != null) ? item.GetComponent<ExtractionPoint>() : null);
				if ((Object)(object)val != (Object)null)
				{
					list.Add(val);
				}
			}
			return list;
		}

		internal static bool TryGetState(ExtractionPoint point, out State state)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected I4, but got Unknown
			state = (State)0;
			if ((Object)(object)point == (Object)null)
			{
				return false;
			}
			if (!(Read(PointStateField, point, "ExtractionPoint.currentState") is State val))
			{
				return false;
			}
			state = (State)(int)val;
			return true;
		}

		internal static bool SetCompletedRightAway(ExtractionPoint point, bool value)
		{
			if ((Object)(object)point == (Object)null || CompletedRightAwayField == null)
			{
				ReportMissing("ExtractionPoint.isCompletedRightAway");
				return false;
			}
			try
			{
				CompletedRightAwayField.SetValue(point, value);
				return true;
			}
			catch (Exception ex)
			{
				ReportMissing("ExtractionPoint.isCompletedRightAway", ex);
				return false;
			}
		}

		internal static bool SetState(ExtractionPoint point, State state)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)point == (Object)null || StateSetMethod == null)
			{
				ReportMissing("ExtractionPoint.StateSet");
				return false;
			}
			try
			{
				StateSetMethod.Invoke(point, new object[1] { state });
				return true;
			}
			catch (Exception ex)
			{
				ReportMissing("ExtractionPoint.StateSet", ex);
				return false;
			}
		}

		private static object Read(FieldInfo field, object instance, string name)
		{
			if (field == null)
			{
				ReportMissing(name);
				return null;
			}
			try
			{
				return field.GetValue(instance);
			}
			catch (Exception ex)
			{
				ReportMissing(name, ex);
				return null;
			}
		}

		private static void ReportMissing(string name, Exception ex = null)
		{
			if (Reported.Add(name))
			{
				Plugin.Log.LogWarning((object)(name + " could not be reached, so the extraction point controls will not work. " + ((ex == null) ? string.Empty : (ex.GetType().Name + ": " + ex.Message))));
			}
		}
	}
	internal static class PlayerAvatarAccess
	{
		private static readonly FieldInfo DeadSetField = AccessTools.Field(typeof(PlayerAvatar), "deadSet");

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

		private static readonly FieldInfo SpectatingField = AccessTools.Field(typeof(PlayerAvatar), "spectating");

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

		private static readonly FieldInfo SpectatedPlayerField = AccessTools.Field(typeof(SpectateCamera), "player");

		private static readonly FieldInfo TumbleField = AccessTools.Field(typeof(PlayerAvatar), "tumble");

		private static readonly FieldInfo TumblePhysObjectField = AccessTools.Field(typeof(PlayerTumble), "physGrabObject");

		private static readonly FieldInfo HeadPhysObjectField = AccessTools.Field(typeof(PlayerDeathHead), "physGrabObject");

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

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

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

		private static readonly HashSet<string> Reported = new HashSet<string>(StringComparer.Ordinal);

		internal static bool IsDead(PlayerAvatar player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return ReadBool(DeadSetField, player, "PlayerAvatar.deadSet");
			}
			return false;
		}

		internal static bool IsDisabled(PlayerAvatar player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return ReadBool(IsDisabledField, player, "PlayerAvatar.isDisabled");
			}
			return false;
		}

		internal static bool IsSpectating(PlayerAvatar player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return ReadBool(SpectatingField, player, "PlayerAvatar.spectating");
			}
			return false;
		}

		internal static PlayerDeathHead GetDeathHead(PlayerAvatar player)
		{
			if ((Object)(object)player == (Object)null || DeathHeadField == null)
			{
				ReportMissing("PlayerAvatar.playerDeathHead");
				return null;
			}
			try
			{
				object? value = DeathHeadField.GetValue(player);
				return (PlayerDeathHead)((value is PlayerDeathHead) ? value : null);
			}
			catch (Exception ex)
			{
				ReportMissing("PlayerAvatar.playerDeathHead", ex);
				return null;
			}
		}

		internal static PlayerAvatar GetSpectatedPlayer()
		{
			SpectateCamera instance = SpectateCamera.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if (SpectatedPlayerField == null)
			{
				ReportMissing("SpectateCamera.player");
				return null;
			}
			try
			{
				object? value = SpectatedPlayerField.GetValue(instance);
				return (PlayerAvatar)((value is PlayerAvatar) ? value : null);
			}
			catch (Exception ex)
			{
				ReportMissing("SpectateCamera.player", ex);
				return null;
			}
		}

		internal static PhysGrabObject GetHeadPhysObject(PlayerAvatar player)
		{
			PlayerDeathHead deathHead = GetDeathHead(player);
			if (!((Object)(object)deathHead == (Object)null))
			{
				object obj = Read(HeadPhysObjectField, deathHead, "PlayerDeathHead.physGrabObject");
				return (PhysGrabObject)((obj is PhysGrabObject) ? obj : null);
			}
			return null;
		}

		internal static PhysGrabObject GetTumblePhysObject(PlayerAvatar player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			object obj = Read(TumbleField, player, "PlayerAvatar.tumble");
			if (obj != null)
			{
				object obj2 = Read(TumblePhysObjectField, obj, "PlayerTumble.physGrabObject");
				return (PhysGrabObject)((obj2 is PhysGrabObject) ? obj2 : null);
			}
			return null;
		}

		internal static int GetMaxHealth(PlayerAvatar player)
		{
			if ((Object)(object)player?.playerHealth == (Object)null)
			{
				return 0;
			}
			object obj = Read(MaxHealthField, player.playerHealth, "PlayerHealth.maxHealth");
			if (obj is int)
			{
				return (int)obj;
			}
			return 0;
		}

		internal static int GetHealth(PlayerAvatar player)
		{
			if ((Object)(object)player?.playerHealth == (Object)null)
			{
				return 0;
			}
			object obj = Read(HealthField, player.playerHealth, "PlayerHealth.health");
			if (obj is int)
			{
				return (int)obj;
			}
			return 0;
		}

		internal static bool GetGodMode(PlayerAvatar player)
		{
			if ((Object)(object)player?.playerHealth == (Object)null)
			{
				return false;
			}
			object obj = Read(GodModeField, player.playerHealth, "PlayerHealth.godMode");
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		internal static bool SetGodMode(PlayerAvatar player, bool value)
		{
			if ((Object)(object)player?.playerHealth == (Object)null || GodModeField == null)
			{
				ReportMissing("PlayerHealth.godMode");
				return false;
			}
			try
			{
				GodModeField.SetValue(player.playerHealth, value);
				return true;
			}
			catch (Exception ex)
			{
				ReportMissing("PlayerHealth.godMode", ex);
				return false;
			}
		}

		private static object Read(FieldInfo field, object instance, string name)
		{
			if (field == null)
			{
				ReportMissing(name);
				return null;
			}
			try
			{
				return field.GetValue(instance);
			}
			catch (Exception ex)
			{
				ReportMissing(name, ex);
				return null;
			}
		}

		private static bool ReadBool(FieldInfo field, object instance, string name)
		{
			if (field == null)
			{
				ReportMissing(name);
				return false;
			}
			try
			{
				return (bool)field.GetValue(instance);
			}
			catch (Exception ex)
			{
				ReportMissing(name, ex);
				return false;
			}
		}

		private static void ReportMissing(string name, Exception ex = null)
		{
			if (Reported.Add(name))
			{
				Plugin.Log.LogWarning((object)(name + " could not be reached, so the menu will treat it as unset. " + ((ex == null) ? string.Empty : (ex.GetType().Name + ": " + ex.Message))));
			}
		}
	}
	internal static class PunBridge
	{
		internal static bool CanAct => SemiFunc.IsMasterClientOrSingleplayer();

		internal static bool ApplyVanillaUpgradeDelta(string steamId, string upgradeName, int delta)
		{
			if (string.IsNullOrEmpty(steamId) || string.IsNullOrEmpty(upgradeName) || delta == 0)
			{
				return false;
			}
			return SendRpc("TesterUpgradeCommandRPC", steamId, upgradeName, delta);
		}

		internal static bool SetNoAggro(string steamId, bool state)
		{
			if (string.IsNullOrEmpty(steamId))
			{
				return false;
			}
			return SendRpc("TesterNoAggroCommandRPC", steamId, state);
		}

		internal static bool SetRunStat(string statName, int value)
		{
			if (string.IsNullOrEmpty(statName) || (Object)(object)PunManager.instance == (Object)null)
			{
				return false;
			}
			try
			{
				PunManager.instance.SetRunStatSet(statName, value);
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not set run stat '{statName}' to {value}. {arg}");
				return false;
			}
		}

		internal static void SyncAllDictionaries()
		{
			if ((Object)(object)PunManager.instance == (Object)null || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			try
			{
				PunManager.instance.SyncAllDictionaries();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not sync the stat dictionaries. {arg}");
			}
		}

		private static bool SendRpc(string methodName, params object[] args)
		{
			PunManager instance = PunManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				Plugin.Log.LogWarning((object)("No PunManager yet, so '" + methodName + "' was dropped."));
				return false;
			}
			try
			{
				if (!SemiFunc.IsMultiplayer())
				{
					InvokeLocally(instance, methodName, args);
					return true;
				}
				PhotonView component = ((Component)instance).GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null)
				{
					Plugin.Log.LogWarning((object)("PunManager carries no PhotonView, so '" + methodName + "' was d