Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AdminMenu v1.0.0
AdminMenu.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
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