Decompiled source of ExtractionAutoRevive v4.0.1

ExtractionAutoRevive.dll

Decompiled a month ago
using 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;

[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("zabuMod")]
[assembly: AssemblyTitle("zabuMod")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPOJP.ExtractionAutoRevive
{
	[BepInPlugin("REPOJP.ExtractionAutoRevive", "ExtractionAutoRevive", "4.0.1")]
	public sealed class ExtractionAutoRevivePlugin : BaseUnityPlugin
	{
		private sealed class PendingReviveEntry
		{
			public PlayerDeathHead DeathHead;

			public PlayerAvatar PlayerAvatar;

			public int Key;

			public float QueuedAt;

			public float GroundedStartedAt = -1f;

			public string LevelName;

			public string PlayerLabel;

			public string Source;
		}

		[CompilerGenerated]
		private sealed class <MonitorPendingRevives>d__39 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ExtractionAutoRevivePlugin <>4__this;

			private float <interval>5__1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <MonitorPendingRevives>d__39(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_010e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: 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;
					}
					<>4__this.ProcessPendingRevives();
					if (<>4__this._pendingRevives.Count > 0)
					{
						<interval>5__1 = 0.05f;
						if (<>4__this._configPendingCheckIntervalSeconds != null)
						{
							<interval>5__1 = Mathf.Clamp(<>4__this._configPendingCheckIntervalSeconds.Value, 0.02f, 1f);
						}
						<>2__current = (object)new WaitForSecondsRealtime(<interval>5__1);
						<>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();
			}
		}

		public const string PluginGuid = "REPOJP.ExtractionAutoRevive";

		public const string PluginName = "ExtractionAutoRevive";

		public const string PluginVersion = "4.0.1";

		internal static ExtractionAutoRevivePlugin Instance;

		internal static ManualLogSource LogSource;

		private Harmony _harmony;

		private static int _extractionCompleteContextDepth;

		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<bool> _configReviveOnShopExtraction;

		private ConfigEntry<float> _configRequiredGroundedSeconds;

		private ConfigEntry<float> _configGroundCheckDistance;

		private ConfigEntry<float> _configPendingCheckIntervalSeconds;

		private ConfigEntry<float> _configMaxPendingSeconds;

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

		private static readonly FieldInfo FieldPlayerAvatarDeadSet = AccessTools.Field(typeof(PlayerAvatar), "deadSet");

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

		private static readonly FieldInfo FieldPlayerDeathHeadTriggered = AccessTools.Field(typeof(PlayerDeathHead), "triggered");

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

		private void Awake()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			try
			{
				((Component)this).transform.parent = null;
				((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[ExtractionAutoRevive] Persist setup failed\n" + ex));
			}
			try
			{
				Instance = this;
				LogSource = ((BaseUnityPlugin)this).Logger;
				SetupConfig();
				_harmony = new Harmony("REPOJP.ExtractionAutoRevive");
				_harmony.PatchAll(typeof(ExtractionAutoRevivePlugin).Assembly);
				WriteLog("Loaded v4.0.1");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[ExtractionAutoRevive] Awake failed\n" + ex2));
			}
		}

		private void OnDestroy()
		{
			ClearPendingRevives("plugin destroy");
			StopPendingMonitor();
			try
			{
				if (_harmony != null)
				{
					_harmony.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[ExtractionAutoRevive] Unpatch failed\n" + ex));
			}
			if (Instance == this)
			{
				Instance = null;
			}
		}

		private void SetupConfig()
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			_configEnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Enable this mod. このMODを有効化");
			_configReviveOnShopExtraction = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReviveOnShopExtraction", false, "Also revive dead players when the shop extraction tube completes purchases. ショップ購入チューブ完了時も蘇生");
			_configEnableLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Log", "EnableLog", true, "Enable standard logs. 標準ログ有効化");
			_configEnableVerboseLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Log", "EnableVerboseLog", false, "Enable verbose logs. 詳細ログ有効化");
			_configRequiredGroundedSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("GroundCheck", "RequiredGroundedSeconds", 0f, new ConfigDescription("Required seconds that the death head must stay on the ground before revive. 蘇生前にデスヘッドが地面接触している必要秒数", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			_configGroundCheckDistance = ((BaseUnityPlugin)this).Config.Bind<float>("GroundCheck", "GroundCheckDistance", 0.35f, new ConfigDescription("Ground ray distance from the death head collider bounds. デスヘッドCollider境界からの地面判定距離", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 3f), Array.Empty<object>()));
			_configPendingCheckIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("GroundCheck", "PendingCheckIntervalSeconds", 0.05f, new ConfigDescription("Pending revive monitor interval. 遅延蘇生監視間隔", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 1f), Array.Empty<object>()));
			_configMaxPendingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("GroundCheck", "MaxPendingSeconds", 0f, new ConfigDescription("Maximum seconds to wait for a death head to touch the ground. 0 means unlimited. デスヘッド地面接触待機最大秒数。0は無制限", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>()));
		}

		private void WriteLog(string message)
		{
			if (_configEnableLog != null && _configEnableLog.Value && LogSource != null)
			{
				LogSource.LogInfo((object)("[ExtractionAutoRevive] " + message));
			}
		}

		private void WriteVerbose(string message)
		{
			if (_configEnableVerboseLog != null && _configEnableVerboseLog.Value && LogSource != null)
			{
				LogSource.LogInfo((object)("[ExtractionAutoRevive] " + message));
			}
		}

		private void WriteWarning(string message)
		{
			if (LogSource != null)
			{
				LogSource.LogWarning((object)("[ExtractionAutoRevive] " + message));
			}
		}

		private bool IsModEnabled()
		{
			return _configEnableMod != null && _configEnableMod.Value;
		}

		private bool ShouldHandleShopExtraction()
		{
			return _configReviveOnShopExtraction != null && _configReviveOnShopExtraction.Value;
		}

		private bool CanRunHostLogic()
		{
			try
			{
				return SemiFunc.IsMasterClientOrSingleplayer();
			}
			catch
			{
				return false;
			}
		}

		internal static void EnterExtractionCompleteContext(string source)
		{
			ExtractionAutoRevivePlugin instance = Instance;
			if (!((Object)(object)instance == (Object)null) && instance.IsModEnabled() && instance.CanRunHostLogic() && (!string.Equals(source, "shop", StringComparison.Ordinal) || instance.ShouldHandleShopExtraction()))
			{
				_extractionCompleteContextDepth++;
				instance.WriteVerbose("Enter extraction context source=" + source + " depth=" + _extractionCompleteContextDepth);
			}
		}

		internal static void ExitExtractionCompleteContext(string source, Exception exception)
		{
			ExtractionAutoRevivePlugin instance = Instance;
			bool flag = _extractionCompleteContextDepth > 0;
			if (_extractionCompleteContextDepth > 0)
			{
				_extractionCompleteContextDepth--;
			}
			if (!((Object)(object)instance == (Object)null) && flag)
			{
				instance.WriteVerbose("Exit extraction context source=" + source + " depth=" + _extractionCompleteContextDepth);
				if (exception != null)
				{
					instance.WriteWarning("Skip queue because extraction method failed source=" + source + "\n" + exception);
				}
				else if (instance.IsModEnabled() && instance.CanRunHostLogic())
				{
					instance.QueueAllDeadPlayers(source);
				}
			}
		}

		internal static bool IsExtractionCompleteContextActive()
		{
			return _extractionCompleteContextDepth > 0;
		}

		private void QueueAllDeadPlayers(string source)
		{
			if ((Object)(object)GameDirector.instance == (Object)null || GameDirector.instance.PlayerList == null)
			{
				WriteWarning("Skip queue reason=GameDirector PlayerList null source=" + source);
				return;
			}
			int num = 0;
			int num2 = 0;
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if ((Object)(object)player == (Object)null)
				{
					num2++;
					continue;
				}
				PlayerDeathHead playerDeathHead = GetPlayerDeathHead(player);
				if ((Object)(object)playerDeathHead == (Object)null)
				{
					num2++;
					WriteVerbose("Skip queue player=" + GetPlayerLabel(player) + " reason=deathHead null source=" + source);
				}
				else if (!IsPlayerDead(player, playerDeathHead))
				{
					num2++;
					WriteVerbose("Skip queue player=" + GetPlayerLabel(player) + " reason=alive source=" + source);
				}
				else if (!IsDeathHeadTriggered(playerDeathHead))
				{
					num2++;
					WriteVerbose("Skip queue player=" + GetPlayerLabel(player) + " reason=headNotTriggered source=" + source);
				}
				else
				{
					EnqueuePendingRevive(playerDeathHead, player, source);
					num++;
				}
			}
			WriteLog("Extraction complete source=" + source + " queued=" + num + " skipped=" + num2);
			StartPendingMonitorIfNeeded();
		}

		private void EnqueuePendingRevive(PlayerDeathHead deathHead, PlayerAvatar playerAvatar, string source)
		{
			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 var value))
				{
					value.DeathHead = deathHead;
					value.PlayerAvatar = playerAvatar;
					value.PlayerLabel = GetPlayerLabel(playerAvatar);
					value.LevelName = GetCurrentLevelName();
					value.Source = source;
					WriteVerbose("Refresh pending revive player=" + value.PlayerLabel + " key=" + num + " source=" + source);
				}
				else
				{
					PendingReviveEntry pendingReviveEntry = new PendingReviveEntry
					{
						DeathHead = deathHead,
						PlayerAvatar = playerAvatar,
						Key = num,
						QueuedAt = Time.unscaledTime,
						GroundedStartedAt = -1f,
						LevelName = GetCurrentLevelName(),
						PlayerLabel = GetPlayerLabel(playerAvatar),
						Source = source
					};
					_pendingRevives[num] = pendingReviveEntry;
					WriteLog("Queue ground-wait revive player=" + pendingReviveEntry.PlayerLabel + " key=" + num + " source=" + source);
				}
			}
		}

		private void StartPendingMonitorIfNeeded()
		{
			if (_pendingRevives.Count > 0 && _pendingMonitorCoroutine == null)
			{
				_pendingMonitorCoroutine = ((MonoBehaviour)this).StartCoroutine(MonitorPendingRevives());
				WriteVerbose("Pending monitor started");
			}
		}

		private void StopPendingMonitor()
		{
			if (_pendingMonitorCoroutine != null)
			{
				try
				{
					((MonoBehaviour)this).StopCoroutine(_pendingMonitorCoroutine);
				}
				catch
				{
				}
				_pendingMonitorCoroutine = null;
			}
		}

		[IteratorStateMachine(typeof(<MonitorPendingRevives>d__39))]
		private IEnumerator MonitorPendingRevives()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <MonitorPendingRevives>d__39(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 var value))
				{
					continue;
				}
				if (value == null || (Object)(object)value.PlayerAvatar == (Object)null || (Object)(object)value.DeathHead == (Object)null)
				{
					RemovePendingRevive(item, "invalid reference");
					continue;
				}
				if (HasQueuedLevelChanged(value))
				{
					RemovePendingRevive(item, "level changed");
					continue;
				}
				if (!IsPlayerDead(value.PlayerAvatar, value.DeathHead))
				{
					RemovePendingRevive(item, "already alive");
					continue;
				}
				if (!IsDeathHeadTriggered(value.DeathHead))
				{
					RemovePendingRevive(item, "head no longer triggered");
					continue;
				}
				if (HasPendingTimedOut(value))
				{
					RemovePendingRevive(item, "pending timeout");
					continue;
				}
				if (!IsDeathHeadGrounded(value.DeathHead))
				{
					value.GroundedStartedAt = -1f;
					WriteVerbose("Pending wait player=" + value.PlayerLabel + " reason=not grounded");
					continue;
				}
				if (value.GroundedStartedAt < 0f)
				{
					value.GroundedStartedAt = Time.unscaledTime;
					WriteVerbose("Pending grounded start player=" + value.PlayerLabel);
				}
				float num = 0f;
				if (_configRequiredGroundedSeconds != null)
				{
					num = Mathf.Clamp(_configRequiredGroundedSeconds.Value, 0f, 10f);
				}
				float num2 = Time.unscaledTime - value.GroundedStartedAt;
				if (num2 < num)
				{
					WriteVerbose("Pending grounded wait player=" + value.PlayerLabel + " elapsed=" + num2.ToString("F2"));
				}
				else if (ReviveNow(value.PlayerAvatar, value.DeathHead, "source=" + value.Source + " grounded=" + num2.ToString("F2") + "s"))
				{
					RemovePendingRevive(item, "revived");
				}
				else
				{
					RemovePendingRevive(item, "revive failed");
				}
			}
		}

		private bool HasPendingTimedOut(PendingReviveEntry entry)
		{
			if (entry == null)
			{
				return true;
			}
			float num = 0f;
			if (_configMaxPendingSeconds != null)
			{
				num = Mathf.Clamp(_configMaxPendingSeconds.Value, 0f, 600f);
			}
			if (num <= 0f)
			{
				return false;
			}
			return Time.unscaledTime - entry.QueuedAt >= num;
		}

		private void RemovePendingRevive(int key, string reason)
		{
			if (_pendingRevives.TryGetValue(key, out var 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 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 flag = (Object)(object)((Component)playerAvatar).gameObject != (Object)null && ((Component)playerAvatar).gameObject.activeSelf;
			bool flag2 = (Object)(object)deathHead != (Object)null && IsDeathHeadTriggered(deathHead);
			if (boolField)
			{
				return true;
			}
			if (boolField2)
			{
				return true;
			}
			if (!flag)
			{
				return true;
			}
			if (flag2)
			{
				return true;
			}
			return false;
		}

		private bool ReviveNow(PlayerAvatar playerAvatar, PlayerDeathHead deathHead, string reason)
		{
			if ((Object)(object)playerAvatar == (Object)null || (Object)(object)deathHead == (Object)null)
			{
				return false;
			}
			if (!IsPlayerDead(playerAvatar, deathHead))
			{
				WriteVerbose("Skip revive player=" + GetPlayerLabel(playerAvatar) + " reason=alreadyAlive finalReason=" + reason);
				return true;
			}
			try
			{
				playerAvatar.Revive(false);
				WriteLog("Revive player=" + GetPlayerLabel(playerAvatar) + " " + reason);
				return true;
			}
			catch (Exception ex)
			{
				WriteWarning("Revive failed player=" + GetPlayerLabel(playerAvatar) + " " + reason + "\n" + ex);
				return false;
			}
		}

		private bool IsDeathHeadGrounded(PlayerDeathHead deathHead)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)deathHead == (Object)null)
			{
				return false;
			}
			PhysGrabObject playerDeathHeadPhysGrabObject = GetPlayerDeathHeadPhysGrabObject(deathHead);
			if ((Object)(object)playerDeathHeadPhysGrabObject == (Object)null)
			{
				return false;
			}
			float num = 0.35f;
			if (_configGroundCheckDistance != null)
			{
				num = Mathf.Clamp(_configGroundCheckDistance.Value, 0.05f, 3f);
			}
			try
			{
				Vector3 centerPoint = playerDeathHeadPhysGrabObject.centerPoint;
				if (SemiFunc.OnGroundCheck(centerPoint, num, playerDeathHeadPhysGrabObject))
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)playerDeathHeadPhysGrabObject.rb != (Object)null)
				{
					Vector3 worldCenterOfMass = playerDeathHeadPhysGrabObject.rb.worldCenterOfMass;
					if (SemiFunc.OnGroundCheck(worldCenterOfMass, num, playerDeathHeadPhysGrabObject))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			try
			{
				Collider[] componentsInChildren = ((Component)deathHead).GetComponentsInChildren<Collider>();
				foreach (Collider val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null) && val.enabled && !val.isTrigger)
					{
						Bounds bounds = val.bounds;
						Vector3 center = ((Bounds)(ref bounds)).center;
						float num2 = ((Bounds)(ref bounds)).extents.y + num;
						if (SemiFunc.OnGroundCheck(center, num2, playerDeathHeadPhysGrabObject))
						{
							return true;
						}
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private int GetPendingKey(PlayerAvatar playerAvatar, PlayerDeathHead deathHead)
		{
			try
			{
				if ((Object)(object)playerAvatar != (Object)null && (Object)(object)playerAvatar.photonView != (Object)null && playerAvatar.photonView.ViewID > 0)
				{
					return playerAvatar.photonView.ViewID;
				}
			}
			catch
			{
			}
			try
			{
				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;
				}
			}
			catch
			{
			}
			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";
			}
			try
			{
				if (!string.IsNullOrEmpty(((Object)playerAvatar).name))
				{
					return ((Object)playerAvatar).name;
				}
			}
			catch
			{
			}
			return "PlayerAvatar";
		}

		private static PlayerDeathHead GetPlayerDeathHead(PlayerAvatar playerAvatar)
		{
			if ((Object)(object)playerAvatar == (Object)null)
			{
				return null;
			}
			if (FieldPlayerAvatarDeathHead != null)
			{
				try
				{
					object? value = FieldPlayerAvatarDeathHead.GetValue(playerAvatar);
					return (PlayerDeathHead)((value is PlayerDeathHead) ? value : null);
				}
				catch
				{
				}
			}
			try
			{
				return ((Component)playerAvatar).GetComponentInChildren<PlayerDeathHead>(true);
			}
			catch
			{
				return null;
			}
		}

		private static bool IsDeathHeadTriggered(PlayerDeathHead deathHead)
		{
			return GetBoolField(FieldPlayerDeathHeadTriggered, deathHead, defaultValue: false);
		}

		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;
			}
			try
			{
				val = ((Component)deathHead).GetComponent<PhysGrabObject>();
			}
			catch
			{
				val = null;
			}
			return val;
		}

		private bool HasQueuedLevelChanged(PendingReviveEntry entry)
		{
			if (entry == null)
			{
				return true;
			}
			string currentLevelName = GetCurrentLevelName();
			if (!string.IsNullOrEmpty(entry.LevelName) && !string.IsNullOrEmpty(currentLevelName) && !string.Equals(entry.LevelName, currentLevelName, StringComparison.Ordinal))
			{
				return true;
			}
			return false;
		}

		private string GetCurrentLevelName()
		{
			try
			{
				if ((Object)(object)RunManager.instance != (Object)null && (Object)(object)RunManager.instance.levelCurrent != (Object)null)
				{
					return ((Object)RunManager.instance.levelCurrent).name ?? string.Empty;
				}
			}
			catch
			{
			}
			return string.Empty;
		}

		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;
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInHaulList")]
	internal static class ExtractionPoint_DestroyAllPhysObjectsInHaulList_Patch
	{
		private static void Prefix()
		{
			ExtractionAutoRevivePlugin.EnterExtractionCompleteContext("haul");
		}

		private static Exception Finalizer(Exception __exception)
		{
			ExtractionAutoRevivePlugin.ExitExtractionCompleteContext("haul", __exception);
			return __exception;
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInShoppingList")]
	internal static class ExtractionPoint_DestroyAllPhysObjectsInShoppingList_Patch
	{
		private static void Prefix()
		{
			ExtractionAutoRevivePlugin.EnterExtractionCompleteContext("shop");
		}

		private static Exception Finalizer(Exception __exception)
		{
			ExtractionAutoRevivePlugin.ExitExtractionCompleteContext("shop", __exception);
			return __exception;
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "Revive")]
	internal static class PlayerDeathHead_Revive_Patch
	{
		private static bool Prefix()
		{
			if (ExtractionAutoRevivePlugin.IsExtractionCompleteContextActive())
			{
				return false;
			}
			return true;
		}
	}
	[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");
			}
		}
	}
}