using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zorro.Core; [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("PEAKQuickResume")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0+5e090d0cade98bc70c00c8010589562ffca17a0f")] [assembly: AssemblyProduct("PEAKQuickResume")] [assembly: AssemblyTitle("PEAKQuickResume")] [assembly: AssemblyVersion("0.3.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 PEAKQuickResume { public class CheckpointInterop { private readonly ManualLogSource _log; private Type _pluginType; private FieldInfo _instanceField; private FieldInfo _selectedAscentField; private FieldInfo _currentlyLoadingField; private MethodInfo _preStartSetSegment; private MethodInfo _loadPlayerOffline; private MethodInfo _loadPlayerCoop; private MethodInfo _showMessage; private MethodInfo _checkReadyStatus; private FieldInfo _readyCheckConfigField; private bool _resolved; public bool IsAvailable => _resolved; public Type CheckpointType => _pluginType; private object Instance => _instanceField?.GetValue(null); public bool IsCurrentlyLoading { get { try { return _currentlyLoadingField != null && (bool)_currentlyLoadingField.GetValue(Instance); } catch { return false; } } } public CheckpointInterop(ManualLogSource log) { _log = log; } public bool Probe() { try { _pluginType = AccessTools.TypeByName("PEAK_Checkpoint_Save.Plugin"); if (_pluginType == null) { _log.LogWarning((object)"Checkpoint mod type 'PEAK_Checkpoint_Save.Plugin' not found. Is 'PEAK Checkpoint Save' installed and loaded? Quick Resume will be inert."); _resolved = false; return false; } _instanceField = AccessTools.Field(_pluginType, "Instance"); _selectedAscentField = AccessTools.Field(_pluginType, "selectedAscent"); _currentlyLoadingField = AccessTools.Field(_pluginType, "currentlyLoading"); _preStartSetSegment = AccessTools.Method(_pluginType, "PreStartSetSegment", (Type[])null, (Type[])null); _loadPlayerOffline = AccessTools.Method(_pluginType, "LoadPlayerOffline", (Type[])null, (Type[])null); _loadPlayerCoop = AccessTools.Method(_pluginType, "LoadPlayerCoop", (Type[])null, (Type[])null); _showMessage = AccessTools.Method(_pluginType, "ShowMessage", new Type[4] { typeof(string), typeof(Color), typeof(float), typeof(bool) }, (Type[])null); _checkReadyStatus = AccessTools.Method(_pluginType, "CheckReadyStatusForPlayers", (Type[])null, (Type[])null); _readyCheckConfigField = AccessTools.Field(_pluginType, "configAdvancedEnableClientReadyStatusCheck"); _log.LogInfo((object)"Checkpoint interop probe:"); _log.LogInfo((object)(" Instance field ....... " + ((_instanceField != null) ? "OK" : "MISSING"))); _log.LogInfo((object)(" selectedAscent ....... " + ((_selectedAscentField != null) ? "OK" : "MISSING"))); _log.LogInfo((object)(" currentlyLoading ..... " + ((_currentlyLoadingField != null) ? "OK" : "MISSING (non-fatal)"))); _log.LogInfo((object)(" PreStartSetSegment ... " + ((_preStartSetSegment != null) ? "OK" : "MISSING"))); _log.LogInfo((object)(" LoadPlayerOffline .... " + ((_loadPlayerOffline != null) ? "OK" : "MISSING"))); _log.LogInfo((object)(" LoadPlayerCoop ....... " + ((_loadPlayerCoop != null) ? "OK" : "MISSING"))); _log.LogInfo((object)(" ShowMessage .......... " + ((_showMessage != null) ? "OK" : "MISSING (non-fatal, on-screen text only)"))); _log.LogInfo((object)(" CheckReadyStatus ..... " + ((_checkReadyStatus != null) ? "OK" : "MISSING (non-fatal, coop readiness)"))); _log.LogInfo((object)(" readyStatusConfig .... " + ((_readyCheckConfigField != null) ? "OK" : "MISSING (non-fatal, coop readiness)"))); _resolved = _instanceField != null && _selectedAscentField != null && _preStartSetSegment != null && _loadPlayerOffline != null && _loadPlayerCoop != null; if (!_resolved) { _log.LogError((object)"One or more required checkpoint members are missing, the checkpoint mod likely changed. See docs/RESEARCH.md and update CheckpointInterop.cs."); } return _resolved; } catch (Exception arg) { _log.LogError((object)$"Checkpoint interop probe threw: {arg}"); _resolved = false; return false; } } public bool TrySetSelectedAscent(int ascent) { try { object instance = Instance; if (instance == null) { _log.LogError((object)"Checkpoint Instance is null (mod not initialized yet?)."); return false; } _selectedAscentField.SetValue(instance, ascent); return true; } catch (Exception arg) { _log.LogError((object)$"TrySetSelectedAscent failed: {arg}"); return false; } } public bool TryPreStartSetSegment() { try { object instance = Instance; if (instance == null) { _log.LogError((object)"Checkpoint Instance is null."); return false; } object obj = _preStartSetSegment.Invoke(instance, null); 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; } catch (Exception arg) { _log.LogError((object)$"TryPreStartSetSegment failed: {arg}"); return false; } } public bool TryLoadPlayer() { try { object instance = Instance; if (instance == null) { _log.LogError((object)"Checkpoint Instance is null."); return false; } if (PhotonNetwork.OfflineMode) { _loadPlayerOffline.Invoke(instance, null); } else { _loadPlayerCoop.Invoke(instance, null); } return true; } catch (Exception arg) { _log.LogError((object)$"TryLoadPlayer failed: {arg}"); return false; } } public bool ReadyCheckEnabled() { try { if (_readyCheckConfigField == null) { return true; } object value = _readyCheckConfigField.GetValue(Instance); if (value == null) { return true; } return !(value.GetType().GetProperty("Value")?.GetValue(value) is bool flag) || flag; } catch { return true; } } public bool AllClientsReady() { try { if (_checkReadyStatus == null) { return true; } return !(_checkReadyStatus.Invoke(Instance, null) is bool flag) || flag; } catch (Exception ex) { _log.LogWarning((object)("AllClientsReady failed (assuming ready): " + ex.Message)); return true; } } public void TryShowMessage(string text, Color color, float duration = 2.5f) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) try { object instance = Instance; if (instance != null && !(_showMessage == null)) { _showMessage.Invoke(instance, new object[4] { text, color, duration, false }); } } catch (Exception ex) { _log.LogWarning((object)("TryShowMessage failed (non-fatal): " + ex.Message)); } } } internal enum ButtonLabel { Restart, ReturnToAirport } internal enum ConfirmDialog { Restart, ReturnToAirport } internal static class PauseMenuLocalization { private static readonly Dictionary _table = new Dictionary { [ButtonLabel.Restart] = new string[15] { "RESTART", "REDÉMARRER", "RIAVVIA", "NEUSTART", "REINICIAR", "REINICIAR", "REINICIAR", "ПЕРЕЗАПУСК", "ПЕРЕЗАПУСК", "重新开始", "", "リスタート", "재시작", "RESTART", "YENİDEN BAŞLAT" }, [ButtonLabel.ReturnToAirport] = new string[15] { "RETURN TO AIRPORT", "RETOUR À L'AÉROPORT", "TORNA ALL'AEROPORTO", "ZURÜCK ZUM FLUGHAFEN", "VOLVER AL AEROPUERTO", "VOLVER AL AEROPUERTO", "VOLTAR AO AEROPORTO", "ВЕРНУТЬСЯ В АЭРОПОРТ", "ПОВЕРНУТИСЯ В АЕРОПОРТ", "返回机场", "", "空港に戻る", "공항으로 돌아가기", "WRÓĆ NA LOTNISKO", "HAVAALANINA DÖN" } }; private static readonly Dictionary _dialogTable = new Dictionary { [ConfirmDialog.Restart] = new string[15] { "Restart this run? Everyone will return to the Airport and a fresh run of the same difficulty will start immediately (no checkpoint will be loaded).", "Recommencer cette partie ? Tout le monde retournera à l'aéroport et une nouvelle partie de la même difficulté commencera immédiatement (aucune sauvegarde ne sera chargée).", "Riavviare questa partita? Tutti torneranno all'aeroporto e una nuova partita della stessa difficoltà inizierà immediatamente (nessun checkpoint verrà caricato).", "Diesen Lauf neu starten? Alle kehren zum Flughafen zurück und ein neuer Lauf mit demselben Schwierigkeitsgrad beginnt sofort (es wird kein Speicherstand geladen).", "¿Reiniciar esta partida? Todos volverán al aeropuerto y comenzará de inmediato una nueva partida de la misma dificultad (no se cargará ningún punto de guardado).", "¿Reiniciar esta partida? Todos volverán al aeropuerto y comenzará de inmediato una nueva partida de la misma dificultad (no se cargará ningún punto de guardado).", "Reiniciar esta corrida? Todos vão voltar para o Aeroporto e uma nova corrida da mesma dificuldade vai começar imediatamente (nenhum checkpoint será carregado).", "Перезапустить этот забег? Все вернутся в аэропорт, и сразу начнётся новый забег той же сложности (сохранение не будет загружено).", "Перезапустити цей забіг? Усі повернуться в аеропорт, і одразу почнеться новий забіг тієї ж складності (збереження не буде завантажено).", "重新开始本局游戏?所有人将返回机场,并立即开始相同难度的新一局(不会加载任何存档)。", "", "このランを再開始しますか?全員が空港に戻り、同じ難易度の新しいランがすぐに始まります(チェックポイントは読み込まれません)。", "이번 런을 재시작하시겠습니까? 모두 공항으로 돌아가고 동일한 난이도의 새로운 런이 즉시 시작됩니다 (체크포인트는 불러오지 않습니다).", "Zrestartować ten przebieg? Wszyscy wrócą na lotnisko i natychmiast rozpocznie się nowy przebieg tej samej trudności (żaden zapis nie zostanie wczytany).", "Bu koşuyu yeniden başlat? Herkes Havaalanı'na dönecek ve aynı zorlukta yeni bir koşu hemen başlayacak (herhangi bir kayıt yüklenmeyecek)." }, [ConfirmDialog.ReturnToAirport] = new string[15] { "Return everyone to the Airport now?", "Renvoyer tout le monde à l'aéroport maintenant ?", "Riportare tutti all'aeroporto ora?", "Jetzt alle zum Flughafen zurückbringen?", "¿Volver todos al aeropuerto ahora?", "¿Volver todos al aeropuerto ahora?", "Voltar todos para o Aeroporto agora?", "Вернуть всех в аэропорт сейчас?", "Повернути всіх в аеропорт зараз?", "现在让所有人返回机场?", "", "今すぐ全員を空港に戻しますか?", "지금 모두를 공항으로 돌려보내시겠습니까?", "Odesłać teraz wszystkich na lotnisko?", "Herkes şimdi Havaalanı'na döndürülsün mü?" } }; public static string Get(ButtonLabel label) { return Resolve(_table[label]); } public static string Get(ConfirmDialog dialog) { return Resolve(_dialogTable[dialog]); } private static string Resolve(string[] arr) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected I4, but got Unknown int num = (int)LocalizedText.CURRENT_LANGUAGE; if (num >= 0 && num < arr.Length && !string.IsNullOrEmpty(arr[num])) { return arr[num]; } return arr[0]; } } public static class PauseMenuPatch { private class ButtonEntry { public GameObject GameObject; public TextMeshProUGUI Text; public Func Localize; } private class Buttons { public ButtonEntry Restart; public ButtonEntry ReturnToAirport; public ButtonEntry OpenKiosk; } private static ManualLogSource _log; private static PluginConfig _cfg; private static MethodInfo _windowOpen; private static MethodInfo _windowClose; private static FieldInfo _templateButtonField; private static FieldInfo _quitButtonField; private static FieldInfo _confirmOkField; private static FieldInfo _confirmCancelField; private static readonly ConditionalWeakTable _built = new ConditionalWeakTable(); public static void Apply(Harmony harmony, PluginConfig cfg, ManualLogSource log) { //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown _log = log; _cfg = cfg; try { _windowOpen = AccessTools.Method(typeof(MenuWindow), "Open", (Type[])null, (Type[])null); _windowClose = AccessTools.Method(typeof(MenuWindow), "Close", (Type[])null, (Type[])null); _templateButtonField = AccessTools.Field(typeof(PauseMenuMainPage), "m_accoladesButton"); _quitButtonField = AccessTools.Field(typeof(PauseMenuMainPage), "m_quitButton"); _confirmOkField = AccessTools.Field(typeof(PauseMenuMainPage), "m_confirmOkButton"); _confirmCancelField = AccessTools.Field(typeof(PauseMenuMainPage), "m_confirmCancelButton"); if (_windowOpen == null || _windowClose == null || _templateButtonField == null || _quitButtonField == null || _confirmOkField == null || _confirmCancelField == null) { log.LogWarning((object)"PauseMenuPatch: one or more pause menu members not found; Restart / Return to Airport / Board Flight buttons will not be added. The pause menu itself is unaffected."); return; } MethodInfo methodInfo = AccessTools.Method(typeof(PauseMenuMainPage), "Start", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PauseMenuMainPage), "OnEnable", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(PauseMenuPatch), "StartPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(PauseMenuPatch), "OnEnablePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"PauseMenuPatch: patched PauseMenuMainPage.Start/OnEnable (Restart / Return to Airport / Board Flight buttons)."); } catch (Exception arg) { log.LogError((object)$"PauseMenuPatch.Apply failed (non-fatal, pause menu unaffected): {arg}"); } } private static void StartPostfix(PauseMenuMainPage __instance) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown try { if (_built.TryGetValue(__instance, out var _)) { return; } Button val = (Button)_templateButtonField.GetValue(__instance); Button val2 = (Button)_quitButtonField.GetValue(__instance); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { _log.LogWarning((object)"PauseMenuPatch: template/anchor button missing on this instance; skipping."); return; } Transform parent = ((Component)val).transform.parent; int siblingIndex = ((Component)val2).transform.GetSiblingIndex(); Buttons buttons = new Buttons { Restart = MakeButton(val, parent, siblingIndex++, (Func)(() => PauseMenuLocalization.Get(ButtonLabel.Restart)), (UnityAction)delegate { OnRestartClicked(__instance); }, (Color?)new Color(0.8f, 0.2f, 0.15f)), ReturnToAirport = MakeButton(val, parent, siblingIndex++, (Func)(() => PauseMenuLocalization.Get(ButtonLabel.ReturnToAirport)), (UnityAction)delegate { OnReturnToAirportClicked(__instance); }, (Color?)new Color(0.12f, 0.55f, 0.58f)), OpenKiosk = MakeButton(val, parent, siblingIndex++, () => LocalizedText.GetText("BOARDFLIGHT", true).ToUpperInvariant(), (UnityAction)delegate { OnOpenKioskClicked(__instance); }) }; _built.Add(__instance, buttons); RectTransform val3 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (val3 != null) { LayoutRebuilder.ForceRebuildLayoutImmediate(val3); } UpdateVisibility(buttons); } catch (Exception arg) { _log.LogError((object)$"PauseMenuPatch.StartPostfix failed (non-fatal): {arg}"); } } private static void OnEnablePostfix(PauseMenuMainPage __instance) { try { if (_built.TryGetValue(__instance, out var value)) { UpdateVisibility(value); } } catch (Exception arg) { _log.LogError((object)$"PauseMenuPatch.OnEnablePostfix failed (non-fatal): {arg}"); } } private static void UpdateVisibility(Buttons b) { bool flag = RunLauncher.IsHost && RunLauncher.InLevel; SetActiveAndRefresh(b.Restart, flag && _cfg.ShowRestartButton.Value); SetActiveAndRefresh(b.ReturnToAirport, flag && _cfg.ShowReturnToAirportButton.Value); SetActiveAndRefresh(b.OpenKiosk, RunLauncher.InAirport && _cfg.ShowBoardFlightButton.Value); } private static void SetActiveAndRefresh(ButtonEntry entry, bool active) { entry.GameObject.SetActive(active); if (active && (Object)(object)entry.Text != (Object)null) { ((TMP_Text)entry.Text).text = entry.Localize(); } } private static ButtonEntry MakeButton(Button template, Transform parent, int siblingIndex, Func localize, UnityAction onClick, Color? bannerColor = null) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) string text = localize(); GameObject val = Object.Instantiate(((Component)template).gameObject, parent); ((Object)val).name = "PEAKQuickResume_" + text.Replace(" ", ""); val.transform.SetSiblingIndex(siblingIndex); Button component = val.GetComponent