Decompiled source of Manual Extraction Confirm v0.1.0

ManualExtractionConfirm.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ExtractionConfirm
{
	[BepInPlugin("yourname.extractionconfirm", "Extraction Confirm", "2.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "yourname.extractionconfirm";

		public const string PluginName = "Extraction Confirm";

		public const string PluginVersion = "2.0.0";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("yourname.extractionconfirm");
			try
			{
				_harmony.PatchAll();
			}
			catch (Exception ex)
			{
				Log.LogError((object)"ExtractionConfirm: PatchAll threw — patches may be partially or fully unapplied.");
				Log.LogError((object)ex.ToString());
			}
			Fields.ValidateOrLog();
			Log.LogInfo((object)string.Format("{0} v{1} loaded.", "Extraction Confirm", "2.0.0"));
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		internal static bool IsHost()
		{
			if (!PhotonNetwork.IsConnected)
			{
				return true;
			}
			return PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient;
		}
	}
	internal static class Fields
	{
		private static readonly FieldInfo CurrentStateField = AccessTools.Field(typeof(ExtractionPoint), "currentState");

		private static readonly FieldInfo IsShopField = AccessTools.Field(typeof(ExtractionPoint), "isShop");

		private static readonly FieldInfo HaulCurrentField = AccessTools.Field(typeof(ExtractionPoint), "haulCurrent");

		private static readonly FieldInfo HaulGoalField = AccessTools.Field(typeof(ExtractionPoint), "haulGoal");

		private static readonly MethodInfo StateSetMethod = AccessTools.Method(typeof(ExtractionPoint), "StateSet", new Type[1] { typeof(State) }, (Type[])null);

		private static readonly FieldInfo TruckScreenInstanceField = AccessTools.Field(typeof(TruckScreenText), "instance");

		private static readonly FieldInfo ChargeChatLoopField = AccessTools.Field(typeof(TruckScreenText), "chargeChatLoop");

		private static readonly FieldInfo EngineRevSoundField = AccessTools.Field(typeof(TruckScreenText), "engineRevSound");

		private static readonly FieldInfo ChatMessageResultSuccessField = AccessTools.Field(typeof(TruckScreenText), "chatMessageResultSuccess");

		private static readonly FieldInfo ChatMessageResultFailField = AccessTools.Field(typeof(TruckScreenText), "chatMessageResultFail");

		private static readonly FieldInfo PlatformField = AccessTools.Field(typeof(ExtractionPoint), "platform");

		private static readonly FieldInfo HaulGoalScreenField = AccessTools.Field(typeof(ExtractionPoint), "haulGoalScreen");

		private static readonly FieldInfo TubeScreenTextField = AccessTools.Field(typeof(ExtractionPoint), "tubeScreenText");

		private static readonly FieldInfo EmojiScreenField = AccessTools.Field(typeof(ExtractionPoint), "emojiScreen");

		private static readonly FieldInfo EmojiLightField = AccessTools.Field(typeof(ExtractionPoint), "emojiLight");

		private static readonly FieldInfo EmojiLightIntensityField = AccessTools.Field(typeof(ExtractionPoint), "emojiLightIntensity");

		private static readonly FieldInfo GrabbedField = AccessTools.Field(typeof(PhysGrabObject), "grabbed");

		private static readonly FieldInfo StaticGrabbedField = AccessTools.Field(typeof(StaticGrabObject), "grabbed");

		public static bool IsGrabbed(StaticGrabObject obj)
		{
			if (StaticGrabbedField == null || (Object)(object)obj == (Object)null)
			{
				return false;
			}
			return (bool)StaticGrabbedField.GetValue(obj);
		}

		public static bool IsGrabbed(PhysGrabObject obj)
		{
			if (GrabbedField == null || (Object)(object)obj == (Object)null)
			{
				return false;
			}
			return (bool)GrabbedField.GetValue(obj);
		}

		public static Transform GetPlatform(ExtractionPoint point)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if (PlatformField == null)
			{
				return null;
			}
			return (Transform)PlatformField.GetValue(point);
		}

		public static Transform GetHaulGoalScreenTransform(ExtractionPoint point)
		{
			if (HaulGoalScreenField == null)
			{
				return null;
			}
			object value = HaulGoalScreenField.GetValue(point);
			Component val = (Component)((value is Component) ? value : null);
			return (!((Object)(object)val != (Object)null)) ? null : val.transform;
		}

		public static Transform GetTubeScreenTextTransform(ExtractionPoint point)
		{
			if (TubeScreenTextField == null)
			{
				return null;
			}
			object value = TubeScreenTextField.GetValue(point);
			Component val = (Component)((value is Component) ? value : null);
			return (!((Object)(object)val != (Object)null)) ? null : val.transform;
		}

		public static Transform GetEmojiScreenTransform(ExtractionPoint point)
		{
			if (EmojiScreenField == null)
			{
				return null;
			}
			object value = EmojiScreenField.GetValue(point);
			Component val = (Component)((value is Component) ? value : null);
			return (!((Object)(object)val != (Object)null)) ? null : val.transform;
		}

		public static object GetHaulGoalScreenComponent(ExtractionPoint point)
		{
			if (HaulGoalScreenField == null)
			{
				return null;
			}
			return HaulGoalScreenField.GetValue(point);
		}

		public static Light GetEmojiLight(ExtractionPoint point)
		{
			if (EmojiLightField == null)
			{
				return null;
			}
			object? value = EmojiLightField.GetValue(point);
			return (Light)((value is Light) ? value : null);
		}

		public static float GetEmojiLightIntensity(ExtractionPoint point)
		{
			if (EmojiLightIntensityField == null)
			{
				return 1f;
			}
			return (float)EmojiLightIntensityField.GetValue(point);
		}

		public static Color? GetColorReflective(object component)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (component == null)
			{
				return null;
			}
			PropertyInfo property = component.GetType().GetProperty("color");
			if (property == null)
			{
				return null;
			}
			return (Color)property.GetValue(component, null);
		}

		public static void SetColorReflective(object component, Color color)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (component != null)
			{
				PropertyInfo property = component.GetType().GetProperty("color");
				if (property != null)
				{
					property.SetValue(component, color, null);
				}
			}
		}

		public static void ValidateOrLog()
		{
			LogIfNull(CurrentStateField, "currentState");
			LogIfNull(IsShopField, "isShop");
			LogIfNull(HaulCurrentField, "haulCurrent");
			LogIfNull(HaulGoalField, "haulGoal");
			LogIfNull(StateSetMethod, "StateSet");
			LogIfNull(PlatformField, "platform");
			LogIfNull(HaulGoalScreenField, "haulGoalScreen");
			LogIfNull(TubeScreenTextField, "tubeScreenText");
			LogIfNull(TruckScreenInstanceField, "TruckScreenText.instance");
			LogIfNull(ChargeChatLoopField, "TruckScreenText.chargeChatLoop");
			LogIfNull(EngineRevSoundField, "TruckScreenText.engineRevSound");
			LogIfNull(ChatMessageResultSuccessField, "TruckScreenText.chatMessageResultSuccess");
			LogIfNull(ChatMessageResultFailField, "TruckScreenText.chatMessageResultFail");
			LogIfNull(GrabbedField, "PhysGrabObject.grabbed");
			LogIfNull(StaticGrabbedField, "StaticGrabObject.grabbed");
			LogIfNull(EmojiScreenField, "emojiScreen");
			LogIfNull(EmojiLightField, "emojiLight");
			LogIfNull(EmojiLightIntensityField, "emojiLightIntensity");
		}

		private static void LogIfNull(object member, string name)
		{
			if (member == null)
			{
				Plugin.Log.LogError((object)("ExtractionConfirm: reflection lookup failed for '" + name + "' — field/method name may have changed."));
			}
		}

		public static State CurrentState(ExtractionPoint point)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return (State)CurrentStateField.GetValue(point);
		}

		public static bool IsShop(ExtractionPoint point)
		{
			return (bool)IsShopField.GetValue(point);
		}

		public static bool QuotaReached(ExtractionPoint point)
		{
			int num = (int)HaulCurrentField.GetValue(point);
			int num2 = (int)HaulGoalField.GetValue(point);
			return num >= num2;
		}

		public static void CallStateSet(ExtractionPoint point, State value)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (StateSetMethod == null)
			{
				Plugin.Log.LogError((object)"ExtractionConfirm: could not find ExtractionPoint.StateSet via reflection.");
				return;
			}
			StateSetMethod.Invoke(point, new object[1] { value });
		}

		public static Sound GetTruckChargeSound()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if (TruckScreenInstanceField == null || ChargeChatLoopField == null)
			{
				return null;
			}
			object value = TruckScreenInstanceField.GetValue(null);
			if (value == null)
			{
				return null;
			}
			return (Sound)ChargeChatLoopField.GetValue(value);
		}

		public static Sound GetTruckApproveSound()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if (TruckScreenInstanceField == null || ChatMessageResultSuccessField == null)
			{
				return null;
			}
			object value = TruckScreenInstanceField.GetValue(null);
			if (value == null)
			{
				return null;
			}
			return (Sound)ChatMessageResultSuccessField.GetValue(value);
		}

		public static Sound GetTruckDenySound()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if (TruckScreenInstanceField == null || ChatMessageResultFailField == null)
			{
				return null;
			}
			object value = TruckScreenInstanceField.GetValue(null);
			if (value == null)
			{
				return null;
			}
			return (Sound)ChatMessageResultFailField.GetValue(value);
		}
	}
	internal class HiddenState
	{
		public GameObject SpawnedObject;

		public PhysGrabObject GrabObject;

		public float? HoldStartTime;

		public bool Confirmed;

		public bool Despawned;

		public AudioSource HoldSound;

		public float LastSpawnAttempt = float.NegativeInfinity;

		public float LastGrabbedTime = float.NegativeInfinity;

		public bool AwaitingRelease;
	}
	internal static class ConfirmTracker
	{
		private static readonly Dictionary<ExtractionPoint, HiddenState> States = new Dictionary<ExtractionPoint, HiddenState>();

		private static readonly HashSet<ExtractionPoint> AllowNextSuccess = new HashSet<ExtractionPoint>();

		public static HiddenState GetOrCreate(ExtractionPoint point)
		{
			if (!States.TryGetValue(point, out var value))
			{
				value = new HiddenState();
				States[point] = value;
			}
			return value;
		}

		public static void Allow(ExtractionPoint point)
		{
			AllowNextSuccess.Add(point);
		}

		public static bool ConsumeAllow(ExtractionPoint point)
		{
			return AllowNextSuccess.Remove(point);
		}
	}
	internal static class HiddenSpawner
	{
		private const string ResourcePath = "enemies/Enemy - Hidden";

		private const float GrabHitboxWidenFactor = 3f;

		public static GameObject SpawnNeutralized(Vector3 position, Quaternion rotation, out PhysGrabObject grabObject)
		{
			//IL_0021: 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_0068: 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_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			grabObject = null;
			GameObject val;
			if (PhotonNetwork.IsConnected)
			{
				Plugin.Log.LogInfo((object)"ExtractionConfirm: spawning via PhotonNetwork.Instantiate (connected).");
				val = PhotonNetwork.Instantiate("enemies/Enemy - Hidden", position, rotation, (byte)0, (object[])null);
			}
			else
			{
				Plugin.Log.LogInfo((object)"ExtractionConfirm: spawning via local Instantiate (not connected to Photon).");
				GameObject val2 = Resources.Load<GameObject>("enemies/Enemy - Hidden");
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log.LogError((object)"ExtractionConfirm: Resources.Load<GameObject>(\"enemies/Enemy - Hidden\") returned null.");
					return null;
				}
				val = Object.Instantiate<GameObject>(val2, position, rotation);
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"ExtractionConfirm: failed to spawn enemies/Enemy - Hidden");
				return null;
			}
			MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val3 in componentsInChildren)
			{
				if (!(val3 is PhysGrabObject) && !(val3 is PhotonView))
				{
					((Behaviour)val3).enabled = false;
				}
			}
			AudioSource[] componentsInChildren2 = val.GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource val4 in componentsInChildren2)
			{
				val4.mute = true;
			}
			Rigidbody[] componentsInChildren3 = val.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody val5 in componentsInChildren3)
			{
				val5.isKinematic = true;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			HashSet<Transform> hashSet = new HashSet<Transform>();
			Collider[] componentsInChildren4 = val.GetComponentsInChildren<Collider>(true);
			foreach (Collider val6 in componentsInChildren4)
			{
				num++;
				MeshCollider val7 = (MeshCollider)(object)((val6 is MeshCollider) ? val6 : null);
				if ((Object)(object)val7 != (Object)null && !val7.convex)
				{
					val6.enabled = false;
					num2++;
					hashSet.Add(((Component)val6).transform);
					continue;
				}
				num3++;
				CapsuleCollider val8 = (CapsuleCollider)(object)((val6 is CapsuleCollider) ? val6 : null);
				if ((Object)(object)val8 != (Object)null)
				{
					BoxCollider val9 = ((Component)val6).gameObject.AddComponent<BoxCollider>();
					val9.center = val8.center;
					val9.size = new Vector3(val8.radius * 2f * 3f, val8.height, val8.radius * 2f);
				}
			}
			int num4 = 0;
			Renderer[] componentsInChildren5 = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val10 in componentsInChildren5)
			{
				if (hashSet.Contains(((Component)val10).transform))
				{
					val10.enabled = false;
					continue;
				}
				((Component)val10).gameObject.SetActive(true);
				val10.enabled = true;
				num4++;
			}
			Plugin.Log.LogInfo((object)$"ExtractionConfirm: colliders total={num} disabled(concave)={num2} left-solid={num3}, renderers={num4}");
			grabObject = val.GetComponentInChildren<PhysGrabObject>(true);
			if ((Object)(object)grabObject == (Object)null)
			{
				Plugin.Log.LogError((object)"ExtractionConfirm: spawned Hidden but found no PhysGrabObject — it won't be grabbable.");
			}
			return val;
		}
	}
}
namespace ExtractionConfirm.Patches
{
	[HarmonyPatch(typeof(ExtractionPoint), "StateSet")]
	internal static class StateSetGatePatch
	{
		private static bool Prefix(ExtractionPoint __instance, State newState)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			try
			{
				if (!Plugin.IsHost())
				{
					return true;
				}
				if ((int)newState != 3)
				{
					return true;
				}
				if (Fields.IsShop(__instance))
				{
					return true;
				}
				if ((int)Fields.CurrentState(__instance) != 2)
				{
					return true;
				}
				if (ConfirmTracker.ConsumeAllow(__instance))
				{
					return true;
				}
				Plugin.Log.LogInfo((object)"Quota reached automatically — holding for manual confirm instead.");
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("ExtractionConfirm: StateSetGatePatch threw, letting original run: " + ex));
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "Update")]
	internal static class ExtractionPointUpdatePatch
	{
		private const float HoldSeconds = 2f;

		private const float SpawnRetrySeconds = 1f;

		private const float ReleaseGraceSeconds = 0.3f;

		private const float StartPitch = 1f;

		private const float EndPitch = 2f;

		private static bool _loggedUpdateError;

		private static bool _loggedDiagnostic;

		private static readonly HashSet<ExtractionPoint> _loggedPerPoint = new HashSet<ExtractionPoint>();

		private static void Postfix(ExtractionPoint __instance)
		{
			if (!_loggedDiagnostic)
			{
				_loggedDiagnostic = true;
				Plugin.Log.LogInfo((object)$"ExtractionConfirm DIAGNOSTIC: InRoom={PhotonNetwork.InRoom} IsMasterClient={PhotonNetwork.IsMasterClient} IsConnected={PhotonNetwork.IsConnected} OfflineMode={PhotonNetwork.OfflineMode} IsHost()={Plugin.IsHost()}");
			}
			try
			{
				RunLogic(__instance);
			}
			catch (Exception ex)
			{
				if (!_loggedUpdateError)
				{
					_loggedUpdateError = true;
					Plugin.Log.LogError((object)("ExtractionConfirm: ExtractionPointUpdatePatch threw (further occurrences suppressed): " + ex));
				}
			}
		}

		private static void RunLogic(ExtractionPoint __instance)
		{
			//IL_0013: 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_004b: 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_006b: Invalid comparison between Unknown and I4
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Invalid comparison between Unknown and I4
			if (!Plugin.IsHost())
			{
				return;
			}
			bool flag = Fields.IsShop(__instance);
			State val = Fields.CurrentState(__instance);
			if (!_loggedPerPoint.Contains(__instance))
			{
				_loggedPerPoint.Add(__instance);
				Plugin.Log.LogInfo((object)$"ExtractionConfirm DIAGNOSTIC per-point: name={((Object)__instance).name} isShop={flag} currentState={val}");
			}
			if (flag)
			{
				return;
			}
			HiddenState orCreate = ConfirmTracker.GetOrCreate(__instance);
			if ((int)val == 2 && (Object)(object)orCreate.SpawnedObject == (Object)null && !orCreate.Despawned)
			{
				float time = Time.time;
				if (time - orCreate.LastSpawnAttempt >= 1f)
				{
					orCreate.LastSpawnAttempt = time;
					SpawnHidden(__instance, orCreate);
				}
			}
			if ((Object)(object)orCreate.SpawnedObject != (Object)null && !orCreate.Confirmed)
			{
				UpdateHold(__instance, orCreate);
			}
			if ((Object)(object)orCreate.SpawnedObject != (Object)null && !orCreate.Despawned && (int)val == 7)
			{
				DespawnHidden(orCreate);
			}
		}

		private static void UpdateHold(ExtractionPoint point, HiddenState state)
		{
			bool flag = Fields.IsGrabbed(state.GrabObject);
			if (flag)
			{
				state.LastGrabbedTime = Time.time;
			}
			bool flag2 = Time.time - state.LastGrabbedTime > 0.3f;
			if (flag && !state.HoldStartTime.HasValue && !state.AwaitingRelease)
			{
				state.HoldStartTime = Time.time;
				StartHoldSound(state);
				return;
			}
			if (!flag && flag2 && state.HoldStartTime.HasValue)
			{
				state.HoldStartTime = null;
				StopHoldSound(state);
				return;
			}
			if (!flag && flag2 && state.AwaitingRelease)
			{
				state.AwaitingRelease = false;
			}
			if (!state.HoldStartTime.HasValue || (!flag && flag2))
			{
				return;
			}
			float num = Time.time - state.HoldStartTime.Value;
			if ((Object)(object)state.HoldSound != (Object)null)
			{
				float num2 = Mathf.Clamp01(num / 2f);
				state.HoldSound.pitch = Mathf.Lerp(1f, 2f, num2);
			}
			if (num >= 2f)
			{
				Transform transform = ((Component)state.GrabObject).transform;
				if (Fields.QuotaReached(point))
				{
					state.Confirmed = true;
					StopHoldSound(state);
					ConfirmTracker.Allow(point);
					Fields.CallStateSet(point, (State)3);
					Plugin.Log.LogInfo((object)"Extraction confirmed via hold.");
				}
				else
				{
					state.HoldStartTime = null;
					state.AwaitingRelease = true;
					StopHoldSound(state);
					PlayOutcomeSound(Fields.GetTruckDenySound(), transform, "deny");
					Fields.CallStateSet(point, (State)5);
				}
			}
		}

		private static void StartHoldSound(HiddenState state)
		{
			Sound truckChargeSound = Fields.GetTruckChargeSound();
			if (truckChargeSound == null)
			{
				Plugin.Log.LogWarning((object)"ExtractionConfirm: GetTruckChargeSound() returned null — no hold sound will play.");
				return;
			}
			AudioSource val = truckChargeSound.Play(((Component)state.GrabObject).transform, 1f, 1f, 1f, 1f);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.clip == (Object)null))
			{
				AudioClip clip = val.clip;
				float volume = Mathf.Max(val.volume, 0.7f);
				val.Stop();
				AudioSource val2 = ((Component)state.GrabObject).gameObject.AddComponent<AudioSource>();
				val2.clip = clip;
				val2.loop = true;
				val2.spatialBlend = 1f;
				val2.volume = volume;
				val2.pitch = 1f;
				val2.Play();
				state.HoldSound = val2;
			}
		}

		private static void SpawnHidden(ExtractionPoint point, HiddenState state)
		{
			//IL_001b: 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_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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_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_00b5: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			Transform emojiScreenTransform = Fields.GetEmojiScreenTransform(point);
			Transform haulGoalScreenTransform = Fields.GetHaulGoalScreenTransform(point);
			Vector3 val;
			Quaternion rotation;
			string arg;
			if ((Object)(object)emojiScreenTransform != (Object)null)
			{
				val = emojiScreenTransform.position + new Vector3(0f, -1.25f, 0f);
				rotation = emojiScreenTransform.rotation;
				arg = "emojiScreen (lowered 1.25m)";
			}
			else if ((Object)(object)haulGoalScreenTransform != (Object)null)
			{
				val = haulGoalScreenTransform.position;
				rotation = haulGoalScreenTransform.rotation;
				arg = "haulGoalScreen";
			}
			else
			{
				Plugin.Log.LogWarning((object)"ExtractionConfirm: no screen transform found, falling back to platform.");
				Transform val2 = Fields.GetPlatform(point) ?? ((Component)point).transform;
				val = val2.position + Vector3.up * 0.5f;
				rotation = val2.rotation;
				arg = "platform/fallback";
			}
			PhysGrabObject grabObject;
			GameObject val3 = HiddenSpawner.SpawnNeutralized(val, rotation, out grabObject);
			if (!((Object)(object)val3 == (Object)null))
			{
				Plugin.Log.LogInfo((object)$"ExtractionConfirm: Hidden spawned via {arg}. spawnPos={val}");
				state.SpawnedObject = val3;
				state.GrabObject = grabObject;
			}
		}

		private static void DespawnHidden(HiddenState state)
		{
			StopHoldSound(state);
			if ((Object)(object)state.SpawnedObject != (Object)null)
			{
				if (PhotonNetwork.IsConnected)
				{
					PhotonView component = state.SpawnedObject.GetComponent<PhotonView>();
					if ((Object)(object)component != (Object)null && component.IsMine)
					{
						PhotonNetwork.Destroy(state.SpawnedObject);
					}
					else
					{
						Object.Destroy((Object)(object)state.SpawnedObject);
					}
				}
				else
				{
					Object.Destroy((Object)(object)state.SpawnedObject);
				}
			}
			state.SpawnedObject = null;
			state.GrabObject = null;
			state.Despawned = true;
		}

		private static void StopHoldSound(HiddenState state)
		{
			if ((Object)(object)state.HoldSound != (Object)null)
			{
				state.HoldSound.Stop();
				Object.Destroy((Object)(object)state.HoldSound);
				state.HoldSound = null;
			}
		}

		private static void PlayOutcomeSound(Sound sound, Transform at, string label)
		{
			if (sound == null)
			{
				Plugin.Log.LogWarning((object)("ExtractionConfirm: " + label + " sound unavailable."));
			}
			else
			{
				sound.Play(at, 1f, 1f, 1f, 1f);
			}
		}
	}
}