using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Logging; using Dropper; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 DropperPeakLevelSelectSwitcher { [BepInPlugin("com.github.Beast.Dropper.PeakLevelSelectSwitcher", "Dropper PeakLevelSelect Switcher", "1.1.12")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class SwitcherPlugin : BaseUnityPlugin { public const string PluginGuid = "com.github.Beast.Dropper.PeakLevelSelectSwitcher"; public const string PluginName = "Dropper PeakLevelSelect Switcher"; public const string PluginVersion = "1.1.12"; internal static ManualLogSource Log; internal static SwitcherPlugin Instance; private SwitcherPhotonCallbacks photonCallbacks; private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; DropperText.Install(); Harmony.CreateAndPatchAll(typeof(BoardingPassSwitcher), "com.github.Beast.Dropper.PeakLevelSelectSwitcher"); BoardingPassSwitcher.InstallManualPatches(); photonCallbacks = new SwitcherPhotonCallbacks(); PhotonNetwork.AddCallbackTarget((object)photonCallbacks); Log.LogInfo((object)"Dropper/PeakLevelSelect boarding pass switcher loaded."); } private void OnDestroy() { if (photonCallbacks != null) { PhotonNetwork.RemoveCallbackTarget((object)photonCallbacks); photonCallbacks = null; } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } } internal sealed class SwitcherPhotonCallbacks : IInRoomCallbacks, IMatchmakingCallbacks { public void OnJoinedRoom() { BoardingPassSwitcher.OnJoinedRoom(); } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { BoardingPassSwitcher.OnRoomPropertiesUpdate(propertiesThatChanged); } public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { BoardingPassSwitcher.OnPlayerPropertiesUpdate(targetPlayer, changedProps); } public void OnPlayerEnteredRoom(Player newPlayer) { BoardingPassSwitcher.OnPlayerEnteredRoom(newPlayer); } public void OnPlayerLeftRoom(Player otherPlayer) { } public void OnMasterClientSwitched(Player newMasterClient) { } public void OnFriendListUpdate(List friendList) { } public void OnCreatedRoom() { BoardingPassSwitcher.OnJoinedRoom(); } public void OnCreateRoomFailed(short returnCode, string message) { } public void OnJoinRoomFailed(short returnCode, string message) { } public void OnJoinRandomFailed(short returnCode, string message) { } public void OnLeftRoom() { BoardingPassSwitcher.OnLeftRoom(); } } internal static class DropperText { private const int ChineseLanguageIndex = 9; public static bool IsChinese { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 try { return (int)LocalizedText.CURRENT_LANGUAGE == 9; } catch { return false; } } } public static string Choose(string english, string chinese) { if (!IsChinese) { return english; } return chinese; } public static void Install() { Set("Name_Reset", "Resetter", "重置器"); Set("Force reset on #targetchar", "force reset #targetchar", "强制重置 #targetchar"); Set("Name_Instant Health I", "Instant Health I", "瞬间治疗 I"); Set("administer #targetchar", "administer #targetchar", "使用于 #targetchar"); Set("Dropper", "Dropper", "坠落挑战"); Set("Immense dread", "Immense dread", "无尽恐惧"); Set("Desc_Dropper", "Does falling from 50 meters and crushing all your bones hurt? YES! But the adrenaline keeps you alive and ready to hit the portal next time!", "从 50 米高空坠落并摔碎全身骨头会痛吗?当然会!但肾上腺素会让你活下来,准备好下一次冲进传送门!"); Set("Dropper - Descend", "Dropper - Descent", "坠落挑战 - 下降"); Set("Desc_Dropper - Descend", "Instead of doing it all in one jump, how about we mix it up with some parkour to climb down. Why would you do that? Well let's finish the first map an you will see why", "不再一次跳到底,而是加入一些跑酷向下推进。为什么要这样做?先完成第一张地图,你就会明白。"); } private static void Set(string key, string english, string chinese) { List list = new List(); for (int i = 0; i < 15; i++) { list.Add(english); } list[9] = chinese; LocalizedText.mainTable[key.ToUpperInvariant()] = list; } } [HarmonyAfter(new string[] { "PeakLevelSelect", "com.github.Beast.Dropper" })] internal static class BoardingPassSwitcher { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__107_0; public static UnityAction <>9__107_1; internal void b__107_0() { useDropperControls = !useDropperControls; SwitcherPlugin.Log.LogInfo((object)("Dropper feature switch clicked. Dropper controls: " + useDropperControls)); if (!useDropperControls) { ApplyDropperToggle(-1); PublishDropperOffSelection(); } if ((Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.boardingPass != (Object)null) { if (useDropperControls) { ClampAscentIndex(GUIManager.instance.boardingPass); } Refresh(GUIManager.instance.boardingPass); } } internal void b__107_1() { dropperMode = ((dropperMode == 0) ? 1 : 0); SwitcherPlugin.Log.LogInfo((object)("Dropper mode switch clicked. Mode: " + dropperMode)); if ((Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.boardingPass != (Object)null) { Refresh(GUIManager.instance.boardingPass); } } } [CompilerGenerated] private sealed class d__163 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string source; private float 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__163(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(4f); <>1__state = 1; return true; case 1: <>1__state = -1; 5__2 = Time.realtimeSinceStartup + 12f; break; case 2: <>1__state = -1; break; case 3: <>1__state = -1; dropperMapActivationRunning = false; ScheduleDropperSpawnRecovery("map activation after " + source); return false; } if (Time.realtimeSinceStartup < 5__2) { if (!IsDropperModeActive()) { dropperMapActivationRunning = false; return false; } if (IsDropperMapBuilt()) { dropperMapActivationRunning = false; ScheduleDropperSpawnRecovery("map already active after " + source); return false; } if (!IsGameplaySceneForDropperBuild() || (Object)(object)GameObject.Find("Map") == (Object)null || (Object)(object)GameObject.Find("GAME") == (Object)null) { <>2__current = null; <>1__state = 2; return true; } IEnumerator enumerator = null; try { enumerator = AccessTools.Method(AccessTools.TypeByName("Dropper.HarmonyPatches"), "DelayedActivation", (Type[])null, (Type[])null)?.Invoke(null, null) as IEnumerator; } catch (Exception ex) { SwitcherPlugin.Log.LogWarning((object)("Failed to start Dropper map activation after " + source + ": " + ex.Message)); } if (enumerator == null) { dropperMapActivationRunning = false; return false; } SwitcherPlugin.Log.LogInfo((object)("Running Dropper map activation after late room mode sync from " + source + ".")); <>2__current = ((MonoBehaviour)SwitcherPlugin.Instance).StartCoroutine(enumerator); <>1__state = 3; return true; } dropperMapActivationRunning = false; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__161 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string source; private float 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__161(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = Time.realtimeSinceStartup + 8f; break; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; case 3: <>1__state = -1; break; case 4: <>1__state = -1; break; case 5: <>1__state = -1; break; } if (Time.realtimeSinceStartup < 5__2) { if (!IsDropperModeActive() && !Plugin.PlayingDropperMap) { return false; } Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null) { <>2__current = null; <>1__state = 1; return true; } KeepDropperSpawnAlive(localCharacter); if (localCharacter.inAirport) { <>2__current = null; <>1__state = 2; return true; } if (localCharacter.warping) { <>2__current = null; <>1__state = 3; return true; } if (!DropperSpawnPointsReadyForRecovery(0.85f)) { <>2__current = null; <>1__state = 4; return true; } if (TryGetDropperSpawnPosition(localCharacter, out var position) && Vector3.Distance(localCharacter.Center, position) < 2.5f) { TryRunDropperUnPassOut(localCharacter); return false; } if (TryWarpLocalCharacterToDropperSpawn(localCharacter)) { TryRunDropperUnPassOut(localCharacter); SwitcherPlugin.Log.LogInfo((object)("Recovered local Dropper spawn after " + source + ".")); return false; } <>2__current = null; <>1__state = 5; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__167 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Character character; private float 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__167(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = Time.realtimeSinceStartup + 5f; break; case 1: <>1__state = -1; break; } if ((Object)(object)character != (Object)null && Time.realtimeSinceStartup < 5__2) { KeepDropperSpawnAlive(character); if (TryWarpLocalCharacterToDropperSpawn(character)) { return false; } <>2__current = null; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const int OffSentinel = -1; private const int DropperSentinel = -101; private const int DescendSentinel = -102; private const int PeakLevelSelectDefault = -2; private const int PeakLevelSelectUnset = -9999; private const string RoomDropperModeKey = "DropperFix.Mode"; private const string RoomPeakLevelKey = "DropperFix.PeakLevel"; private const string RoomPeakAscentKey = "DropperFix.PeakAscent"; private const string PlayerSwitcherInstalledKey = "DropperFix.SwitcherInstalled"; private const float LocalPublishedModeGraceSeconds = 120f; private static bool useDropperControls; private static int dropperMode; private static int localPublishedMode = -9999; private static float localPublishedModeExpiresAt; private static GameObject switchButton; private static GameObject dropperModeButton; private static TextMeshProUGUI switchButtonText; private static TextMeshProUGUI dropperModeButtonText; private static bool checkedPeakLevelSelect; private static Type peakLevelSelectPatchType; private static bool dropperUiApplied; private static bool capturedDescLayout; private static bool defaultDescAutoSizing; private static float defaultDescLineSpacing; private static float defaultDescParagraphSpacing; private static Vector4 defaultDescMargin; private static float defaultDescFontSizeMin; private static float defaultDescFontSizeMax; private static RectTransform ascentTitleRect; private static Vector2 defaultAscentTitleAnchoredPosition; private static Vector2 defaultAscentTitleSizeDelta; private static bool capturedTitleLayout; private static bool capturedRewardState; private static bool defaultRewardActive; private static bool capturedCustomOptionsState; private static bool defaultCustomOptionsActive; private static bool capturedTextState; private static string defaultAscentTitleText; private static Color defaultAscentTitleColor; private static string defaultAscentDescText; private static bool peakLevelSelectHiddenByDropper; private static bool loggedDropperFogFreeze; private static bool loggedDropperLavaFreeze; private static bool loggedDropperSpawnDeathBypass; private static bool loggedDropperDeathBypass; private static bool fogColdControlPatched; private static bool checkedFogColdControl; private static bool loggedInstallAdvertisement; private static bool loggedDropperPassOutUnpatch; private static bool dropperMapActivationRunning; private static bool dropperPlayerSpawnInFlight; private static bool loggedDuplicateDropperSpawnSuppression; private static float lastDropperMapActivationAt; private static float dropperPlayerSpawnInFlightAt; private static float nextDropperSpawnRecoveryAt; private static float dropperSpawnPointsReadyAt; private static int lastDropperSpawnPointCount; private static readonly Dictionary PlayerSpawnPointIndexes = new Dictionary(); private static readonly Dictionary LastResetBerryGrantTimes = new Dictionary(); private static readonly Color Blue = new Color(0.1922f, 0.2941f, 0.9804f, 1f); private static readonly Color Yellow = new Color(0.9804f, 0.8075f, 0.1922f, 1f); [HarmonyPatch(typeof(OrbFogHandler), "Update")] [HarmonyPrefix] private static bool OrbFogHandler_Update_Prefix(OrbFogHandler __instance) { if (!IsDropperModeActive()) { return true; } FreezeOrbFog(__instance, "Update"); return false; } [HarmonyPatch(typeof(OrbFogHandler), "WaitToMove")] [HarmonyPrefix] private static bool OrbFogHandler_WaitToMove_Prefix(OrbFogHandler __instance) { if (!IsDropperModeActive()) { return true; } FreezeOrbFog(__instance, "WaitToMove"); return false; } [HarmonyPatch(typeof(OrbFogHandler), "StartMovingRPC")] [HarmonyPrefix] private static bool OrbFogHandler_StartMovingRPC_Prefix(OrbFogHandler __instance) { if (!IsDropperModeActive()) { return true; } FreezeOrbFog(__instance, "StartMovingRPC"); return false; } [HarmonyPatch(typeof(OrbFogHandler), "RPCA_SyncFog")] [HarmonyPrefix] private static bool OrbFogHandler_RPCA_SyncFog_Prefix(OrbFogHandler __instance) { if (!IsDropperModeActive()) { return true; } FreezeOrbFog(__instance, "RPCA_SyncFog"); return false; } [HarmonyPatch(typeof(OrbFogHandler), "RPC_InitFog")] [HarmonyPrefix] private static bool OrbFogHandler_RPC_InitFog_Prefix(OrbFogHandler __instance) { if (!IsDropperModeActive()) { return true; } FreezeOrbFog(__instance, "RPC_InitFog"); return false; } [HarmonyPatch(typeof(Fog), "Update")] [HarmonyPrefix] private static bool Fog_Update_Prefix() { if (!IsDropperModeActive()) { return true; } if ((Object)(object)Character.localCharacter?.data != (Object)null) { Character.localCharacter.data.isInFog = false; } LogDropperFogFreeze("legacy fog Update"); return false; } [HarmonyPatch(typeof(Fog), "RPCA_Resume")] [HarmonyPrefix] private static bool Fog_RPCA_Resume_Prefix() { if (!IsDropperModeActive()) { return true; } LogDropperFogFreeze("legacy fog resume"); return false; } [HarmonyPatch(typeof(Fog), "RPCA_SyncFog")] [HarmonyPrefix] private static bool Fog_RPCA_SyncFog_Prefix() { if (!IsDropperModeActive()) { return true; } LogDropperFogFreeze("legacy fog sync"); return false; } [HarmonyPatch(typeof(LavaRising), "Update")] [HarmonyPrefix] private static bool LavaRising_Update_Prefix(LavaRising __instance) { if (!IsDropperModeActive()) { return true; } FreezeLavaRising(__instance, "Update"); return false; } [HarmonyPatch(typeof(LavaRising), "StartWaiting")] [HarmonyPrefix] private static bool LavaRising_StartWaiting_Prefix(LavaRising __instance) { if (!IsDropperModeActive()) { return true; } FreezeLavaRising(__instance, "StartWaiting"); return false; } [HarmonyPatch(typeof(LavaRising), "RecieveLavaData")] [HarmonyPrefix] private static bool LavaRising_RecieveLavaData_Prefix(LavaRising __instance) { if (!IsDropperModeActive()) { return true; } FreezeLavaRising(__instance, "RecieveLavaData"); return false; } [HarmonyPatch(typeof(MovingLava), "Update")] [HarmonyPrefix] private static bool MovingLava_Update_Prefix() { if (!IsDropperModeActive()) { return true; } LogDropperLavaFreeze("moving lava Update"); return false; } [HarmonyPatch(typeof(MovingLava), "RPCA_StartLavaRise")] [HarmonyPrefix] private static bool MovingLava_RPCA_StartLavaRise_Prefix() { if (!IsDropperModeActive()) { return true; } LogDropperLavaFreeze("moving lava start"); return false; } [HarmonyPatch(typeof(MovingLava), "RPCA_SyncLavaHeight")] [HarmonyPrefix] private static bool MovingLava_RPCA_SyncLavaHeight_Prefix() { if (!IsDropperModeActive()) { return true; } LogDropperLavaFreeze("moving lava sync"); return false; } [HarmonyPatch(typeof(CharacterSpawner), "KillImmediately")] [HarmonyPrefix] private static bool CharacterSpawner_KillImmediately_Prefix(Character self) { if (!IsDropperModeActive()) { return true; } KeepDropperSpawnAlive(self); if ((Object)(object)self != (Object)null && self.IsLocal) { if (!TryWarpLocalCharacterToDropperSpawn(self)) { ScheduleDropperSpawnRecovery("late-join death spawn"); } TryRunDropperUnPassOut(self); } if (!loggedDropperSpawnDeathBypass) { loggedDropperSpawnDeathBypass = true; SwitcherPlugin.Log.LogInfo((object)"Bypassed vanilla late-join death spawn while Dropper mode is active."); } return false; } [HarmonyPatch(typeof(Character), "StartPassedOutOnTheBeach")] [HarmonyPostfix] private static void Character_StartPassedOutOnTheBeach_Postfix(Character __instance) { if (IsDropperModeActive() && !((Object)(object)__instance == (Object)null)) { KeepDropperSpawnAlive(__instance); if (__instance.IsLocal) { TryRunDropperUnPassOut(__instance); } } } [HarmonyPatch(typeof(Character), "RPCA_SetDead")] [HarmonyPrefix] private static bool Character_RPCA_SetDead_Prefix(Character __instance) { if (!IsDropperModeActive()) { return true; } KeepDropperSpawnAlive(__instance); if ((Object)(object)__instance != (Object)null && __instance.IsLocal) { if (!TryWarpLocalCharacterToDropperSpawn(__instance)) { ScheduleDropperSpawnRecovery("dead reconnect spawn"); } TryRunDropperUnPassOut(__instance); } return false; } [HarmonyPatch(typeof(Character), "RPCA_Die")] [HarmonyPrefix] private static bool Character_RPCA_Die_Prefix(Character __instance) { if (!IsDropperModeActive()) { return true; } KeepDropperSpawnAlive(__instance); if (!TryWarpLocalCharacterToDropperSpawn(__instance) && (Object)(object)__instance != (Object)null && __instance.IsLocal) { ((MonoBehaviour)__instance).StartCoroutine(WarpLocalCharacterToDropperSpawnWhenReady(__instance)); } if (!loggedDropperDeathBypass) { loggedDropperDeathBypass = true; SwitcherPlugin.Log.LogInfo((object)"Bypassed vanilla death RPC while Dropper mode is active."); } return false; } [HarmonyPatch(typeof(Character), "RPCA_PassOut")] [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "com.github.Beast.Dropper.runtime" })] private static bool Character_RPCA_PassOut_Prefix(Character __instance) { if (!IsDropperModeActive()) { return true; } KeepDropperSpawnAlive(__instance); if ((Object)(object)__instance != (Object)null && __instance.IsLocal) { TryWarpLocalCharacterToDropperSpawn(__instance); TryRunDropperUnPassOut(__instance); } return false; } [HarmonyPatch(typeof(AddItemInNetwork), "AddItemIntoInventory")] [HarmonyPrefix] private static bool AddItemInNetwork_AddItemIntoInventory_Prefix(int itemID, int photonID) { if (!IsDropperModeActive() || (Object)(object)Plugin.ResetBerryItem == (Object)null || itemID != Plugin.ResetBerryItem.itemID) { return true; } Character val = TryGetCharacterByPhotonId(photonID); if ((Object)(object)val != (Object)null && HasResetBerry(val)) { return false; } int num = (((Object)(object)val != (Object)null) ? GetPlayerKey(val) : photonID); if (num == 0) { num = photonID; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (LastResetBerryGrantTimes.TryGetValue(num, out var value) && realtimeSinceStartup - value < 2f) { return false; } LastResetBerryGrantTimes[num] = realtimeSinceStartup; return true; } [HarmonyPatch(typeof(ScoutmasterSpawner), "Awake")] [HarmonyPostfix] private static void ScoutmasterSpawner_Awake_DropperProgress_Postfix() { PlayerSpawnPointIndexes.Clear(); LastResetBerryGrantTimes.Clear(); } [HarmonyPatch(typeof(TriggerTeleporter), "OnTriggerEnter")] [HarmonyPostfix] private static void TriggerTeleporter_OnTriggerEnter_Postfix(TriggerTeleporter __instance, Collider other) { if (!IsDropperModeActive() || (Object)(object)__instance == (Object)null || (Object)(object)other == (Object)null) { return; } Character componentInParent = ((Component)other).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null)) { Transform transform = ((Component)__instance).transform; if ((Object)(object)transform.parent != (Object)null && ((Object)((Component)transform.parent).gameObject).name == "ohter parent") { SetPlayerSpawnPointIndex(componentInParent, transform.GetSiblingIndex() + 1); } } } [HarmonyPatch(typeof(InteratableTeleporter), "Interact_CastFinished")] [HarmonyPostfix] private static void InteratableTeleporter_Interact_CastFinished_Postfix(InteratableTeleporter __instance, Character interactor) { if (IsDropperModeActive() && !((Object)(object)__instance == (Object)null) && !((Object)(object)interactor == (Object)null)) { Transform transform = ((Component)__instance).transform; if ((Object)(object)transform.parent != (Object)null && (Object)(object)transform.parent.parent != (Object)null && ((Object)((Component)transform.parent.parent).gameObject).name == "Next Stage Parent") { SetPlayerSpawnPointIndex(interactor, transform.parent.GetSiblingIndex() + 1); } } } [HarmonyPatch(typeof(InteractableBackPorter), "Interact_CastFinished")] [HarmonyPostfix] private static void InteractableBackPorter_Interact_CastFinished_Postfix(InteractableBackPorter __instance, Character interactor) { if (IsDropperModeActive() && !((Object)(object)__instance == (Object)null) && !((Object)(object)interactor == (Object)null)) { SetPlayerSpawnPointIndex(interactor, ((Component)__instance).transform.GetSiblingIndex()); } } [HarmonyPatch(typeof(InteratableFinisher), "GetInteractionText")] [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "com.github.Beast.Dropper.runtime" })] private static bool InteratableFinisher_GetInteractionText_Prefix(ref string __result) { if (!IsDropperModeActive()) { return true; } __result = (IsLocalPlayerAtDropperFinish() ? "Finish the game for all players" : "Breaking out of the map doesn't allow you to finish early"); return false; } [HarmonyPatch(typeof(InteratableFinisher), "Interact_CastFinished")] [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "com.github.Beast.Dropper.runtime" })] private static bool InteratableFinisher_Interact_CastFinished_Prefix(InteratableFinisher __instance, Character interactor) { if (!IsDropperModeActive()) { return true; } if ((Object)(object)interactor != (Object)null && IsPlayerAtDropperFinish(interactor)) { __instance.Interacted?.Invoke(interactor); } return false; } private static bool HarmonyPatches_GiveResetBerry_Prefix(Character character) { if (!IsDropperModeActive()) { return true; } TryGiveResetBerryOnce(character); return false; } internal static void InstallManualPatches() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) try { MethodInfo methodInfo = AccessTools.Method("Dropper.HarmonyPatches:GiveResetBerry", (Type[])null, (Type[])null); if (methodInfo == null) { SwitcherPlugin.Log.LogWarning((object)"Dropper GiveResetBerry patch skipped: target method not found."); return; } HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(BoardingPassSwitcher), "HarmonyPatches_GiveResetBerry_Prefix", (Type[])null, (Type[])null)); val.priority = 800; val.before = new string[1] { "com.github.Beast.Dropper.runtime" }; HarmonyMethod val2 = val; new Harmony("com.github.Beast.Dropper.PeakLevelSelectSwitcher.ManualDropperPatches").Patch((MethodBase)methodInfo, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); SwitcherPlugin.Log.LogInfo((object)"Patched Dropper GiveResetBerry for per-player dedupe."); } catch (Exception ex) { SwitcherPlugin.Log.LogError((object)("Failed to install manual Dropper compatibility patches: " + ex)); } } [HarmonyPatch(typeof(AirportCheckInKiosk), "BeginIslandLoadRPC")] [HarmonyPrefix] private static void AirportCheckInKiosk_BeginIslandLoadRPC_Prefix() { ApplyRoomSelection("BeginIslandLoadRPC"); } [HarmonyPatch(typeof(AirportCheckInKiosk), "LoadIslandMaster")] [HarmonyPrefix] private static void AirportCheckInKiosk_LoadIslandMaster_Prefix(ref byte[] serializedRunSettings) { ApplyRoomSelection("LoadIslandMaster"); } [HarmonyPatch(typeof(CharacterSpawner), "RPC_NewPlayerSpawn")] [HarmonyPrefix] private static bool CharacterSpawner_RPC_NewPlayerSpawn_Prefix() { ApplyRoomSelection("RPC_NewPlayerSpawn"); return AllowDropperPlayerSpawnRpc("new player spawn"); } [HarmonyPatch(typeof(CharacterSpawner), "RPC_NewPlayerSpawn")] [HarmonyPostfix] private static void CharacterSpawner_RPC_NewPlayerSpawn_Postfix() { ScheduleDropperSpawnRecovery("new player spawn"); } [HarmonyPatch(typeof(CharacterSpawner), "RPC_ReconnectingPlayerSpawn")] [HarmonyPrefix] private static bool CharacterSpawner_RPC_ReconnectingPlayerSpawn_Prefix() { ApplyRoomSelection("RPC_ReconnectingPlayerSpawn"); return AllowDropperPlayerSpawnRpc("reconnecting player spawn"); } [HarmonyPatch(typeof(CharacterSpawner), "RPC_ReconnectingPlayerSpawn")] [HarmonyPostfix] private static void CharacterSpawner_RPC_ReconnectingPlayerSpawn_Postfix() { ScheduleDropperSpawnRecovery("reconnecting player spawn"); } [HarmonyPatch(typeof(CharacterSpawner), "RPC_MiniRunPlayerSpawn")] [HarmonyPrefix] private static bool CharacterSpawner_RPC_MiniRunPlayerSpawn_Prefix() { ApplyRoomSelection("RPC_MiniRunPlayerSpawn"); return AllowDropperPlayerSpawnRpc("mini run player spawn"); } [HarmonyPatch(typeof(CharacterSpawner), "RPC_MiniRunPlayerSpawn")] [HarmonyPostfix] private static void CharacterSpawner_RPC_MiniRunPlayerSpawn_Postfix() { ScheduleDropperSpawnRecovery("mini run player spawn"); } [HarmonyPatch(typeof(CharacterSpawner), "SpawnHostCharacter")] [HarmonyPrefix] private static void CharacterSpawner_SpawnHostCharacter_Prefix() { ApplyRoomSelection("SpawnHostCharacter"); } [HarmonyPatch(typeof(CharacterSpawner), "SpawnSelfOnShore")] [HarmonyPostfix] private static void CharacterSpawner_SpawnSelfOnShore_Postfix() { ScheduleDropperSpawnRecovery("vanilla shore spawn"); } [HarmonyPatch(typeof(CharacterSpawner), "SpawnDeadAtBaseCamp")] [HarmonyPostfix] private static void CharacterSpawner_SpawnDeadAtBaseCamp_Postfix() { ScheduleDropperSpawnRecovery("vanilla basecamp spawn"); } [HarmonyPatch(typeof(CharacterSpawner), "SpawnMyPlayerCharacter")] [HarmonyPostfix] private static void CharacterSpawner_SpawnMyPlayerCharacter_Postfix() { dropperPlayerSpawnInFlight = false; ScheduleDropperSpawnRecovery("local player character spawn"); } [HarmonyPatch(typeof(RunSettings), "PushRunSettings")] [HarmonyPrefix] private static bool RunSettings_PushRunSettings_Prefix(Player player = null) { TryAdvertiseSwitcherInstall(); return true; } [HarmonyPatch(typeof(GUIManager), "Start")] [HarmonyPostfix] private static void GUIManager_Start_Postfix() { TryAdvertiseSwitcherInstall(); TryPatchFogColdControl(); if ((Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.boardingPass != (Object)null) { EnsureButtons(GUIManager.instance.boardingPass); Refresh(GUIManager.instance.boardingPass); } } [HarmonyPatch(typeof(BoardingPass), "UpdateAscent")] [HarmonyPrefix] private static void BoardingPass_UpdateAscent_Prefix(BoardingPass __instance) { ClampAscentIndex(__instance); } [HarmonyPatch(typeof(BoardingPass), "UpdateAscent")] [HarmonyPostfix] private static void BoardingPass_UpdateAscent_Postfix(BoardingPass __instance) { EnsureButtons(__instance); Refresh(__instance); } [HarmonyPatch(typeof(BoardingPass), "StartGame")] [HarmonyPrefix] private static bool BoardingPass_StartGame_Prefix(BoardingPass __instance) { TryAdvertiseSwitcherInstall(); if ((Object)(object)__instance == (Object)null || LoadingScreenHandler.loading) { return true; } if (RunSettings.IsCustomRun || !useDropperControls) { DisableDropperForVanillaStart(__instance); return true; } RunSettings.IsCustomRun = false; ClearPeakLevelSelectSelection(); int mode = ((dropperMode == 0) ? (-101) : (-102)); PublishRoomSelection(mode); SendDropperMode(__instance, mode); if ((Object)(object)__instance.kiosk != (Object)null) { __instance.kiosk.StartGame(__instance.ascentIndex); } return false; } [HarmonyPatch(typeof(AirportCheckInKiosk), "StartGame")] [HarmonyPrefix] private static void AirportCheckInKiosk_StartGame_Prefix(ref int ascent) { TryAdvertiseSwitcherInstall(); } private static void EnsureButtons(BoardingPass pass) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown if ((Object)(object)pass == (Object)null || (Object)(object)switchButton != (Object)null) { return; } Transform val = ((Component)pass).transform.Find("BoardingPass/Panel"); if ((Object)(object)val == (Object)null) { val = ((Component)pass).transform.Find("Panel"); } if ((Object)(object)val == (Object)null || (Object)(object)pass.incrementAscentButton == (Object)null) { SwitcherPlugin.Log.LogWarning((object)"Could not find boarding pass panel/reference button for Dropper switcher."); return; } GameObject gameObject = ((Component)pass.incrementAscentButton).gameObject; Transform parent = val; Vector2 position = new Vector2(545f, 405f); Vector2 size = new Vector2(120f, 30f); object obj = <>c.<>9__107_0; if (obj == null) { UnityAction val2 = delegate { useDropperControls = !useDropperControls; SwitcherPlugin.Log.LogInfo((object)("Dropper feature switch clicked. Dropper controls: " + useDropperControls)); if (!useDropperControls) { ApplyDropperToggle(-1); PublishDropperOffSelection(); } if ((Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.boardingPass != (Object)null) { if (useDropperControls) { ClampAscentIndex(GUIManager.instance.boardingPass); } Refresh(GUIManager.instance.boardingPass); } }; <>c.<>9__107_0 = val2; obj = (object)val2; } switchButton = CreateButton(pass, gameObject, parent, "DropperFeatureSwitch", position, size, (UnityAction)obj, out switchButtonText); GameObject gameObject2 = ((Component)pass.incrementAscentButton).gameObject; Transform parent2 = val; Vector2 position2 = new Vector2(690f, 405f); Vector2 size2 = new Vector2(135f, 30f); object obj2 = <>c.<>9__107_1; if (obj2 == null) { UnityAction val3 = delegate { dropperMode = ((dropperMode == 0) ? 1 : 0); SwitcherPlugin.Log.LogInfo((object)("Dropper mode switch clicked. Mode: " + dropperMode)); if ((Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.boardingPass != (Object)null) { Refresh(GUIManager.instance.boardingPass); } }; <>c.<>9__107_1 = val3; obj2 = (object)val3; } dropperModeButton = CreateButton(pass, gameObject2, parent2, "DropperModeSwitch", position2, size2, (UnityAction)obj2, out dropperModeButtonText); SwitcherPlugin.Log.LogInfo((object)"Created Dropper switcher buttons on boarding pass."); } private static void ClampAscentIndex(BoardingPass pass) { if ((Object)(object)pass == (Object)null || (Object)(object)pass.ascentData == (Object)null || pass.ascentData.ascents == null) { return; } int num = Math.Min(7, pass.ascentData.ascents.Count - 3); if (num < -1) { return; } bool flag = pass.ascentIndex < -1; int num2 = ((!flag) ? Mathf.Min(pass.ascentIndex, num) : 0); if (num2 != pass.ascentIndex) { SwitcherPlugin.Log.LogWarning((object)("Clamped invalid boarding pass ascent index from " + pass.ascentIndex + " to " + num2 + ".")); pass.ascentIndex = num2; if (GetPeakLevelSelectValue("SelectedAscent", -2) != -2) { SetPeakLevelSelectValue("SelectedAscent", flag ? (-2) : num2); } } } private static GameObject CreateButton(BoardingPass pass, GameObject referenceButton, Transform parent, string name, Vector2 position, Vector2 size, UnityAction onClick, out TextMeshProUGUI label) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(referenceButton, parent, false); ((Object)val).name = name; Animator component = val.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Transform val2 = val.transform.Find("Image"); if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)((Component)val2).gameObject); } RectTransform component2 = val.GetComponent(); component2.anchorMin = Vector2.zero; component2.anchorMax = Vector2.zero; component2.pivot = Vector2.zero; component2.anchoredPosition = position; component2.sizeDelta = size; Button component3 = val.GetComponent