Decompiled source of AddExtractionButton v0.2.0

BepInEx/plugins/AddExtractionButton/AddExtractionButton.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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 Photon.Realtime;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("DJ-DarkLucky")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+c1c6839f106c050be49a262ab27e7d8c2ac2ed9b")]
[assembly: AssemblyProduct("AddExtractionButton")]
[assembly: AssemblyTitle("AddExtractionButton")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 AddExtractionButton
{
	internal sealed class ExtractionClownController : MonoBehaviour
	{
		private readonly struct PlacementBasis
		{
			internal Vector3 Origin { get; }

			internal Vector3 Right { get; }

			internal Vector3 Up { get; }

			internal Vector3 Into { get; }

			internal Bounds StorageBounds { get; }

			internal float ExpectedFloor { get; }

			internal PlacementBasis(Vector3 origin, Vector3 right, Vector3 up, Vector3 into, Bounds storageBounds, float expectedFloor)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				Origin = origin;
				Right = right;
				Up = up;
				Into = into;
				StorageBounds = storageBounds;
				ExpectedFloor = expectedFloor;
			}
		}

		private sealed class DetachedCleanupEntry
		{
			internal GameObject Root { get; }

			internal ClownTrap? Clown { get; }

			internal int LookupId { get; }

			internal Room? Room { get; }

			internal PhotonView? RootView { get; }

			internal int RootViewId { get; }

			internal float NextAttemptAt { get; set; }

			internal bool FailureLogged { get; set; }

			internal DetachedCleanupEntry(GameObject root, ClownTrap? clown, int lookupId, Room? room, PhotonView? rootView, int rootViewId)
			{
				Root = root;
				Clown = clown;
				LookupId = lookupId;
				Room = room;
				RootView = rootView;
				RootViewId = rootViewId;
			}
		}

		private static readonly Dictionary<int, ExtractionClownController> ProxyOwners = new Dictionary<int, ExtractionClownController>();

		private static readonly List<DetachedCleanupEntry> DetachedCleanups = new List<DetachedCleanupEntry>();

		private static readonly HashSet<int> DetachedCleanupClownIds = new HashSet<int>();

		private static bool DetachedCleanupRunnerFailureLogged;

		private static readonly string[] ClownResourcePathCandidates = new string[2] { "valuables/03 medium/Valuable Clown", "valuables/03 medium/Valueable Clown" };

		private const float HeldSuccessDelaySeconds = 1.5f;

		private const float SpawnRetrySeconds = 1f;

		private const float PlacementFailureWarningDelaySeconds = 3f;

		private const float CleanupRetrySeconds = 1f;

		private const float PatchRevalidationSeconds = 1f;

		private const float AuthorityStabilizationSeconds = 1f;

		private const float InteractionRespawnCooldownSeconds = 0.35f;

		private const float StorageEdgeGap = 0.18f;

		private const float FloorClearance = 0.015f;

		private const float PlacementCollisionPadding = 0.035f;

		private const float PlacementCollisionSkin = 0.01f;

		private const float SupportProbeInset = 0.04f;

		private const float MaximumSupportHeightVariation = 0.035f;

		private const float MinimumSupportNormalDot = 0.65f;

		private const float ProxyBoundsTolerance = 0.05f;

		private const float SpawnPosePositionTolerance = 0.01f;

		private const float SpawnPoseRotationToleranceDegrees = 0.5f;

		private const float LockRefreshSeconds = 0.25f;

		private const float PositionCorrectionTolerance = 0.025f;

		private const float RotationCorrectionToleranceDegrees = 1f;

		private const float NetworkCorrectionCooldownSeconds = 0.2f;

		private const float MaximumFloorOffsetFromStorage = 1.25f;

		private const int NetworkProtocolVersion = 1;

		private ExtractionPoint _extractionPoint;

		private Transform _platform;

		private GameObject? _clownRoot;

		private GameObject? _orphanedSpawn;

		private ClownTrap? _clownTrap;

		private PhysGrabObject? _physGrabObject;

		private Rigidbody? _rigidbody;

		private Room? _clownSpawnRoom;

		private PhotonView? _clownRootPhotonView;

		private int _clownRootViewId;

		private bool _initialized;

		private bool _gateArmed;

		private bool _proxyConsumed;

		private bool _replacementRequested;

		private bool _pendingSuccess;

		private bool _successPermitAvailable;

		private bool _successPermitAccepted;

		private bool _successInvocationInProgress;

		private bool _submissionSent;

		private bool _blockedSuccessLogged;

		private bool _quotaPreviouslyReached;

		private bool _spawnFailureLogged;

		private bool _spawnAttemptDeferred;

		private bool _sessionFailedOpen;

		private bool _prefabInspectionWarningLogged;

		private bool _cleanupPending;

		private bool _wasCurrentActive;

		private bool _wasAuthoritative;

		private bool _destroyFailureLogged;

		private bool _controllerFailureLogged;

		private bool _staleProxyWarningLogged;

		private int _clownViewId;

		private float _nextSpawnAttemptAt;

		private float _placementFailureStartedAt = -1f;

		private float _replacementReadyAt;

		private float _nextNetworkCorrectionAt;

		private float _nextPatchRevalidationAt;

		private float _authorityReadyAt;

		private Vector3 _anchorPosition;

		private Quaternion _anchorRotation;

		private string? _resolvedResourcePath;

		private GameObject? _resolvedPrefab;

		private string? _lastDetailedSpawnFailure;

		private string? _nonRetryableSpawnFailure;

		internal void Initialize(ExtractionPoint extractionPoint)
		{
			_extractionPoint = extractionPoint;
			_platform = (((Object)(object)extractionPoint.platform != (Object)null) ? extractionPoint.platform : ((Component)extractionPoint).transform);
			_initialized = true;
			_wasAuthoritative = IsAuthoritative();
			_authorityReadyAt = (_wasAuthoritative ? Time.realtimeSinceStartup : float.PositiveInfinity);
			Plugin.LogDebug("Attached network-clown controller to '" + ((Object)extractionPoint).name + "'. Platform='" + ((Object)_platform).name + "', extractionArea='" + (((Object)(object)extractionPoint.extractionArea != (Object)null) ? ((Object)extractionPoint.extractionArea).name : "<none>") + "', ramp='" + (((Object)(object)extractionPoint.ramp != (Object)null) ? ((Object)extractionPoint.ramp).name : "<none>") + "'.");
		}

		internal static ExtractionClownController? FindOwner(ClownTrap clown)
		{
			int clownLookupId = GetClownLookupId(clown);
			if (clownLookupId == 0)
			{
				return null;
			}
			if (!ProxyOwners.TryGetValue(clownLookupId, out ExtractionClownController value))
			{
				return null;
			}
			if ((Object)(object)value == (Object)null)
			{
				ProxyOwners.Remove(clownLookupId);
				return null;
			}
			if (!value.OwnsClown(clown))
			{
				return null;
			}
			return value;
		}

		internal bool OwnsClown(ClownTrap clown)
		{
			if (_initialized && (Object)(object)_clownTrap != (Object)null && _clownTrap == clown && _clownViewId != 0)
			{
				return GetClownLookupId(clown) == _clownViewId;
			}
			return false;
		}

		internal bool ShouldSuppressExplosion(ClownTrap clown)
		{
			return OwnsClown(clown);
		}

		internal static bool ShouldSuppressDetachedCleanup(ClownTrap clown)
		{
			int clownLookupId = GetClownLookupId(clown);
			if (!DetachedCleanupClownIds.Contains(clownLookupId))
			{
				return false;
			}
			foreach (DetachedCleanupEntry detachedCleanup in DetachedCleanups)
			{
				if (detachedCleanup.LookupId == clownLookupId && (Object)(object)detachedCleanup.Root != (Object)null && (Object)(object)detachedCleanup.Clown != (Object)null && detachedCleanup.Clown == clown)
				{
					return true;
				}
			}
			return false;
		}

		internal static void RetryDetachedCleanup()
		{
			if (DetachedCleanups.Count == 0)
			{
				DetachedCleanupRunnerFailureLogged = false;
				return;
			}
			try
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				for (int num = DetachedCleanups.Count - 1; num >= 0; num--)
				{
					DetachedCleanupEntry detachedCleanupEntry = DetachedCleanups[num];
					if ((Object)(object)detachedCleanupEntry.Root == (Object)null)
					{
						RemoveDetachedCleanupAt(num);
					}
					else if (!(realtimeSinceStartup < detachedCleanupEntry.NextAttemptAt))
					{
						try
						{
							DestroyNetworkOrLocalObject(detachedCleanupEntry.Root, detachedCleanupEntry.Room, detachedCleanupEntry.RootView, detachedCleanupEntry.RootViewId);
							detachedCleanupEntry.NextAttemptAt = realtimeSinceStartup + 1f;
						}
						catch (Exception ex)
						{
							detachedCleanupEntry.NextAttemptAt = realtimeSinceStartup + 1f;
							if (!detachedCleanupEntry.FailureLogged)
							{
								detachedCleanupEntry.FailureLogged = true;
								Plugin.Log.LogError((object)("Detached cleanup for extraction clown " + $"ViewID={detachedCleanupEntry.LookupId} failed with " + ex.GetType().Name + ": " + ex.Message + ". Vanilla extraction is already available; cleanup will retry."));
							}
						}
					}
				}
				DetachedCleanupRunnerFailureLogged = false;
			}
			catch (Exception ex2)
			{
				if (!DetachedCleanupRunnerFailureLogged)
				{
					DetachedCleanupRunnerFailureLogged = true;
					Plugin.Log.LogError((object)("Detached extraction-clown cleanup runner failed with " + ex2.GetType().Name + ": " + ex2.Message + ". Vanilla extraction remains available."));
					Plugin.LogDebug(ex2.ToString());
				}
			}
		}

		internal void OnNosePressed(ClownTrap clown, int playerActorNumber)
		{
			if (Plugin.CriticalPatchesReady && _initialized && _gateArmed && !_proxyConsumed && !_submissionSent && SemiFunc.IsMasterClientOrSingleplayer() && IsCurrentActivePoint() && OwnsClown(clown))
			{
				_proxyConsumed = true;
				if (IsQuotaReached())
				{
					_pendingSuccess = true;
					Plugin.LogDebug($"Quota confirmation received from clown ViewID={_clownViewId}, " + $"playerActor={playerActorNumber}, haul={_extractionPoint.haulCurrent}/{_extractionPoint.haulGoal}. " + "Vanilla Success will be requested on the next host frame.");
				}
				else if (TryScheduleDeniedReplacement(playerActorNumber))
				{
					Plugin.LogDebug($"Pre-quota clown press accepted from playerActor={playerActorNumber}, " + $"haul={_extractionPoint.haulCurrent}/{_extractionPoint.haulGoal}. " + "The consumed clown stays visible and will be refreshed after " + $"{0.35f:0.##} seconds.");
				}
			}
		}

		internal bool AllowVanillaStateSet(State requestedState)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if (!Plugin.CriticalPatchesReady)
			{
				return true;
			}
			if (!_initialized || (int)requestedState != 3 || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return true;
			}
			if (_successPermitAvailable)
			{
				_successPermitAvailable = false;
				if (IsQuotaReached())
				{
					_successPermitAccepted = true;
					_blockedSuccessLogged = false;
					return true;
				}
				return false;
			}
			if (_submissionSent)
			{
				return !IsCurrentActivePoint();
			}
			if (!_gateArmed || !IsCurrentActivePoint())
			{
				return true;
			}
			ApplySubmissionGate();
			if (!_blockedSuccessLogged)
			{
				_blockedSuccessLogged = true;
				Plugin.LogDebug("Blocked vanilla Success at '" + ((Object)_extractionPoint).name + "' until the network clown nose is pressed with the quota filled.");
			}
			return false;
		}

		internal void BeforeVanillaUpdate()
		{
			TickExtractionSession();
		}

		internal void AfterVanillaUpdate()
		{
			TickExtractionSession();
		}

		internal void BeforeVanillaStateActive()
		{
			TickExtractionSession();
		}

		internal void AfterVanillaStateSet()
		{
			if (_initialized)
			{
				if (!_successInvocationInProgress)
				{
					ObserveActivationState();
				}
				RetryPendingCleanup();
			}
		}

		internal void FailOpenFromRuntimeFailure(string callback, Exception exception)
		{
			if (!_initialized)
			{
				return;
			}
			try
			{
				FailOpenForActivation(callback + " failed with " + exception.GetType().Name + ": " + exception.Message, logAsError: false, logFailure: false);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Emergency fail-open after " + callback + " also threw " + ex.GetType().Name + ": " + ex.Message + ". The Harmony callback will still allow vanilla game logic to continue."));
			}
		}

		internal void FailOpenFromRuntimeCondition(string reason)
		{
			if (_initialized)
			{
				FailOpenForActivation(reason);
			}
		}

		private void TickExtractionSession()
		{
			if (!_initialized)
			{
				return;
			}
			bool flag = RefreshAuthorityState();
			bool flag2 = ObserveActivationState();
			RetryPendingCleanup();
			if (!flag || !flag2)
			{
				return;
			}
			if (_sessionFailedOpen)
			{
				ReleaseVanillaSubmission();
			}
			else if (!Plugin.CriticalPatchesReady)
			{
				if (_gateArmed || (Object)(object)_clownRoot != (Object)null)
				{
					FailOpenForActivation("critical Harmony patches are no longer available");
				}
			}
			else if (_submissionSent)
			{
				if (!HasPendingVanillaSuccess())
				{
					FailOpenForActivation("the accepted vanilla Success request stopped pending while the extraction point remained Active");
				}
				else
				{
					ReleaseVanillaSubmission();
				}
			}
			else
			{
				if (_cleanupPending || Time.realtimeSinceStartup < _authorityReadyAt)
				{
					return;
				}
				EnsureSessionStarted();
				if (_gateArmed)
				{
					string failure;
					if (IsWaitingForReplacementProxy())
					{
						ApplySubmissionGate();
					}
					else if (!TryValidateProxy(out failure))
					{
						FailOpenForActivation(failure);
					}
					else
					{
						ApplySubmissionGate();
					}
				}
			}
		}

		private void LateUpdate()
		{
			try
			{
				RunLateUpdate();
			}
			catch (Exception exception)
			{
				HandleControllerFailure("LateUpdate", exception);
			}
		}

		private void RunLateUpdate()
		{
			if (!_initialized)
			{
				return;
			}
			bool flag = RefreshAuthorityState();
			bool flag2 = ObserveActivationState();
			RetryPendingCleanup();
			if (!flag || !flag2)
			{
				return;
			}
			if (_sessionFailedOpen)
			{
				ReleaseVanillaSubmission();
				return;
			}
			if (!Plugin.CriticalPatchesReady)
			{
				if (_gateArmed || (Object)(object)_clownRoot != (Object)null)
				{
					FailOpenForActivation("critical Harmony patches are no longer available");
				}
				return;
			}
			if (_gateArmed && Time.realtimeSinceStartup >= _nextPatchRevalidationAt)
			{
				_nextPatchRevalidationAt = Time.realtimeSinceStartup + 1f;
				if (!Plugin.RevalidateCriticalPatches())
				{
					FailOpenForActivation("critical Harmony patch revalidation failed at runtime");
					return;
				}
			}
			if (_cleanupPending)
			{
				return;
			}
			if (_pendingSuccess)
			{
				ProcessPendingSuccess();
			}
			else if (_replacementRequested)
			{
				ReplaceConsumedClown();
			}
			if (_gateArmed && !_sessionFailedOpen && IsCurrentActivePoint() && !IsWaitingForReplacementProxy())
			{
				string failure2;
				if (!TryValidateProxy(out string failure))
				{
					FailOpenForActivation(failure);
				}
				else if (!TryMaintainClownLock(forceNetworkCorrection: false, out failure2))
				{
					FailOpenForActivation(failure2);
				}
			}
		}

		private void FixedUpdate()
		{
			try
			{
				if (_initialized && _gateArmed && !_sessionFailedOpen && IsAuthoritative() && !IsWaitingForReplacementProxy() && IsCurrentActivePoint())
				{
					string failure2;
					if (!TryValidateProxy(out string failure))
					{
						FailOpenForActivation(failure);
					}
					else if (!TryMaintainClownLock(forceNetworkCorrection: false, out failure2))
					{
						FailOpenForActivation(failure2);
					}
				}
			}
			catch (Exception exception)
			{
				HandleControllerFailure("FixedUpdate", exception);
			}
		}

		private void OnDisable()
		{
			try
			{
				if (_initialized)
				{
					if (IsCurrentActivePoint())
					{
						FailOpenForActivation("the extraction controller was disabled", logAsError: false, logFailure: false);
						return;
					}
					_wasCurrentActive = false;
					_sessionFailedOpen = false;
					_controllerFailureLogged = false;
					EndSession("the extraction controller was disabled");
				}
			}
			catch (Exception exception)
			{
				HandleControllerFailure("OnDisable", exception);
			}
		}

		private void OnDestroy()
		{
			try
			{
				if (_initialized)
				{
					EndSession("the extraction controller was destroyed");
				}
			}
			catch (Exception exception)
			{
				HandleControllerFailure("OnDestroy", exception);
			}
			finally
			{
				try
				{
					TransferCleanupToDetachedRunner();
				}
				finally
				{
					_initialized = false;
				}
			}
		}

		private void EnsureSessionStarted()
		{
			if (!Plugin.CriticalPatchesReady || _gateArmed || _submissionSent || _sessionFailedOpen || _cleanupPending || Time.realtimeSinceStartup < _authorityReadyAt || Time.realtimeSinceStartup < _nextSpawnAttemptAt || !Plugin.RevalidateCriticalPatches())
			{
				return;
			}
			if (TrySpawnClown())
			{
				_gateArmed = true;
				_quotaPreviouslyReached = IsQuotaReached();
				_spawnFailureLogged = false;
				ApplySubmissionGate();
				Plugin.Log.LogInfo((object)("Extraction confirmation gate armed at '" + ((Object)_extractionPoint).name + "'. Automatic submission is held until the network clown nose is pressed."));
			}
			else if (_nonRetryableSpawnFailure != null)
			{
				FailOpenForActivation(_nonRetryableSpawnFailure);
			}
			else
			{
				_nextSpawnAttemptAt = Time.realtimeSinceStartup + 1f;
				if (!_spawnAttemptDeferred && !_spawnFailureLogged)
				{
					_spawnFailureLogged = true;
					Plugin.Log.LogError((object)("Could not create the network clown at '" + ((Object)_extractionPoint).name + "'. Vanilla extraction remains available while the mod retries."));
				}
			}
		}

		private bool RefreshAuthorityState()
		{
			bool flag = IsAuthoritative();
			if (flag == _wasAuthoritative)
			{
				return flag;
			}
			_wasAuthoritative = flag;
			if (flag)
			{
				_authorityReadyAt = Time.realtimeSinceStartup + 1f;
				_nextSpawnAttemptAt = Mathf.Max(_nextSpawnAttemptAt, _authorityReadyAt);
				Plugin.LogDebug("Host authority acquired for '" + ((Object)_extractionPoint).name + "'. Waiting briefly for the previous actor-owned proxy to leave the room cache.");
				return true;
			}
			_authorityReadyAt = float.PositiveInfinity;
			if (_gateArmed || (Object)(object)_clownRoot != (Object)null || _submissionSent)
			{
				FailOpenForActivation("the local player lost host authority", logAsError: false, logFailure: false);
			}
			return false;
		}

		private bool ObserveActivationState()
		{
			bool flag = IsCurrentActivePoint();
			if (flag && !_wasCurrentActive)
			{
				_wasCurrentActive = true;
				BeginActivation();
			}
			else if (!flag && _wasCurrentActive)
			{
				_wasCurrentActive = false;
				EndSession(_submissionSent ? "the extraction point left Active after submission" : "the extraction point left Active before submission");
				_sessionFailedOpen = false;
				_spawnFailureLogged = false;
				_controllerFailureLogged = false;
			}
			return flag;
		}

		private void BeginActivation()
		{
			_sessionFailedOpen = false;
			_gateArmed = false;
			_replacementRequested = false;
			_pendingSuccess = false;
			_successPermitAvailable = false;
			_successPermitAccepted = false;
			_successInvocationInProgress = false;
			_submissionSent = false;
			_replacementReadyAt = 0f;
			_blockedSuccessLogged = false;
			_quotaPreviouslyReached = false;
			_spawnFailureLogged = false;
			_spawnAttemptDeferred = false;
			_prefabInspectionWarningLogged = false;
			_controllerFailureLogged = false;
			_staleProxyWarningLogged = false;
			_lastDetailedSpawnFailure = null;
			_nonRetryableSpawnFailure = null;
			_placementFailureStartedAt = -1f;
			_nextPatchRevalidationAt = 0f;
			Plugin.LogDebug("Started extraction confirmation lifecycle for '" + ((Object)_extractionPoint).name + "'.");
		}

		private void FailOpenForActivation(string reason, bool logAsError = true, bool logFailure = true)
		{
			bool flag = !_sessionFailedOpen;
			bool flag2 = _gateArmed || (Object)(object)_clownRoot != (Object)null || _pendingSuccess || _replacementRequested || _submissionSent || _nonRetryableSpawnFailure != null;
			_wasCurrentActive = true;
			_sessionFailedOpen = true;
			_gateArmed = false;
			_replacementRequested = false;
			_pendingSuccess = false;
			_successPermitAvailable = false;
			_successPermitAccepted = false;
			_successInvocationInProgress = false;
			_submissionSent = false;
			_replacementReadyAt = 0f;
			_blockedSuccessLogged = false;
			ReleaseVanillaSubmission();
			if ((Object)(object)_clownRoot != (Object)null && !_cleanupPending)
			{
				DestroyCurrentClown("the controller failed open: " + reason);
			}
			if (flag && flag2 && logFailure)
			{
				string text = "Extraction confirmation at '" + ((Object)_extractionPoint).name + "' failed open: " + reason + ". Vanilla extraction is restored for this activation.";
				if (logAsError)
				{
					Plugin.Log.LogError((object)text);
				}
				else
				{
					Plugin.Log.LogWarning((object)text);
				}
			}
		}

		private void ReleaseVanillaSubmission()
		{
			if ((Object)(object)_extractionPoint != (Object)null)
			{
				_extractionPoint.successDelay = 0f;
			}
		}

		private void HandleControllerFailure(string callback, Exception exception)
		{
			bool flag = !_controllerFailureLogged;
			_controllerFailureLogged = true;
			try
			{
				FailOpenForActivation(callback + " threw " + exception.GetType().Name + ": " + exception.Message, logAsError: false, logFailure: false);
			}
			catch (Exception ex)
			{
				if (flag)
				{
					Plugin.Log.LogError((object)("Emergency fail-open from " + callback + " also threw " + ex.GetType().Name + ": " + ex.Message + "."));
				}
			}
			if (flag)
			{
				Plugin.Log.LogError((object)(callback + " failed with " + exception.GetType().Name + ": " + exception.Message + ". Vanilla extraction was allowed to continue."));
				Plugin.LogDebug(exception.ToString());
			}
		}

		private bool TryValidateProxy(out string failure)
		{
			failure = string.Empty;
			if ((Object)(object)_clownRoot == (Object)null || !_clownRoot.activeInHierarchy || (Object)(object)_clownTrap == (Object)null || (Object)(object)_physGrabObject == (Object)null)
			{
				failure = "the active extraction clown disappeared or became inactive";
				return false;
			}
			if ((_clownTrap.CountDownActive || _clownTrap.NoseSqueezeActive) && !_proxyConsumed)
			{
				failure = "the vanilla clown nose was consumed without a completed mod callback";
				return false;
			}
			if (_proxyConsumed && !_pendingSuccess && !_replacementRequested && !_submissionSent)
			{
				failure = "the extraction clown was consumed without a pending replacement or submission";
				return false;
			}
			if (!OwnsClown(_clownTrap))
			{
				failure = "the active extraction clown lost its ownership registration";
				return false;
			}
			if (PhotonNetwork.InRoom)
			{
				PhotonView clownPhotonView = GetClownPhotonView(_clownTrap);
				if ((Object)(object)clownPhotonView == (Object)null || clownPhotonView.ViewID == 0 || !clownPhotonView.IsMine)
				{
					failure = "the active extraction clown lost its valid network ownership";
					return false;
				}
			}
			return true;
		}

		private void RetryPendingCleanup()
		{
			if (_cleanupPending && !((Object)(object)_orphanedSpawn != (Object)null))
			{
				_orphanedSpawn = null;
				if (!((Object)(object)_clownRoot != (Object)null))
				{
					ClearProxyReferences();
					_cleanupPending = false;
					_destroyFailureLogged = false;
				}
			}
		}

		private void ApplySubmissionGate()
		{
			if (!_gateArmed || _submissionSent)
			{
				return;
			}
			bool flag = IsQuotaReached();
			_extractionPoint.successDelay = 1.5f;
			if (flag != _quotaPreviouslyReached)
			{
				_quotaPreviouslyReached = flag;
				if (flag)
				{
					Plugin.LogDebug("Quota reached at '" + ((Object)_extractionPoint).name + "'. Automatic submission remains held until the clown nose is pressed.");
				}
				else
				{
					Plugin.LogDebug("Quota is no longer reached at '" + ((Object)_extractionPoint).name + "'.");
				}
			}
		}

		private void ProcessPendingSuccess()
		{
			_pendingSuccess = false;
			if (!_gateArmed || _submissionSent || !IsCurrentActivePoint())
			{
				return;
			}
			if (!IsQuotaReached())
			{
				_proxyConsumed = true;
				TryScheduleDeniedReplacement(-1);
				return;
			}
			try
			{
				_successInvocationInProgress = true;
				_successPermitAvailable = true;
				_successPermitAccepted = false;
				_submissionSent = true;
				_extractionPoint.successDelay = 0f;
				_extractionPoint.StateSet((State)3);
				if (IsCurrentActivePoint() && (!_successPermitAccepted || !HasPendingVanillaSuccess()))
				{
					FailOpenForActivation("the one-shot vanilla StateSet(Success) request was not registered");
					return;
				}
				Plugin.LogDebug("Clown confirmation submitted '" + ((Object)_extractionPoint).name + "' through vanilla " + $"StateSet(Success), haul={_extractionPoint.haulCurrent}/{_extractionPoint.haulGoal}.");
			}
			catch (Exception ex)
			{
				if (IsCurrentActivePoint())
				{
					FailOpenForActivation("vanilla StateSet(Success) threw " + ex.GetType().Name + ": " + ex.Message);
				}
				else
				{
					EndSession("vanilla StateSet(Success) changed the extraction state before throwing");
				}
				return;
			}
			finally
			{
				_successInvocationInProgress = false;
				_successPermitAvailable = false;
				_successPermitAccepted = false;
			}
			_gateArmed = false;
			DestroyCurrentClown("vanilla extraction Success started");
		}

		private void ReplaceConsumedClown()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (!_gateArmed || _submissionSent || !IsCurrentActivePoint())
			{
				_replacementRequested = false;
				_replacementReadyAt = 0f;
			}
			else
			{
				if (Time.realtimeSinceStartup < _replacementReadyAt)
				{
					return;
				}
				Vector3 anchorPosition = _anchorPosition;
				Quaternion anchorRotation = _anchorRotation;
				if (((Object)(object)_clownRoot != (Object)null || (Object)(object)_clownTrap != (Object)null || _clownViewId != 0) && !DestroyCurrentClown("the denied nose press cooldown elapsed"))
				{
					FailOpenForActivation("the used extraction clown could not be removed before replacement");
					return;
				}
				_replacementRequested = false;
				_replacementReadyAt = 0f;
				if (!TrySpawnClown(checkStaleProxies: false, anchorPosition, anchorRotation))
				{
					FailOpenForActivation("a fresh extraction clown could not be created after the nose press");
				}
			}
		}

		private bool TryPrepareNetworkSpawn(bool checkStaleProxies, out string failure)
		{
			failure = string.Empty;
			if (!PhotonNetwork.InRoom)
			{
				return true;
			}
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (currentRoom == null)
			{
				failure = "Photon reports InRoom without an available CurrentRoom";
				return false;
			}
			if (!currentRoom.AutoCleanUp || currentRoom.PlayerTtl != 0)
			{
				failure = "The Photon room cannot guarantee host-only proxy cleanup: " + $"AutoCleanUp={currentRoom.AutoCleanUp}, PlayerTtl={currentRoom.PlayerTtl}. " + "Vanilla extraction will remain active";
				return false;
			}
			if (!checkStaleProxies)
			{
				return true;
			}
			bool flag = false;
			PhotonView[] array = Object.FindObjectsOfType<PhotonView>(true);
			foreach (PhotonView val in array)
			{
				if (!IsMarkedExtractionProxy(val))
				{
					continue;
				}
				if (!val.IsMine)
				{
					_spawnAttemptDeferred = true;
					failure = $"a previous extraction proxy ViewID={val.ViewID} is still " + $"controlled by actor {val.ControllerActorNr}";
					if (!_staleProxyWarningLogged)
					{
						_staleProxyWarningLogged = true;
						Plugin.Log.LogWarning((object)("Waiting for " + failure + ". Vanilla extraction remains available and no duplicate proxy will be spawned."));
					}
					return false;
				}
				try
				{
					int viewID = val.ViewID;
					GameObject gameObject = ((Component)val).gameObject;
					ClownTrap componentInChildren = gameObject.GetComponentInChildren<ClownTrap>(true);
					int lookupId = (((Object)(object)componentInChildren != (Object)null) ? GetClownLookupId(componentInChildren) : viewID);
					DetachedCleanupEntry detachedCleanupEntry = QueueDetachedCleanup(gameObject, componentInChildren, lookupId, currentRoom, val, viewID);
					DestroyNetworkOrLocalObject(gameObject, detachedCleanupEntry.Room, detachedCleanupEntry.RootView, detachedCleanupEntry.RootViewId);
					flag = true;
					Plugin.LogDebug($"Removed stale marked extraction proxy ViewID={viewID} " + "before creating a new confirmation session.");
				}
				catch (Exception ex)
				{
					failure = $"Removing stale extraction proxy ViewID={val.ViewID} failed " + "with " + ex.GetType().Name + ": " + ex.Message;
					return false;
				}
			}
			if (flag)
			{
				_spawnAttemptDeferred = true;
				Plugin.LogDebug("Deferred extraction clown spawn for one retry after stale proxy cleanup.");
				return false;
			}
			_staleProxyWarningLogged = false;
			return true;
		}

		private static bool IsMarkedExtractionProxy(PhotonView view)
		{
			if ((Object)(object)view == (Object)null || view.ViewID == 0 || view.InstantiationId != view.ViewID)
			{
				return false;
			}
			object[] instantiationData = view.InstantiationData;
			if (instantiationData != null && instantiationData.Length >= 2 && instantiationData[0] is string a)
			{
				return string.Equals(a, "DJDarkLucky.AddExtractionButton", StringComparison.Ordinal);
			}
			return false;
		}

		private bool TrySpawnClown(bool checkStaleProxies = true, Vector3? preservedAnchorPosition = null, Quaternion? preservedAnchorRotation = null)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			//IL_0430: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0531: Unknown result type (might be due to invalid IL or missing references)
			//IL_054d: Unknown result type (might be due to invalid IL or missing references)
			_spawnAttemptDeferred = false;
			_nonRetryableSpawnFailure = null;
			if (_cleanupPending)
			{
				return false;
			}
			if ((Object)(object)_clownRoot != (Object)null)
			{
				return true;
			}
			if (!TryPrepareNetworkSpawn(checkStaleProxies, out string failure))
			{
				if (!_spawnAttemptDeferred)
				{
					LogDetailedSpawnFailure(failure);
				}
				return false;
			}
			if (!TryResolveClownPrefab(out string resourcePath, out GameObject prefab))
			{
				return false;
			}
			bool flag = preservedAnchorPosition.HasValue && preservedAnchorRotation.HasValue;
			if (preservedAnchorPosition.HasValue != preservedAnchorRotation.HasValue)
			{
				LogDetailedSpawnFailure("A preserved extraction-clown pose must include both position and rotation.");
				return false;
			}
			PlacementBasis basis = default(PlacementBasis);
			Bounds offsets = default(Bounds);
			Vector3 position;
			Quaternion desiredRotation;
			string text;
			if (flag)
			{
				position = preservedAnchorPosition.GetValueOrDefault();
				desiredRotation = preservedAnchorRotation.GetValueOrDefault();
				text = "preserved previous extraction proxy pose";
			}
			else
			{
				if (!TryPreparePlacementBasis(out basis, out desiredRotation, out text))
				{
					LogDetailedSpawnFailure("Could not calculate a clown placement at '" + ((Object)_extractionPoint).name + "': " + text + ".");
					return false;
				}
				if (!TryMeasureProxyOffsets(prefab, desiredRotation, basis, out offsets, out string source))
				{
					LogDetailedSpawnFailure("Could not measure the vanilla clown before network spawn: " + source + ".");
					return false;
				}
				if (!TryCalculateFinalPose(basis, offsets, out position, out string source2))
				{
					ReportTransientPlacementFailure("No safe floor placement was found at '" + ((Object)_extractionPoint).name + "': " + source2 + ".");
					return false;
				}
				text = text + ", geometry=" + source + ", final=" + source2;
			}
			GameObject val = null;
			try
			{
				if (PhotonNetwork.InRoom)
				{
					if (!PhotonNetwork.IsMasterClient)
					{
						return false;
					}
					val = PhotonNetwork.Instantiate(resourcePath, position, desiredRotation, (byte)0, new object[2] { "DJDarkLucky.AddExtractionButton", 1 });
				}
				else
				{
					val = Object.Instantiate<GameObject>(prefab, position, desiredRotation);
				}
				if (!TryValidateSpawnPose(val, position, desiredRotation, out string diagnostics))
				{
					DestroyUntrackedSpawn(val);
					LogNonRetryableSpawnFailure("The vanilla clown did not instantiate at its calculated final pose: " + diagnostics + ".");
					return false;
				}
				if (!TryMakeClownEconomicallyNeutral(val, out string diagnostics2))
				{
					DestroyUntrackedSpawn(val);
					LogNonRetryableSpawnFailure("The spawned extraction clown could not be made economically neutral: " + diagnostics2 + ".");
					return false;
				}
				ClownTrap componentInChildren = val.GetComponentInChildren<ClownTrap>(true);
				PhysGrabObject val2 = (((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.physgrabobject != (Object)null) ? componentInChildren.physgrabobject : (((Object)(object)componentInChildren != (Object)null && (Object)(object)((Trap)componentInChildren).physGrabObject != (Object)null) ? ((Trap)componentInChildren).physGrabObject : val.GetComponentInChildren<PhysGrabObject>(true)));
				PhotonView val3 = (PhotonView)(((Object)(object)componentInChildren != (Object)null) ? ((object)GetClownPhotonView(componentInChildren)) : ((object)val.GetComponentInChildren<PhotonView>(true)));
				Room val4 = (PhotonNetwork.InRoom ? PhotonNetwork.CurrentRoom : null);
				PhotonView val5 = ((val4 != null) ? FindRootNetworkView(val) : null);
				if ((Object)(object)componentInChildren == (Object)null || (Object)(object)val2 == (Object)null || (val4 != null && ((Object)(object)val3 == (Object)null || val3.ViewID == 0 || (Object)(object)val5 == (Object)null || val5.ViewID == 0)))
				{
					DestroyUntrackedSpawn(val);
					LogNonRetryableSpawnFailure("Resolved prefab '" + resourcePath + "' did not create a usable ClownTrap + PhysGrabObject + root PhotonView instance.");
					return false;
				}
				string text2;
				if (flag)
				{
					text2 = "spawnPose=" + diagnostics + ", geometry='preserved pose reuse'";
				}
				else
				{
					if (!TryValidateSpawnedGeometry(basis, val, offsets, position, out text2))
					{
						DestroyUntrackedSpawn(val);
						LogNonRetryableSpawnFailure("The spawned extraction clown did not match its preflight geometry: " + text2 + ".");
						return false;
					}
					text2 = "spawnPose=" + diagnostics + ", " + text2;
				}
				_clownRoot = val;
				_clownTrap = componentInChildren;
				_physGrabObject = val2;
				_rigidbody = (((Object)(object)val2.rb != (Object)null) ? val2.rb : val.GetComponentInChildren<Rigidbody>(true));
				_clownViewId = GetClownLookupId(componentInChildren);
				_clownSpawnRoom = val4;
				_clownRootPhotonView = val5;
				_clownRootViewId = (((Object)(object)val5 != (Object)null) ? val5.ViewID : 0);
				_anchorPosition = position;
				_anchorRotation = desiredRotation;
				ProxyOwners[_clownViewId] = this;
				_proxyConsumed = false;
				_replacementRequested = false;
				_nextSpawnAttemptAt = 0f;
				_replacementReadyAt = 0f;
				_nextNetworkCorrectionAt = 0f;
				_cleanupPending = false;
				_destroyFailureLogged = false;
				_staleProxyWarningLogged = false;
				if (!TryMaintainClownLock(forceNetworkCorrection: true, out string failure2))
				{
					DestroyCurrentClown("the initial proxy lock failed");
					LogNonRetryableSpawnFailure("The spawned extraction clown could not be locked safely: " + failure2 + ".");
					return false;
				}
				_lastDetailedSpawnFailure = null;
				_placementFailureStartedAt = -1f;
				Plugin.LogDebug("Spawned network clown for '" + ((Object)_extractionPoint).name + "': resourcePath='" + resourcePath + "', prefab='" + ((Object)prefab).name + "', " + $"ViewID={_clownViewId}, position={FormatVector(_anchorPosition)}, " + "rotation=" + FormatQuaternion(_anchorRotation) + ", value=" + diagnostics2 + ", placement=" + text + ", verification=" + text2 + ", network=" + GetNetworkLifecycleSnapshot(val) + ", visual=" + GetSpawnVisualSnapshot(val) + ".");
				return true;
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					DestroyUntrackedSpawn(val);
					LogNonRetryableSpawnFailure("Network clown post-instantiation setup failed with " + ex.GetType().Name + ": " + ex.Message + ".");
				}
				else
				{
					LogDetailedSpawnFailure("Network clown spawn failed with " + ex.GetType().Name + ": " + ex.Message + ".");
				}
				ClearProxyReferences();
				return false;
			}
		}

		private static bool TryMakeClownEconomicallyNeutral(GameObject spawned, out string diagnostics)
		{
			diagnostics = string.Empty;
			try
			{
				ValuableObject[] componentsInChildren = spawned.GetComponentsInChildren<ValuableObject>(true);
				if (componentsInChildren.Length != 1)
				{
					diagnostics = $"expected exactly one ValuableObject, found {componentsInChildren.Length}";
					return false;
				}
				ValuableObject val = componentsInChildren[0];
				float dollarValueOriginal = val.dollarValueOriginal;
				float dollarValueCurrent = val.dollarValueCurrent;
				int dollarValueOverride = val.dollarValueOverride;
				bool dollarValueSet = val.dollarValueSet;
				val.dollarValueOverride = 0;
				val.dollarValueOriginal = 0f;
				val.dollarValueCurrent = 0f;
				val.dollarValueSet = true;
				int num = 0;
				if (PhotonNetwork.InRoom)
				{
					PhotonView val2 = (((Object)(object)val.photonView != (Object)null) ? val.photonView : ((Component)val).GetComponent<PhotonView>());
					if ((Object)(object)val2 == (Object)null || val2.ViewID == 0)
					{
						diagnostics = "the ValuableObject has no valid PhotonView for value synchronization";
						return false;
					}
					num = val2.ViewID;
					val2.RPC("DollarValueSetRPC", (RpcTarget)4, new object[1] { 0f });
				}
				if (!val.dollarValueSet || !Mathf.Approximately(val.dollarValueOriginal, 0f) || !Mathf.Approximately(val.dollarValueCurrent, 0f))
				{
					diagnostics = "the zero-value invariant did not hold after assignment";
					return false;
				}
				RoundDirector instance = RoundDirector.instance;
				string arg = (((Object)(object)instance != (Object)null) ? ($"currentHaul={instance.currentHaul}, " + $"currentHaulMax={instance.currentHaulMax}, " + $"haulGoal={instance.haulGoal}, " + $"haulGoalMax={instance.haulGoalMax}") : "<unavailable>");
				diagnostics = $"previous=(original={dollarValueOriginal:0.##}, " + $"current={dollarValueCurrent:0.##}, override={dollarValueOverride}, " + $"set={dollarValueSet}), current=(original=0, current=0, set=True), " + $"valueViewID={num}, round=({arg})";
				return true;
			}
			catch (Exception ex)
			{
				diagnostics = ex.GetType().Name + ": " + ex.Message;
				return false;
			}
		}

		private bool TryResolveClownPrefab(out string resourcePath, out GameObject prefab)
		{
			if (!string.IsNullOrEmpty(_resolvedResourcePath) && (Object)(object)_resolvedPrefab != (Object)null && IsClownPrefab(_resolvedPrefab))
			{
				resourcePath = _resolvedResourcePath;
				prefab = _resolvedPrefab;
				return true;
			}
			ValuableDirector instance = ValuableDirector.instance;
			if ((Object)(object)instance != (Object)null && instance.mediumValuables != null)
			{
				foreach (PrefabRef mediumValuable in instance.mediumValuables)
				{
					if (mediumValuable == null)
					{
						continue;
					}
					try
					{
						GameObject prefab2 = ((PrefabRef<GameObject>)(object)mediumValuable).Prefab;
						if ((Object)(object)prefab2 != (Object)null && IsClownPrefab(prefab2) && !string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)mediumValuable).ResourcePath))
						{
							return CacheResolvedPrefab(((PrefabRef<GameObject>)(object)mediumValuable).ResourcePath, prefab2, out resourcePath, out prefab);
						}
					}
					catch (Exception ex)
					{
						if (!_prefabInspectionWarningLogged)
						{
							_prefabInspectionWarningLogged = true;
							Plugin.Log.LogWarning((object)("Inspecting a vanilla medium valuable PrefabRef failed with " + ex.GetType().Name + ": " + ex.Message + "."));
						}
					}
				}
			}
			string[] clownResourcePathCandidates = ClownResourcePathCandidates;
			foreach (string text in clownResourcePathCandidates)
			{
				GameObject val = Resources.Load<GameObject>(text);
				if ((Object)(object)val != (Object)null && IsClownPrefab(val))
				{
					return CacheResolvedPrefab(text, val, out resourcePath, out prefab);
				}
			}
			GameObject[] array = Resources.LoadAll<GameObject>("valuables/03 medium");
			foreach (GameObject val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null) && IsClownPrefab(val2))
				{
					string text2 = "valuables/03 medium/" + ((Object)val2).name;
					GameObject val3 = Resources.Load<GameObject>(text2);
					if ((Object)(object)val3 != (Object)null && IsClownPrefab(val3))
					{
						return CacheResolvedPrefab(text2, val3, out resourcePath, out prefab);
					}
				}
			}
			resourcePath = string.Empty;
			prefab = null;
			LogDetailedSpawnFailure("The vanilla Valuable Clown prefab could not be found in Resources.");
			return false;
		}

		private bool CacheResolvedPrefab(string path, GameObject candidate, out string resourcePath, out GameObject prefab)
		{
			_resolvedResourcePath = path;
			_resolvedPrefab = candidate;
			resourcePath = path;
			prefab = candidate;
			Plugin.LogDebug("Resolved vanilla clown prefab: path='" + path + "', prefab='" + ((Object)candidate).name + "'.");
			return true;
		}

		private static bool IsClownPrefab(GameObject candidate)
		{
			return (Object)(object)candidate.GetComponentInChildren<ClownTrap>(true) != (Object)null;
		}

		private bool TryPreparePlacementBasis(out PlacementBasis basis, out Quaternion desiredRotation, out string source)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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_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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_010f: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: 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_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: 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_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
			basis = default(PlacementBasis);
			desiredRotation = Quaternion.identity;
			source = string.Empty;
			Vector3 position = _platform.position;
			Vector3 val = _platform.up;
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			if (!TryGetWorldCenter(_extractionPoint.extractionArea, out var center))
			{
				center = _platform.position + _platform.forward;
			}
			Vector3 val2 = (((Object)(object)_extractionPoint.ramp != (Object)null) ? _extractionPoint.ramp.position : (_platform.position - _platform.forward));
			Vector3 val3 = Vector3.ProjectOnPlane(center - val2, normalized);
			if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
			{
				val3 = Vector3.ProjectOnPlane(_platform.forward, normalized);
			}
			if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
			{
				source = "could not determine the direction from the ramp into the platform";
				return false;
			}
			((Vector3)(ref val3)).Normalize();
			val = Vector3.Cross(normalized, val3);
			Vector3 normalized2 = ((Vector3)(ref val)).normalized;
			Bounds val4 = CreateSyntheticStorageBounds(position, normalized2, normalized, val3, center, val2);
			float num = Vector3.Dot(val2 - position, normalized);
			float expectedFloor = ((Mathf.Abs(num) <= 1.25f) ? num : 0f);
			basis = new PlacementBasis(position, normalized2, normalized, val3, val4, expectedFloor);
			desiredRotation = Quaternion.LookRotation(-val3, normalized);
			source = "storageBoundsSource='fixed ramp-relative footprint', storageBounds=" + FormatBounds(val4) + ", platformWorld=" + FormatVector(position) + ", rampWorld=" + FormatVector(val2) + ", areaWorld=" + FormatVector(center);
			return true;
		}

		private static bool TryMeasureProxyOffsets(GameObject root, Quaternion desiredRotation, PlacementBasis basis, out Bounds offsets, out string source)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			offsets = default(Bounds);
			source = string.Empty;
			try
			{
				Bounds offsets2 = default(Bounds);
				bool initialized = false;
				int num = 0;
				int num2 = 0;
				Transform transform = root.transform;
				Collider[] componentsInChildren = root.GetComponentsInChildren<Collider>(true);
				foreach (Collider val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null) && !val.isTrigger && TryGetColliderLocalBounds(val, out var localBounds))
					{
						EncapsulatePrefabLocalBounds(transform, ((Component)val).transform, localBounds, desiredRotation, basis, ref offsets2, ref initialized);
						num++;
					}
				}
				Renderer[] componentsInChildren2 = root.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren2)
				{
					if (!((Object)(object)val2 == (Object)null) && !(val2 is ParticleSystemRenderer) && !(val2 is TrailRenderer) && !(val2 is LineRenderer))
					{
						Bounds localBounds2 = val2.localBounds;
						if (IsFiniteBounds(localBounds2))
						{
							EncapsulatePrefabLocalBounds(transform, ((Component)val2).transform, localBounds2, desiredRotation, basis, ref offsets2, ref initialized);
							num2++;
						}
					}
				}
				if (!initialized || num == 0)
				{
					source = "usable physical bounds were not found " + $"(colliders={num}, renderers={num2})";
					return false;
				}
				offsets = offsets2;
				source = "offsets=" + FormatBounds(offsets) + ", " + $"colliders={num}, renderers={num2}";
				return true;
			}
			catch (Exception ex)
			{
				source = ex.GetType().Name + ": " + ex.Message;
				return false;
			}
		}

		private static bool TryGetColliderLocalBounds(Collider collider, out Bounds localBounds)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			BoxCollider val = (BoxCollider)(object)((collider is BoxCollider) ? collider : null);
			if (val == null)
			{
				SphereCollider val2 = (SphereCollider)(object)((collider is SphereCollider) ? collider : null);
				if (val2 == null)
				{
					CapsuleCollider val3 = (CapsuleCollider)(object)((collider is CapsuleCollider) ? collider : null);
					if (val3 == null)
					{
						CharacterController val4 = (CharacterController)(object)((collider is CharacterController) ? collider : null);
						if (val4 == null)
						{
							MeshCollider val5 = (MeshCollider)(object)((collider is MeshCollider) ? collider : null);
							if (val5 == null || !((Object)(object)val5.sharedMesh != (Object)null))
							{
								localBounds = default(Bounds);
								return false;
							}
							localBounds = val5.sharedMesh.bounds;
						}
						else
						{
							float num = val4.radius * 2f;
							localBounds = new Bounds(val4.center, new Vector3(num, Mathf.Max(val4.height, num), num));
						}
					}
					else
					{
						float num2 = val3.radius * 2f;
						Vector3 val6 = Vector3.one * num2;
						float num3 = Mathf.Max(val3.height, num2);
						if (val3.direction == 0)
						{
							val6.x = num3;
						}
						else if (val3.direction == 1)
						{
							val6.y = num3;
						}
						else
						{
							val6.z = num3;
						}
						localBounds = new Bounds(val3.center, val6);
					}
				}
				else
				{
					localBounds = new Bounds(val2.center, Vector3.one * (val2.radius * 2f));
				}
			}
			else
			{
				localBounds = new Bounds(val.center, val.size);
			}
			if (!TryCompensateColliderBoundsForPhysicsScale(collider, ref localBounds))
			{
				return false;
			}
			return IsFiniteBounds(localBounds);
		}

		private static bool TryCompensateColliderBoundsForPhysicsScale(Collider collider, ref Bounds localBounds)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			if (!(collider is SphereCollider) && !(collider is CapsuleCollider) && !(collider is CharacterController))
			{
				return true;
			}
			Vector3 lossyScale = ((Component)collider).transform.lossyScale;
			float[] array = new float[3]
			{
				Mathf.Abs(lossyScale.x),
				Mathf.Abs(lossyScale.y),
				Mathf.Abs(lossyScale.z)
			};
			if (array[0] < 0.0001f || array[1] < 0.0001f || array[2] < 0.0001f)
			{
				return false;
			}
			Vector3 size = ((Bounds)(ref localBounds)).size;
			SphereCollider val = (SphereCollider)(object)((collider is SphereCollider) ? collider : null);
			if (val != null)
			{
				float num = val.radius * 2f * Mathf.Max(new float[3]
				{
					array[0],
					array[1],
					array[2]
				});
				size.x = num / array[0];
				size.y = num / array[1];
				size.z = num / array[2];
			}
			else
			{
				CapsuleCollider val2 = (CapsuleCollider)(object)((collider is CapsuleCollider) ? collider : null);
				int num2;
				float radius;
				float height;
				if (val2 != null)
				{
					num2 = Mathf.Clamp(val2.direction, 0, 2);
					radius = val2.radius;
					height = val2.height;
				}
				else
				{
					CharacterController val3 = (CharacterController)collider;
					num2 = 1;
					radius = val3.radius;
					height = val3.height;
				}
				int num3 = ((num2 == 0) ? 1 : 0);
				int num4 = ((num2 == 2) ? 1 : 2);
				float num5 = Mathf.Max(array[num3], array[num4]);
				float num6 = radius * 2f * num5;
				float num7 = Mathf.Max(height * array[num2], num6);
				((Vector3)(ref size))[num3] = num6 / array[num3];
				((Vector3)(ref size))[num4] = num6 / array[num4];
				((Vector3)(ref size))[num2] = num7 / array[num2];
			}
			((Bounds)(ref localBounds)).size = size;
			return true;
		}

		private static void EncapsulatePrefabLocalBounds(Transform prefabRoot, Transform componentTransform, Bounds localBounds, Quaternion desiredRotation, PlacementBasis basis, ref Bounds offsets, ref bool initialized)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			Vector3 rootScale = prefabRoot.localScale;
			Bounds collectedOffsets = offsets;
			bool hasOffsets = initialized;
			ForEachBoundsCorner(localBounds, delegate(Vector3 localPoint)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = prefabRoot.InverseTransformPoint(componentTransform.TransformPoint(localPoint));
				Vector3 val2 = desiredRotation * Vector3.Scale(val, rootScale);
				Vector3 point = default(Vector3);
				((Vector3)(ref point))..ctor(Vector3.Dot(val2, basis.Right), Vector3.Dot(val2, basis.Up), Vector3.Dot(val2, basis.Into));
				EncapsulatePoint(ref collectedOffsets, ref hasOffsets, point);
			});
			offsets = collectedOffsets;
			initialized = hasOffsets;
		}

		private bool TryCalculateFinalPose(PlacementBasis basis, Bounds proxyOffsets, out Vector3 position, out string source)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_043e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			source = string.Empty;
			float expectedFloor = basis.ExpectedFloor;
			Bounds storageBounds = basis.StorageBounds;
			float item = ((Bounds)(ref storageBounds)).min.x - 0.18f - ((Bounds)(ref proxyOffsets)).max.x;
			storageBounds = basis.StorageBounds;
			float item2 = ((Bounds)(ref storageBounds)).max.x + 0.18f - ((Bounds)(ref proxyOffsets)).min.x;
			storageBounds = basis.StorageBounds;
			float num = ((Bounds)(ref storageBounds)).min.z - 0.18f - ((Bounds)(ref proxyOffsets)).max.z;
			storageBounds = basis.StorageBounds;
			float x = ((Bounds)(ref storageBounds)).min.x;
			storageBounds = basis.StorageBounds;
			float item3 = Mathf.Lerp(x, ((Bounds)(ref storageBounds)).max.x, 0.2f) - ((Bounds)(ref proxyOffsets)).center.x;
			storageBounds = basis.StorageBounds;
			float x2 = ((Bounds)(ref storageBounds)).min.x;
			storageBounds = basis.StorageBounds;
			float item4 = Mathf.Lerp(x2, ((Bounds)(ref storageBounds)).max.x, 0.8f) - ((Bounds)(ref proxyOffsets)).center.x;
			List<(string, float, float, bool, bool)> list = new List<(string, float, float, bool, bool)>();
			float[] array = new float[3] { 0f, 0.2f, 0.4f };
			float[] array2 = array;
			foreach (float num2 in array2)
			{
				string text = ((num2 > 0f) ? $" +{num2:0.##}m" : string.Empty);
				float item5 = num - num2;
				list.Add(("entrance left" + text, item3, item5, true, false));
				list.Add(("entrance right" + text, item4, item5, true, false));
			}
			float[] array3 = new float[2] { 0.25f, 0.65f };
			float[] array4 = array3;
			foreach (float num3 in array4)
			{
				storageBounds = basis.StorageBounds;
				float z = ((Bounds)(ref storageBounds)).min.z;
				storageBounds = basis.StorageBounds;
				float item6 = Mathf.Lerp(z, ((Bounds)(ref storageBounds)).max.z, num3) - ((Bounds)(ref proxyOffsets)).center.z;
				list.Add(($"left side {num3:0.##}", item, item6, false, true));
				list.Add(($"right side {num3:0.##}", item2, item6, false, true));
			}
			List<string> list2 = new List<string>();
			foreach (var (text2, num4, num5, flag, flag2) in list)
			{
				if (flag)
				{
					float num6 = num4 + ((Bounds)(ref proxyOffsets)).min.x;
					storageBounds = basis.StorageBounds;
					if (!(num6 < ((Bounds)(ref storageBounds)).min.x))
					{
						float num7 = num4 + ((Bounds)(ref proxyOffsets)).max.x;
						storageBounds = basis.StorageBounds;
						if (!(num7 > ((Bounds)(ref storageBounds)).max.x))
						{
							goto IL_0329;
						}
					}
					list2.Add(text2 + ": footprint exceeds platform width");
					continue;
				}
				goto IL_0329;
				IL_0391:
				if (!TryFindSupportedFloor(basis, num4, num5, proxyOffsets, expectedFloor, null, out float floor, out string floorSource))
				{
					list2.Add(text2 + ": " + floorSource);
					continue;
				}
				float num8 = floor + 0.015f - ((Bounds)(ref proxyOffsets)).min.y;
				Vector3 val = basis.Origin + basis.Right * num4 + basis.Up * num8 + basis.Into * num5;
				if (!TryValidatePlacementClearance(basis, val, proxyOffsets, null, out string source2))
				{
					list2.Add(text2 + ": " + source2);
					continue;
				}
				position = val;
				source = "candidate='" + text2 + "', proxyOffsets=" + FormatBounds(proxyOffsets) + ", " + $"floor='{floorSource}', floorOffset={floor - expectedFloor:0.###}, " + "clearance='clear'";
				return true;
				IL_0329:
				if (flag2)
				{
					float num9 = num5 + ((Bounds)(ref proxyOffsets)).min.z;
					storageBounds = basis.StorageBounds;
					if (!(num9 < ((Bounds)(ref storageBounds)).min.z))
					{
						float num10 = num5 + ((Bounds)(ref proxyOffsets)).max.z;
						storageBounds = basis.StorageBounds;
						if (!(num10 > ((Bounds)(ref storageBounds)).max.z))
						{
							goto IL_0391;
						}
					}
					list2.Add(text2 + ": footprint exceeds platform depth");
					continue;
				}
				goto IL_0391;
			}
			source = "no fully supported collision-free candidate was found; proxyOffsets=" + FormatBounds(proxyOffsets) + ", rejections=[" + string.Join("; ", list2) + "]";
			return false;
		}

		private bool TryFindSupportedFloor(PlacementBasis basis, float targetRight, float targetInto, Bounds proxyOffsets, float expectedFloor, Transform? excludedRoot, out float floor, out string floorSource)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			floor = expectedFloor;
			floorSource = string.Empty;
			float num = Mathf.Min(0.04f, ((Bounds)(ref proxyOffsets)).size.x * 0.25f);
			float num2 = Mathf.Min(0.04f, ((Bounds)(ref proxyOffsets)).size.z * 0.25f);
			float item = ((Bounds)(ref proxyOffsets)).min.x + num;
			float item2 = ((Bounds)(ref proxyOffsets)).max.x - num;
			float item3 = ((Bounds)(ref proxyOffsets)).min.z + num2;
			float item4 = ((Bounds)(ref proxyOffsets)).max.z - num2;
			(string, float, float)[] array = new(string, float, float)[5]
			{
				("center", ((Bounds)(ref proxyOffsets)).center.x, ((Bounds)(ref proxyOffsets)).center.z),
				("near-left", item, item3),
				("near-right", item2, item3),
				("far-left", item, item4),
				("far-right", item2, item4)
			};
			float num3 = float.MaxValue;
			float num4 = float.MinValue;
			HashSet<string> hashSet = new HashSet<string>();
			List<string> list = new List<string>();
			(string, float, float)[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				var (text, num5, num6) = array2[i];
				if (!TryFindFloorAtProbe(basis, targetRight + num5, targetInto + num6, expectedFloor, excludedRoot, out float floor2, out string floorSource2))
				{
					floorSource = "support probe '" + text + "' found no usable floor";
					return false;
				}
				num3 = Mathf.Min(num3, floor2);
				num4 = Mathf.Max(num4, floor2);
				hashSet.Add(floorSource2);
				list.Add($"{text}={floor2:0.###}@'{floorSource2}'");
			}
			float num7 = num4 - num3;
			if (num7 > 0.035f)
			{
				floorSource = $"support height varies by {num7:0.###}m across the footprint " + "[" + string.Join(", ", list) + "]";
				return false;
			}
			floor = num4;
			List<string> list2 = new List<string>(hashSet);
			list2.Sort(StringComparer.Ordinal);
			floorSource = string.Format("{0}, probes={1}, ", string.Join(" | ", list2), array.Length) + $"variation={num7:0.###}";
			return true;
		}

		private static bool TryFindFloorAtProbe(PlacementBasis basis, float targetRight, float targetInto, float expectedFloor, Transform? excludedRoot, out float floor, out string floorSource)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			floor = expectedFloor;
			floorSource = string.Empty;
			Vector3 val = basis.Origin + basis.Right * targetRight + basis.Into * targetInto + basis.Up * (expectedFloor + 3f);
			RaycastHit[] array = Physics.RaycastAll(val, -basis.Up, 8f, -1, (QueryTriggerInteraction)1);
			bool result = false;
			float num = float.MaxValue;
			RaycastHit[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				RaycastHit val2 = array2[i];
				Collider collider = ((RaycastHit)(ref val2)).collider;
				if (!((Object)(object)collider == (Object)null) && !IsSameOrChildOf(((Component)collider).transform, excludedRoot) && !((Object)(object)((Component)collider).GetComponentInParent<PhysGrabObject>() != (Object)null) && !(Vector3.Dot(((RaycastHit)(ref val2)).normal, basis.Up) < 0.65f))
				{
					float num2 = Vector3.Dot(((RaycastHit)(ref val2)).point - basis.Origin, basis.Up);
					float num3 = Mathf.Abs(num2 - expectedFloor);
					if (!(num3 > 1.25f) && !(num3 >= num))
					{
						num = num3;
						floor = num2;
						floorSource = GetTransformPath(((Component)collider).transform);
						result = true;
					}
				}
			}
			return result;
		}

		private static bool TryValidatePlacementClearance(PlacementBasis basis, Vector3 rootPosition, Bounds proxyOffsets, Transform? excludedRoot, out string source)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			Vector3 extents = ((Bounds)(ref proxyOffsets)).extents;
			extents.x = Mathf.Max(extents.x + 0.035f, 0.035f);
			extents.y = Mathf.Max(extents.y - 0.01f, 0.01f);
			extents.z = Mathf.Max(extents.z + 0.035f, 0.035f);
			Vector3 val = rootPosition + basis.Right * ((Bounds)(ref proxyOffsets)).center.x + basis.Up * ((Bounds)(ref proxyOffsets)).center.y + basis.Into * ((Bounds)(ref proxyOffsets)).center.z;
			Quaternion val2 = Quaternion.LookRotation(basis.Into, basis.Up);
			Collider[] array = Physics.OverlapBox(val, extents, val2, -1, (QueryTriggerInteraction)1);
			HashSet<string> hashSet = new HashSet<string>();
			int num = 0;
			Collider[] array2 = array;
			foreach (Collider val3 in array2)
			{
				if (!((Object)(object)val3 == (Object)null) && !IsSameOrChildOf(((Component)val3).transform, excludedRoot))
				{
					num++;
					hashSet.Add(GetTransformPath(((Component)val3).transform));
				}
			}
			if (num == 0)
			{
				source = "clear";
				return true;
			}
			source = $"volume overlaps {num} collider(s): " + FormatSortedPaths(hashSet);
			return false;
		}

		private static string FormatSortedPaths(HashSet<string> paths)
		{
			List<string> list = new List<string>(paths);
			list.Sort(StringComparer.Ordinal);
			int num = Mathf.Max(list.Count - 4, 0);
			if (num > 0)
			{
				list.RemoveRange(4, num);
			}
			string text = string.Join(" | ", list);
			if (num <= 0)
			{
				return text;
			}
			return $"{text} | ... +{num} path(s)";
		}

		private bool TryValidateSpawnedGeometry(PlacementBasis basis, GameObject spawned, Bounds plannedOffsets, Vector3 spawnPosition, out string source)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_00d8: 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)
			if (!TryMeasureProxyOffsets(spawned, spawned.transform.rotation, basis, out Bounds offsets, out string source2))
			{
				source = "the live object exposed no usable local geometry: " + source2;
				return false;
			}
			if (!BoundsCoveredByPlan(plannedOffsets, offsets) || Mathf.Abs(((Bounds)(ref plannedOffsets)).min.y - ((Bounds)(ref offsets)).min.y) > 0.05f)
			{
				source = "plannedOffsets=" + FormatBounds(plannedOffsets) + ", actualOffsets=" + FormatBounds(offsets) + ", " + $"tolerance={0.05f:0.###}";
				return false;
			}
			if (!TryValidatePlacementClearance(basis, spawnPosition, offsets, spawned.transform, out string source3))
			{
				source = "post-spawn clearance failed: " + source3 + ", plannedOffsets=" + FormatBounds(plannedOffsets) + ", actualOffsets=" + FormatBounds(offsets);
				return false;
			}
			source = "plannedOffsets=" + FormatBounds(plannedOffsets) + ", actualOffsets=" + FormatBounds(offsets) + ", clearance='clear'";
			return true;
		}

		private static bool TryValidateSpawnPose(GameObject spawned, Vector3 expectedPosition, Quaternion expectedRotation, out string diagnostics)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			float num = Vector3.Distance(spawned.transform.position, expectedPosition);
			float num2 = Quaternion.Angle(spawned.transform.rotation, expectedRotation);
			diagnostics = $"positionDelta={num:0.####}, " + $"rotationDelta={num2:0.###}";
			if (num <= 0.01f)
			{
				return num2 <= 0.5f;
			}
			return false;
		}

		private static bool BoundsCoveredByPlan(Bounds planned, Bounds actual)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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)
			Vector3 val = ((Bounds)(ref planned)).min - Vector3.one * 0.05f;
			Vector3 val2 = ((Bounds)(ref planned)).max + Vector3.one * 0.05f;
			Vector3 min = ((Bounds)(ref actual)).min;
			Vector3 max = ((Bounds)(ref actual)).max;
			if (min.x >= val.x && min.y >= val.y && min.z >= val.z && max.x <= val2.x && max.y <= val2.y)
			{
				return max.z <= val2.z;
			}
			return false;
		}

		private bool TryMaintainClownLock(bool forceNetworkCorrection, out string failure)
		{
			//IL_00ac: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: 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_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			failure = string.Empty;
			if ((Object)(object)_clownRoot == (Object)null || (Object)(object)_physGrabObject == (Object)null)
			{
				failure = "the extraction clown lock lost its root or PhysGrabObject";
				return false;
			}
			try
			{
				_physGrabObject.OverrideKinematic(0.25f);
				_physGrabObject.OverrideIndestructible(0.25f);
				if ((Object)(object)_rigidbody != (Object)null)
				{
					if (!_rigidbody.isKinematic)
					{
						_rigidbody.velocity = Vector3.zero;
						_rigidbody.angularVelocity = Vector3.zero;
					}
					_rigidbody.constraints = (RigidbodyConstraints)126;
					_rigidbody.isKinematic = true;
				}
				bool flag = Vector3.Distance(_clownRoot.transform.position, _anchorPosition) > 0.025f;
				bool flag2 = Quaternion.Angle(_clownRoot.transform.rotation, _anchorRotation) > 1f;
				if (!forceNetworkCorrection && !flag && !flag2)
				{
					return true;
				}
				_clownRoot.transform.SetPositionAndRotation(_anchorPosition, _anchorRotation);
				if ((Object)(object)_rigidbody != (Object)null)
				{
					_rigidbody.position = _anchorPosition;
					_rigidbody.rotation = _anchorRotation;
				}
				if (PhotonNetwork.InRoom && (forceNetworkCorrection || Time.realtimeSinceStartup >= _nextNetworkCorrectionAt))
				{
					if (!TryResolvePositionSynchronizationView(out PhotonView positionView, out failure))
					{
						return false;
					}
					_nextNetworkCorrectionAt = Time.realtimeSinceStartup + 0.2f;
					positionView.RPC("SetPositionRPC", (RpcTarget)(forceNetworkCorrection ? 1 : 0), new object[2] { _anchorPosition, _anchorRotation });
				}
				else if (!PhotonNetwork.InRoom)
				{
					_physGrabObject.SetPositionLogic(_anchorPosition, _anchorRotation);
				}
				return true;
			}
			catch (Exception ex)
			{
				failure = "maintaining the extraction clown lock threw " + ex.GetType().Name + ": " + ex.Message;
				return false;
			}
		}

		private bool TryResolvePositionSynchronizationView(out PhotonView positionView, out string failure)
		{
			positionView = null;
			failure = string.Empty;
			if ((Object)(object)_physGrabObject == (Object)null)
			{
				failure = "the extraction clown lost its PhysGrabObject before position synchronization";
				return false;
			}
			GameObject gameObject = ((Component)_physGrabObject).gameObject;
			PhotonView photonView = _physGrabObject.photonView;
			if ((Object)(object)photonView != (Object)null && (Object)(object)((Component)photonView).gameObject == (Object)(object)gameObject)
			{
				positionView = photonView;
			}
			else
			{
				PhotonView component = gameObject.GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null)
				{
					failure = "the extraction clown has no PhotonView on the PhysGrabObject GameObject for position synchronization";
					return false;
				}
				positionView = component;
				_physGrabObject.photonView = component;
			}
			if (positionView.ViewID == 0)
			{
				failure = "the extraction clown position PhotonView has no allocated ViewID";
				return false;
			}
			if ((Object)(object)PhotonView.Find(positionView.ViewID) != (Object)(object)positionView)
			{
				failure = $"the extraction clown position PhotonView ViewID={positionView.ViewID} " + "is not the registered room instance";
				return false;
			}
			if (!positionView.IsMine)
			{
				failure = $"the extraction clown position PhotonView ViewID={positionView.ViewID} " + $"is controlled by actor {positionView.ControllerActorNr}";
				return false;
			}
			return true;
		}

		private bool TryScheduleDeniedReplacement(int playerActorNumber)
		{
			if (!TryPlayVanillaDeny(playerActorNumber, out string failure))
			{
				FailOpenForActivation(failure);
				return false;
			}
			_replacementRequested = true;
			_replacementReadyAt = Time.realtimeSinceStartup + 0.35f;
			Plugin.LogDebug("Scheduled one seamless extraction-clown refresh after " + $"{0.35f:0.##} seconds; the consumed " + "proxy remains visible until the swap.");
			return true;
		}

		private bool IsWaitingForReplacementProxy()
		{
			if (_gateArmed && _replacementRequested && (Object)(object)_clownRoot == (Object)null)
			{
				return !_sessionFailedOpen;
			}
			return false;
		}

		private bool HasPendingVanillaSuccess()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			if (_extractionPoint.settingState)
			{
				return (int)_extractionPoint.stateSetTo == 3;
			}
			return false;
		}

		private bool TryPlayVanillaDeny(int playerActorNumber, out string failure)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			failure = string.Empty;
			try
			{
				PhotonView photonView = _extractionPoint.photonView;
				if (PhotonNetwork.InRoom && (Object)(object)photonView != (Object)null && photonView.ViewID != 0)
				{
					photonView.RPC("ButtonDenyRPC", (RpcTarget)0, Array.Empty<object>());
				}
				else
				{
					_extractionPoint.ButtonDenyRPC(default(PhotonMessageInfo));
				}
				Plugin.LogDebug("Played vanilla ButtonDenyRPC for clown press by " + $"playerActor={playerActorNumber}.");
				return true;
			}
			catch (Exception ex)
			{
				failure = "vanilla ButtonDenyRPC failed with " + ex.GetType().Name + ": " + ex.Message;
				return false;
			}
		}

		private bool DestroyCurrentClown(string reason)
		{
			GameObject clownRoot = _clownRoot;
			int clownViewId = _clownViewId;
			DetachedCleanupEntry detachedCleanupEntry = null;
			if ((Object)(object)clownRoot == (Object)null)
			{
				ClearProxyReferences();
				return true;
			}
			try
			{
				detachedCleanupEntry = QueueDetachedCleanup(clownRoot, _clownTrap, clownViewId, _clownSpawnRoom, _clownRootPhotonView, _clownRootViewId);
				DestroyNetworkOrLocalObject(clownRoot, detachedCleanupEntry.Room, detachedCleanupEntry.RootView, detachedCleanupEntry.RootViewId);
			}
			catch (Exception ex)
			{
				if (detachedCleanupEntry != null)
				{
					detachedCleanupEntry.FailureLogged = true;
				}
				ScheduleCleanupFailure($"Destroying extraction clown ViewID={clownViewId} failed with " + ex.GetType().Name + ": " + ex.Message);
				return false;
			}
			ClearProxyReferences();
			Plugin.LogDebug($"Removed network clown ViewID={clownViewId} because {reason}.");
			return true;
		}

		private bool DestroyUntrackedSpawn(GameObject spawned)
		{
			DetachedCleanupEntry detachedCleanupEntry = null;
			try
			{
				detachedCleanupEntry = QueueDetachedCleanup(spawned, spawned.GetComponentInChildren<ClownTrap>(true), 0);
				DestroyNetworkOrLocalObject(spawned, detachedCleanupEntry.Room, detachedCleanupEntry.RootView, detachedCleanupEntry.RootViewId);
			}
			catch (Exception ex)
			{
				if (detachedCleanupEntry != null)
				{
					detachedCleanupEntry.FailureLogged = true;
				}
				_orphanedSpawn = spawned;
				ScheduleCleanupFailure("Cleaning up an unusable extraction clown failed with " + ex.GetType().Name + ": " + ex.Message);
				return false;
			}
			if (_orphanedSpawn == spawned)
			{
				_orphanedSpawn = null;
			}
			if ((Object)(object)_clownRoot == (Object)null)
			{
				_cleanupPending = false;
				_destroyFailureLogged = false;
			}
			return true;
		}

		private static void DestroyNetworkOrLocalObject(GameObject root, Room? expectedRoom, PhotonView? expectedRootView, int expectedRootViewId)
		{
			if (expectedRoom == null || !PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom != expectedRoom)
			{
				Object.Destroy((Object)(object)root);
				return;
			}
			if ((Object)(object)expectedRootView == (Object)null || expectedRootViewId == 0 || expectedRootView.ViewID != expectedRootViewId || PhotonView.Find(expectedRootViewId) != expectedRootView)
			{
				Object.Destroy((Object)(object)root);
				return;
			}
			if (!expectedRootView.IsMine)
			{
				throw new InvalidOperationException($"local actor does not control PhotonView {expectedRootViewId}");
			}
			PhotonNetwork.Destroy(expectedRootView);
		}

		private static PhotonView? FindRootNetworkView(GameObject root)
		{
			PhotonView[] componentsInChildren = root.GetComponentsInChildren<PhotonView>(true);
			foreach (PhotonView val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.ViewID != 0 && val.InstantiationId == val.ViewID)
				{
					return val;
				}
			}
			return null;
		}

		private void ScheduleCleanupFailure(string reason)
		{
			_cleanupPending = true;
			if (!_destroyFailureLogged)
			{
				_destroyFailureLogged = true;
				Plugin.Log.LogError((object)(reason + ". Vanilla extraction is already available; network cleanup will be retried in the background."));
			}
		}

		private void EndSession(string reason)
		{
			bool flag = _gateArmed || (Object)(object)_clownRoot != (Object)null || (Object)(object)_orphanedSpawn != (Object)null || _submissionSent;
			ReleaseVanillaSubmission();
			_gateArmed = false;
			_replacementRequested = false;
			_pendingSuccess = false;
			_successPermitAvailable = false;
			_successPermitAccepted = false;
			_successInvocationInProgress = false;
			_submissionSent = false;
			_replacementReadyAt = 0f;
			_blockedSuccessLogged = false;
			DestroyCurrentClown(reason);
			if ((Object)(object)_orphanedSpawn != (Object)null)
			{
				DestroyUntrackedSpawn(_orphanedSpawn);
			}
			if (flag)
			{