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 ExtractionAutoRevive v1.3.1
ExtractionAutoRevive.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("REPOJP")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("REPOJP")] [assembly: AssemblyTitle("REPOJP")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 ExtractionAutoRevive { [BepInPlugin("com.repojp.extractionautorevive", "ExtractionAutoRevive", "1.2.0")] public sealed class ExtractionAutoRevivePlugin : BaseUnityPlugin { private sealed class PendingReviveEntry { public PlayerDeathHead DeathHead; public PlayerAvatar PlayerAvatar; public int Key; public float QueuedAt; public float ElectrifiedEndedAt = -1f; public float VelocityStableStartedAt = -1f; public string PlayerLabel; } [CompilerGenerated] private sealed class <MonitorPendingRevives>d__37 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ExtractionAutoRevivePlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <MonitorPendingRevives>d__37(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } while (<>4__this.pendingRevives.Count > 0) { if (!<>4__this.IsModEnabled()) { <>4__this.ClearPendingRevives("mod disabled"); break; } if (!<>4__this.CanRunHostLogic()) { <>4__this.ClearPendingRevives("host lost"); break; } if (<>4__this.ShouldClearPendingByRoundState()) { <>4__this.ClearPendingRevives("round transition"); break; } <>4__this.ProcessPendingRevives(); if (<>4__this.pendingRevives.Count > 0) { <>2__current = (object)new WaitForSecondsRealtime(Mathf.Clamp(<>4__this.configPendingCheckIntervalSeconds.Value, 0.02f, 1f)); <>1__state = 1; return true; } } <>4__this.pendingMonitorCoroutine = null; <>4__this.WriteVerbose("Pending monitor stopped"); 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(); } } internal static ExtractionAutoRevivePlugin Instance; internal static ManualLogSource Log; private Harmony harmony; private static int customReviveContextDepth; private Coroutine pendingMonitorCoroutine; private readonly Dictionary<int, PendingReviveEntry> pendingRevives = new Dictionary<int, PendingReviveEntry>(); private ConfigEntry<bool> configEnableMod; private ConfigEntry<bool> configEnableLog; private ConfigEntry<bool> configEnableVerboseLog; private ConfigEntry<float> configPitHeadExtraDelaySeconds; private ConfigEntry<float> configPitHeadMaxVelocityToRevive; private ConfigEntry<float> configPendingCheckIntervalSeconds; private static readonly FieldInfo FieldPlayerAvatarDeadSet = AccessTools.Field(typeof(PlayerAvatar), "deadSet"); private static readonly FieldInfo FieldPlayerAvatarIsDisabled = AccessTools.Field(typeof(PlayerAvatar), "isDisabled"); private static readonly FieldInfo FieldPlayerAvatarFinalHeal = AccessTools.Field(typeof(PlayerAvatar), "finalHeal"); private static readonly FieldInfo FieldPlayerDeathHeadTriggered = AccessTools.Field(typeof(PlayerDeathHead), "triggered"); private static readonly FieldInfo FieldPlayerDeathHeadInExtractionPoint = AccessTools.Field(typeof(PlayerDeathHead), "inExtractionPoint"); private static readonly FieldInfo FieldPlayerDeathHeadInTruck = AccessTools.Field(typeof(PlayerDeathHead), "inTruck"); private static readonly FieldInfo FieldPlayerDeathHeadPhysGrabObject = AccessTools.Field(typeof(PlayerDeathHead), "physGrabObject"); private static readonly FieldInfo FieldPhysGrabObjectDeathPitEffect = AccessTools.Field(typeof(PhysGrabObject), "deathPitEffect"); private static readonly FieldInfo FieldPhysGrabObjectDeathPitEffectDisableTimer = AccessTools.Field(typeof(PhysGrabObject), "deathPitEffectDisableTimer"); private static readonly FieldInfo FieldDeathPitSaveEffectTimeCurrent = AccessTools.Field(typeof(DeathPitSaveEffect), "timeCurrent"); private void Awake() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown try { ((Component)this).transform.parent = null; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"[ExtractionAutoRevive] Persist setup failed ex={arg}"); } Instance = this; Log = ((BaseUnityPlugin)this).Logger; SetupConfig(); SceneManager.activeSceneChanged += OnActiveSceneChanged; harmony = new Harmony("com.repojp.extractionautorevive"); harmony.PatchAll(); WriteLog("Loaded"); } private void OnDestroy() { ClearPendingRevives("plugin destroy"); SceneManager.activeSceneChanged -= OnActiveSceneChanged; try { if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"[ExtractionAutoRevive] Unpatch failed ex={arg}"); } if (Instance == this) { Instance = null; } } private void SetupConfig() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown configEnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "MOD overall enable switch"); configEnableLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Log", "EnableLog", true, "Enable standard logs"); configEnableVerboseLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Log", "EnableVerboseLog", false, "Enable verbose logs"); configPitHeadExtraDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("PitHead", "PitHeadExtraDelaySeconds", 0.35f, new ConfigDescription("Additional delay after death pit electricity ends", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); configPitHeadMaxVelocityToRevive = ((BaseUnityPlugin)this).Config.Bind<float>("PitHead", "PitHeadMaxVelocityToRevive", 1f, new ConfigDescription("Maximum rigidbody velocity magnitude allowed before revive", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>())); configPendingCheckIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("PitHead", "PendingCheckIntervalSeconds", 0.05f, new ConfigDescription("Pending pit head monitor interval", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 1f), Array.Empty<object>())); } private void OnActiveSceneChanged(Scene previousScene, Scene nextScene) { ClearPendingRevives("scene changed " + ((Scene)(ref previousScene)).name + " -> " + ((Scene)(ref nextScene)).name); } private void WriteLog(string message) { if (configEnableLog != null && configEnableLog.Value) { Log.LogInfo((object)("[ExtractionAutoRevive] " + message)); } } private void WriteVerbose(string message) { if (configEnableVerboseLog != null && configEnableVerboseLog.Value) { Log.LogInfo((object)("[ExtractionAutoRevive] " + message)); } } private void WriteWarning(string message) { Log.LogWarning((object)("[ExtractionAutoRevive] " + message)); } internal static void EnterCustomReviveContext() { customReviveContextDepth++; } internal static void ExitCustomReviveContext() { if (customReviveContextDepth > 0) { customReviveContextDepth--; } } internal static bool IsCustomReviveContextActive() { return customReviveContextDepth > 0; } internal bool IsModEnabled() { return configEnableMod != null && configEnableMod.Value; } internal void HandleDeathHeadRevive(PlayerDeathHead deathHead) { if (IsModEnabled() && !((Object)(object)deathHead == (Object)null)) { PlayerAvatar playerAvatar = deathHead.playerAvatar; DeathPitSaveEffect effect; if ((Object)(object)playerAvatar == (Object)null) { WriteWarning("Skip custom revive reason=playerAvatar null"); } else if (!IsPlayerDead(playerAvatar, deathHead)) { WriteVerbose("Skip custom revive player=" + GetPlayerLabel(playerAvatar) + " reason=alreadyAlive"); } else if (!GetBoolField(FieldPlayerDeathHeadTriggered, deathHead, defaultValue: false)) { WriteVerbose("Skip custom revive player=" + GetPlayerLabel(playerAvatar) + " reason=headNotTriggered"); } else if (IsPitHeadElectrified(deathHead, out effect)) { EnqueuePendingRevive(deathHead, playerAvatar); } else { ReviveNow(playerAvatar, "immediate"); } } } private void EnqueuePendingRevive(PlayerDeathHead deathHead, PlayerAvatar playerAvatar) { if (!((Object)(object)deathHead == (Object)null) && !((Object)(object)playerAvatar == (Object)null)) { int num = GetPendingKey(playerAvatar, deathHead); if (num == 0) { num = ((Object)playerAvatar).GetInstanceID(); } if (pendingRevives.TryGetValue(num, out PendingReviveEntry value)) { value.DeathHead = deathHead; value.PlayerAvatar = playerAvatar; value.PlayerLabel = GetPlayerLabel(playerAvatar); WriteVerbose($"Refresh pending revive player={value.PlayerLabel} key={num}"); StartPendingMonitorIfNeeded(); } else { PendingReviveEntry pendingReviveEntry = new PendingReviveEntry { DeathHead = deathHead, PlayerAvatar = playerAvatar, Key = num, QueuedAt = Time.unscaledTime, PlayerLabel = GetPlayerLabel(playerAvatar) }; pendingRevives[num] = pendingReviveEntry; WriteLog($"Queue delayed revive player={pendingReviveEntry.PlayerLabel} key={num}"); StartPendingMonitorIfNeeded(); } } } private void StartPendingMonitorIfNeeded() { if (pendingRevives.Count > 0 && pendingMonitorCoroutine == null) { pendingMonitorCoroutine = ((MonoBehaviour)this).StartCoroutine(MonitorPendingRevives()); WriteVerbose("Pending monitor started"); } } [IteratorStateMachine(typeof(<MonitorPendingRevives>d__37))] private IEnumerator MonitorPendingRevives() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <MonitorPendingRevives>d__37(0) { <>4__this = this }; } private void ProcessPendingRevives() { if (pendingRevives.Count <= 0) { return; } List<int> list = new List<int>(pendingRevives.Keys); foreach (int item in list) { if (!pendingRevives.TryGetValue(item, out PendingReviveEntry value)) { continue; } if (value == null || (Object)(object)value.PlayerAvatar == (Object)null || (Object)(object)value.DeathHead == (Object)null) { RemovePendingRevive(item, "invalid reference"); continue; } if (!IsPlayerDead(value.PlayerAvatar, value.DeathHead)) { RemovePendingRevive(item, "already alive"); continue; } if (!GetBoolField(FieldPlayerDeathHeadTriggered, value.DeathHead, defaultValue: false)) { RemovePendingRevive(item, "head no longer triggered"); continue; } if (ShouldLeaveToVanillaTruckRevive(value.DeathHead, value.PlayerAvatar)) { RemovePendingRevive(item, "vanilla truck revive"); continue; } if (IsPitHeadElectrified(value.DeathHead, out DeathPitSaveEffect _)) { value.ElectrifiedEndedAt = -1f; value.VelocityStableStartedAt = -1f; WriteVerbose("Pending wait player=" + value.PlayerLabel + " reason=electrified"); continue; } if (value.ElectrifiedEndedAt < 0f) { value.ElectrifiedEndedAt = Time.unscaledTime; value.VelocityStableStartedAt = -1f; WriteVerbose("Pending electricity ended player=" + value.PlayerLabel); } float num = Time.unscaledTime - value.ElectrifiedEndedAt; if (num < configPitHeadExtraDelaySeconds.Value) { WriteVerbose($"Pending extra delay player={value.PlayerLabel} elapsed={num:F2}"); continue; } float headVelocityMagnitude = GetHeadVelocityMagnitude(value.DeathHead); if (headVelocityMagnitude > configPitHeadMaxVelocityToRevive.Value) { value.VelocityStableStartedAt = -1f; WriteVerbose($"Pending velocity wait player={value.PlayerLabel} velocity={headVelocityMagnitude:F2}"); continue; } if (value.VelocityStableStartedAt < 0f) { value.VelocityStableStartedAt = Time.unscaledTime; WriteVerbose("Pending velocity stable start player=" + value.PlayerLabel); } ReviveNow(value.PlayerAvatar, "delayed"); RemovePendingRevive(item, "revived"); } } private void RemovePendingRevive(int key, string reason) { if (pendingRevives.TryGetValue(key, out PendingReviveEntry value)) { WriteVerbose($"Pending remove player={value.PlayerLabel} key={key} reason={reason}"); pendingRevives.Remove(key); } } internal void ClearPendingRevives(string reason) { if (pendingRevives.Count > 0) { WriteLog($"Clear pending revives count={pendingRevives.Count} reason={reason}"); pendingRevives.Clear(); } } private bool CanRunHostLogic() { try { return SemiFunc.IsMasterClientOrSingleplayer(); } catch { return false; } } private bool ShouldClearPendingByRoundState() { try { if ((Object)(object)RunManager.instance == (Object)null) { return false; } if (SemiFunc.RunIsLobby() || SemiFunc.RunIsLobbyMenu() || (!SemiFunc.RunIsShop() && !SemiFunc.RunIsLevel())) { return true; } if ((Object)(object)RoundDirector.instance != (Object)null && RoundDirector.instance.allExtractionPointsCompleted) { return true; } } catch { return true; } return false; } private bool ShouldLeaveToVanillaTruckRevive(PlayerDeathHead deathHead, PlayerAvatar playerAvatar) { if ((Object)(object)deathHead == (Object)null || (Object)(object)playerAvatar == (Object)null) { return false; } if ((Object)(object)RoundDirector.instance == (Object)null) { return false; } if (!RoundDirector.instance.allExtractionPointsCompleted) { return false; } if (GetBoolField(FieldPlayerAvatarFinalHeal, playerAvatar, defaultValue: false)) { return false; } if (!GetBoolField(FieldPlayerDeathHeadInTruck, deathHead, defaultValue: false)) { return false; } return true; } private bool IsPlayerDead(PlayerAvatar playerAvatar, PlayerDeathHead deathHead) { if ((Object)(object)playerAvatar == (Object)null) { return false; } bool boolField = GetBoolField(FieldPlayerAvatarDeadSet, playerAvatar, defaultValue: false); bool boolField2 = GetBoolField(FieldPlayerAvatarIsDisabled, playerAvatar, defaultValue: false); bool activeSelf = ((Component)playerAvatar).gameObject.activeSelf; bool flag = (Object)(object)deathHead != (Object)null && GetBoolField(FieldPlayerDeathHeadTriggered, deathHead, defaultValue: false); if (boolField) { return true; } if (boolField2) { return true; } if (!activeSelf) { return true; } if (flag) { return true; } return false; } private void ReviveNow(PlayerAvatar playerAvatar, string reason) { if ((Object)(object)playerAvatar == (Object)null) { return; } if (!IsPlayerDead(playerAvatar, playerAvatar.playerDeathHead)) { WriteVerbose("Skip revive player=" + GetPlayerLabel(playerAvatar) + " reason=alreadyAlive finalReason=" + reason); return; } try { playerAvatar.Revive(true); WriteLog("Revive(true) player=" + GetPlayerLabel(playerAvatar) + " reason=" + reason); } catch (Exception arg) { WriteWarning($"Revive(true) failed player={GetPlayerLabel(playerAvatar)} reason={reason} ex={arg}"); } } private bool IsPitHeadElectrified(PlayerDeathHead deathHead, out DeathPitSaveEffect effect) { effect = null; if ((Object)(object)deathHead == (Object)null) { return false; } PhysGrabObject playerDeathHeadPhysGrabObject = GetPlayerDeathHeadPhysGrabObject(deathHead); if ((Object)(object)playerDeathHeadPhysGrabObject == (Object)null) { return false; } float floatField = GetFloatField(FieldPhysGrabObjectDeathPitEffectDisableTimer, playerDeathHeadPhysGrabObject, 0f); GameObject gameObjectField = GetGameObjectField(FieldPhysGrabObjectDeathPitEffect, playerDeathHeadPhysGrabObject); if ((Object)(object)gameObjectField == (Object)null) { if (floatField > 0f) { return false; } return false; } effect = gameObjectField.GetComponent<DeathPitSaveEffect>(); if ((Object)(object)effect == (Object)null) { return false; } if ((Object)(object)effect.physGrabObject != (Object)null && (Object)(object)effect.physGrabObject != (Object)(object)playerDeathHeadPhysGrabObject) { return false; } float floatField2 = GetFloatField(FieldDeathPitSaveEffectTimeCurrent, effect, 0f); if (floatField2 > 0f) { return true; } return false; } private float GetHeadVelocityMagnitude(PlayerDeathHead deathHead) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)deathHead == (Object)null) { return 0f; } PhysGrabObject playerDeathHeadPhysGrabObject = GetPlayerDeathHeadPhysGrabObject(deathHead); if ((Object)(object)playerDeathHeadPhysGrabObject == (Object)null) { return 0f; } if ((Object)(object)playerDeathHeadPhysGrabObject.rb == (Object)null) { return 0f; } Vector3 velocity = playerDeathHeadPhysGrabObject.rb.velocity; return ((Vector3)(ref velocity)).magnitude; } private int GetPendingKey(PlayerAvatar playerAvatar, PlayerDeathHead deathHead) { if ((Object)(object)playerAvatar != (Object)null && (Object)(object)playerAvatar.photonView != (Object)null && playerAvatar.photonView.ViewID > 0) { return playerAvatar.photonView.ViewID; } PhotonView val = null; if ((Object)(object)deathHead != (Object)null) { val = ((Component)deathHead).GetComponent<PhotonView>(); } if ((Object)(object)val != (Object)null && val.ViewID > 0) { return val.ViewID; } if ((Object)(object)playerAvatar != (Object)null) { return ((Object)playerAvatar).GetInstanceID(); } return 0; } private string GetPlayerLabel(PlayerAvatar playerAvatar) { if ((Object)(object)playerAvatar == (Object)null) { return "null"; } if (!string.IsNullOrEmpty(((Object)playerAvatar).name)) { return ((Object)playerAvatar).name; } return "PlayerAvatar"; } private PhysGrabObject GetPlayerDeathHeadPhysGrabObject(PlayerDeathHead deathHead) { if ((Object)(object)deathHead == (Object)null) { return null; } PhysGrabObject val = null; if (FieldPlayerDeathHeadPhysGrabObject != null) { try { object? value = FieldPlayerDeathHeadPhysGrabObject.GetValue(deathHead); val = (PhysGrabObject)((value is PhysGrabObject) ? value : null); } catch { } } if ((Object)(object)val != (Object)null) { return val; } return ((Component)deathHead).GetComponent<PhysGrabObject>(); } private static bool GetBoolField(FieldInfo fieldInfo, object instance, bool defaultValue) { if (fieldInfo == null || instance == null) { return defaultValue; } try { object value = fieldInfo.GetValue(instance); if (value is bool) { return (bool)value; } } catch { } return defaultValue; } private static float GetFloatField(FieldInfo fieldInfo, object instance, float defaultValue) { if (fieldInfo == null || instance == null) { return defaultValue; } try { object value = fieldInfo.GetValue(instance); if (value is float) { return (float)value; } } catch { } return defaultValue; } private static GameObject GetGameObjectField(FieldInfo fieldInfo, object instance) { if (fieldInfo == null || instance == null) { return null; } try { object? value = fieldInfo.GetValue(instance); return (GameObject)((value is GameObject) ? value : null); } catch { return null; } } } [HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInShoppingList")] internal static class ExtractionPoint_DestroyAllPhysObjectsInShoppingList_Patch { private static void Prefix() { if (SemiFunc.IsMasterClientOrSingleplayer()) { ExtractionAutoRevivePlugin.EnterCustomReviveContext(); } } private static Exception Finalizer(Exception __exception) { if (SemiFunc.IsMasterClientOrSingleplayer()) { ExtractionAutoRevivePlugin.ExitCustomReviveContext(); } return __exception; } } [HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInHaulList")] internal static class ExtractionPoint_DestroyAllPhysObjectsInHaulList_Patch { private static void Prefix() { if (SemiFunc.IsMasterClientOrSingleplayer()) { ExtractionAutoRevivePlugin.EnterCustomReviveContext(); } } private static Exception Finalizer(Exception __exception) { if (SemiFunc.IsMasterClientOrSingleplayer()) { ExtractionAutoRevivePlugin.ExitCustomReviveContext(); } return __exception; } } [HarmonyPatch(typeof(PlayerDeathHead), "Revive")] internal static class PlayerDeathHead_Revive_Patch { private static bool Prefix(PlayerDeathHead __instance) { if (!ExtractionAutoRevivePlugin.IsCustomReviveContextActive()) { return true; } if ((Object)(object)ExtractionAutoRevivePlugin.Instance == (Object)null) { return true; } if (!ExtractionAutoRevivePlugin.Instance.IsModEnabled()) { return true; } try { ExtractionAutoRevivePlugin.Instance.HandleDeathHeadRevive(__instance); } catch (Exception arg) { ManualLogSource log = ExtractionAutoRevivePlugin.Log; if (log != null) { log.LogWarning((object)$"[ExtractionAutoRevive] PlayerDeathHead.Revive patch failed ex={arg}"); } } return false; } } [HarmonyPatch(typeof(RunManager), "ChangeLevel")] internal static class RunManager_ChangeLevel_Patch { private static void Prefix() { if ((Object)(object)ExtractionAutoRevivePlugin.Instance != (Object)null) { ExtractionAutoRevivePlugin.Instance.ClearPendingRevives("run manager change level"); } } } [HarmonyPatch(typeof(RunManager), "RestartScene")] internal static class RunManager_RestartScene_Patch { private static void Prefix() { if ((Object)(object)ExtractionAutoRevivePlugin.Instance != (Object)null) { ExtractionAutoRevivePlugin.Instance.ClearPendingRevives("run manager restart scene"); } } } [HarmonyPatch(typeof(RoundDirector), "ExtractionCompletedAllRPC")] internal static class RoundDirector_ExtractionCompletedAllRPC_Patch { private static void Postfix() { if ((Object)(object)ExtractionAutoRevivePlugin.Instance != (Object)null) { ExtractionAutoRevivePlugin.Instance.ClearPendingRevives("all extractions completed"); } } } [HarmonyPatch(typeof(TruckHealer), "StateUpdate")] internal static class TruckHealer_StateUpdate_Patch { private static void Prefix(State _newState) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (((int)_newState == 1 || (int)_newState == 2 || (int)_newState == 3) && (Object)(object)ExtractionAutoRevivePlugin.Instance != (Object)null) { ExtractionAutoRevivePlugin.Instance.ClearPendingRevives($"truck healer state={_newState}"); } } } }