Decompiled source of Hung to Dry v1.0.0

HungToDry.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SpiderCocoon
{
	[BepInPlugin("Militus.HungToDry", "Hung to Dry", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<float> HoldSeconds;

		internal static ConfigEntry<float> HangSeconds;

		internal static ConfigEntry<float> ImmunitySeconds;

		internal static ConfigEntry<Key> CutDownKey;

		internal static ConfigEntry<float> StuckSeconds;

		internal static ConfigEntry<float> CutDownSeconds;

		internal static ConfigEntry<bool> DropHeldItems;

		internal static ConfigEntry<float> LookSensitivity;

		internal static ConfigEntry<bool> EnableDebugSpawn;

		internal static ConfigEntry<Key> DebugSpawnKey;

		private void Awake()
		{
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			HoldSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "VictimHoldSeconds", 60f, "Safety net: if the spider has NOT hung the victim up after this many seconds, they are released.");
			HangSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SecondsHangingBeforeDeath", 45f, "How many seconds a victim stays hung up before they die.");
			ImmunitySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ImmunitySeconds", 10f, "Seconds after a release during which the spider cannot cocoon the player again.");
			DropHeldItems = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DropHeldItems", true, "Victims drop the items they are holding when they are caught.");
			CutDownKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Rescue", "CutDownKey", (Key)19, "Hold this key near a hung cocoon to cut the victim down.");
			CutDownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rescue", "CutDownSeconds", 4f, "How many seconds the key must be held to cut a victim down.");
			StuckSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "StuckSeconds", 12f, "If a spider stands still this many seconds while carrying a victim, it hangs them where it stands.");
			LookSensitivity = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "LookSensitivity", 0.12f, "How fast the mouse turns the camera while you are wrapped up. Mouse wheel zooms in and out.");
			EnableDebugSpawn = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "EnableDebugSpawnKey", false, "Testing only: lets the HOST press F8 to spawn a bunker spider in front of them (and F7 to log nearby labels). Leave this off for normal play.");
			DebugSpawnKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Testing", "DebugSpawnKey", (Key)101, "The key that spawns a bunker spider (host only, needs EnableDebugSpawnKey).");
			CocoonRunner.Ensure();
			Harmony val = new Harmony("Militus.HungToDry");
			val.PatchAll();
			try
			{
				MethodBase methodBase = AccessTools.Method(typeof(EnemyAI), "PlayerIsTargetable", (Type[])null, (Type[])null);
				if (methodBase != null)
				{
					val.Patch(methodBase, (HarmonyMethod)null, new HarmonyMethod(typeof(SpiderTargetPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				else
				{
					Log.LogWarning((object)"Could not find EnemyAI.PlayerIsTargetable; spiders may re-target frozen players.");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not patch PlayerIsTargetable: " + ex.Message));
			}
			Log.LogInfo((object)"Hung to Dry 1.0.0 loaded (spider camera, death timer, cut-down rescue, anti-stall).");
		}
	}
	internal class CocoonRunner : MonoBehaviour
	{
		private static CocoonRunner instance;

		public static void Ensure()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!((Object)(object)instance != (Object)null))
			{
				GameObject val = new GameObject("SpiderCocoonRunner");
				((Object)val).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)val);
				instance = val.AddComponent<CocoonRunner>();
			}
		}

		public static void Run(IEnumerator routine)
		{
			Ensure();
			((MonoBehaviour)instance).StartCoroutine(routine);
		}

		private void Update()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Keyboard current = Keyboard.current;
			if (current != null && ((ButtonControl)current.f9Key).wasPressedThisFrame)
			{
				Cocoon.EmergencyRelease();
			}
			if (Plugin.EnableDebugSpawn.Value && current != null)
			{
				KeyControl val = current[Plugin.DebugSpawnKey.Value];
				if (val != null && ((ButtonControl)val).wasPressedThisFrame)
				{
					DebugSpawn.SpawnSpiderInFrontOfHost();
				}
				if (((ButtonControl)current.f7Key).wasPressedThisFrame)
				{
					DebugSpawn.DumpLabelsNearby();
				}
			}
			Cocoon.RemoveDeadVictims();
			CocoonNet.EnsureRegistered();
			Cocoon.WatchSpiders();
		}

		private void LateUpdate()
		{
			Cocoon.UpdateCameras();
			Cocoon.UpdateRescue();
		}
	}
	internal static class DebugSpawn
	{
		private static string PathOf(Transform t)
		{
			string text = ((Object)t).name;
			int num = 0;
			while ((Object)(object)t.parent != (Object)null && num++ < 8)
			{
				t = t.parent;
				text = ((Object)t).name + "/" + text;
			}
			return text;
		}

		internal static void DumpLabelsNearby()
		{
			//IL_0033: 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_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Invalid comparison between Unknown and I4
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Vector3 position = ((Component)val).transform.position;
				Plugin.Log.LogInfo((object)"=== Label dump (F7) ===");
				PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
				foreach (PlayerControllerB val2 in allPlayerScripts)
				{
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val) && val2.isPlayerControlled)
					{
						Plugin.Log.LogInfo((object)("Player " + val2.playerClientId + " (" + val2.playerUsername + ") cocooned=" + Cocoon.IsCocooned(val2) + " canvasActive=" + ((Object)(object)val2.usernameCanvas != (Object)null && ((Component)val2.usernameCanvas).gameObject.activeSelf) + " alpha=" + (((Object)(object)val2.usernameAlpha != (Object)null) ? val2.usernameAlpha.alpha : (-1f)) + " dist=" + Vector3.Distance(position, ((Component)val2).transform.position)));
					}
				}
				Canvas[] array = Object.FindObjectsOfType<Canvas>();
				foreach (Canvas val3 in array)
				{
					if (!((Object)(object)val3 == (Object)null) && ((Component)val3).gameObject.activeInHierarchy && (int)val3.renderMode == 2)
					{
						float num = Vector3.Distance(position, ((Component)val3).transform.position);
						if (!(num > 20f))
						{
							Plugin.Log.LogInfo((object)("WorldCanvas " + PathOf(((Component)val3).transform) + " dist=" + num));
						}
					}
				}
				ScanNodeProperties[] array2 = Object.FindObjectsOfType<ScanNodeProperties>();
				foreach (ScanNodeProperties val4 in array2)
				{
					if (!((Object)(object)val4 == (Object)null) && ((Component)val4).gameObject.activeInHierarchy)
					{
						float num2 = Vector3.Distance(position, ((Component)val4).transform.position);
						if (!(num2 > 20f))
						{
							Plugin.Log.LogInfo((object)("ScanNode '" + val4.headerText + "' / '" + val4.subText + "' " + PathOf(((Component)val4).transform) + " dist=" + num2));
						}
					}
				}
				Plugin.Log.LogInfo((object)"=== End label dump ===");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Label dump failed: " + ex));
			}
		}

		internal unsafe static void SpawnSpiderInFrontOfHost()
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: 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_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton == (Object)null || !singleton.IsServer)
				{
					Plugin.Log.LogWarning((object)"Spawn key: only the host can spawn a spider.");
					return;
				}
				PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"Spawn key: no local player yet.");
					return;
				}
				EnemyType val2 = null;
				EnemyType[] array = Resources.FindObjectsOfTypeAll<EnemyType>();
				foreach (EnemyType val3 in array)
				{
					if ((Object)(object)val3 != (Object)null && (Object)(object)val3.enemyPrefab != (Object)null && (Object)(object)val3.enemyPrefab.GetComponentInChildren<SandSpiderAI>() != (Object)null)
					{
						val2 = val3;
						break;
					}
				}
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log.LogWarning((object)"Spawn key: could not find the bunker spider type.");
					return;
				}
				Vector3 val4 = ((Component)val).transform.position + ((Component)val).transform.forward * 7f;
				NavMeshHit val5 = default(NavMeshHit);
				if (NavMesh.SamplePosition(val4, ref val5, 8f, -1))
				{
					val4 = ((NavMeshHit)(ref val5)).position;
				}
				GameObject val6 = Object.Instantiate<GameObject>(val2.enemyPrefab, val4, Quaternion.identity);
				NetworkObject componentInChildren = val6.GetComponentInChildren<NetworkObject>();
				if ((Object)(object)componentInChildren == (Object)null)
				{
					Object.Destroy((Object)(object)val6);
					Plugin.Log.LogWarning((object)"Spawn key: spider prefab has no network object.");
					return;
				}
				componentInChildren.Spawn(true);
				EnemyAI componentInChildren2 = val6.GetComponentInChildren<EnemyAI>();
				if ((Object)(object)componentInChildren2 != (Object)null && (Object)(object)RoundManager.Instance != (Object)null && RoundManager.Instance.SpawnedEnemies != null)
				{
					RoundManager.Instance.SpawnedEnemies.Add(componentInChildren2);
				}
				ManualLogSource log = Plugin.Log;
				Vector3 val7 = val4;
				log.LogInfo((object)("Spawn key: bunker spider spawned at " + ((object)(*(Vector3*)(&val7))/*cast due to .constrained prefix*/).ToString() + "."));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Spawn key failed: " + ex));
			}
		}
	}
	internal class CocoonState
	{
		public PlayerControllerB Player;

		public SandSpiderAI Spider;

		public List<Renderer> Renderers = new List<Renderer>();

		public List<bool> WereEnabled = new List<bool>();

		public List<Collider> Colliders = new List<Collider>();

		public List<bool> ColliderWasEnabled = new List<bool>();

		public bool Hung;

		public float BeganAt;

		public bool DiagLogged;

		public float LostSince = -1f;

		public Vector3 LastSpiderPos;

		public float StillSince = -1f;

		public bool CameraActive;

		public bool CamInitialized;

		public Vector3 CamDir = Vector3.forward;

		public float OrbitYaw;

		public float OrbitPitch;

		public float ZoomMul = 1f;

		public Vector3 SavedLocalPos;

		public Quaternion SavedLocalRot;
	}
	internal static class Cocoon
	{
		private const float CamDistance = 3.5f;

		private const float CamHeight = 1.2f;

		private static readonly Dictionary<int, CocoonState> Active = new Dictionary<int, CocoonState>();

		private static readonly Dictionary<int, float> ImmuneUntil = new Dictionary<int, float>();

		private static readonly MethodInfo GrabBodyMethod = AccessTools.Method(typeof(SandSpiderAI), "GrabBody", (Type[])null, (Type[])null);

		private static readonly MethodInfo CancelSpoolingMethod = AccessTools.Method(typeof(SandSpiderAI), "CancelSpoolingBody", (Type[])null, (Type[])null);

		private static readonly FieldInfo SpooledField = AccessTools.Field(typeof(SandSpiderAI), "spooledPlayerBody");

		private static readonly FieldInfo HeldBodyField = AccessTools.Field(typeof(SandSpiderAI), "currentlyHeldBody");

		private static readonly FieldInfo SpoolingField = AccessTools.Field(typeof(SandSpiderAI), "spoolingPlayerBody");

		private static readonly MethodInfo HangBodyMethod = AccessTools.Method(typeof(SandSpiderAI), "HangBodyFromCeiling", (Type[])null, (Type[])null);

		private static readonly FieldInfo StunField = AccessTools.Field(typeof(EnemyAI), "stunNormalizedTimer");

		private static readonly FieldInfo CoroutineField = AccessTools.Field(typeof(SandSpiderAI), "turnBodyIntoWebCoroutine");

		private static readonly MethodInfo WrapMethod = AccessTools.Method(typeof(SandSpiderAI), "turnBodyIntoWeb", (Type[])null, (Type[])null);

		private const float RescueRange = 5f;

		private static int cutTarget = -1;

		private static float cutProgress;

		private static float lastRequestTime = -10f;

		private static bool promptShown;

		public static bool IsCocooned(PlayerControllerB player)
		{
			return (Object)(object)player != (Object)null && Active.ContainsKey((int)player.playerClientId);
		}

		public static bool IsImmune(PlayerControllerB player)
		{
			float value;
			return (Object)(object)player != (Object)null && ImmuneUntil.TryGetValue((int)player.playerClientId, out value) && Time.time < value;
		}

		private static bool IsLocal(PlayerControllerB p)
		{
			return (Object)(object)p != (Object)null && (Object)(object)p == (Object)(object)GameNetworkManager.Instance.localPlayerController;
		}

		private static void MakeSpiderGrab(SandSpiderAI spider, PlayerControllerB victim)
		{
			if ((Object)(object)spider == (Object)null || ((EnemyAI)spider).isEnemyDead || !((NetworkBehaviour)spider).IsOwner)
			{
				return;
			}
			DeadBodyInfo deadBody = victim.deadBody;
			if (!((Object)(object)deadBody == (Object)null))
			{
				if (!(bool)SpoolingField.GetValue(spider))
				{
					CoroutineField.SetValue(spider, null);
				}
				SpooledField.SetValue(spider, false);
				GrabBodyMethod.Invoke(spider, new object[1] { deadBody });
				spider.GrabBodyServerRpc((int)victim.playerClientId);
				((EnemyAI)spider).targetPlayer = null;
				((EnemyAI)spider).SwitchToBehaviourState(1);
				Plugin.Log.LogInfo((object)("Spider grabbed player " + victim.playerClientId + "'s stand-in body."));
			}
		}

		public static void Begin(PlayerControllerB victim, SandSpiderAI spider)
		{
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)victim == (Object)null || victim.isPlayerDead)
			{
				return;
			}
			int num = (int)victim.playerClientId;
			if (Active.ContainsKey(num))
			{
				return;
			}
			CocoonState cocoonState = new CocoonState
			{
				Player = victim,
				Spider = spider,
				BeganAt = Time.time
			};
			Active[num] = cocoonState;
			if (ImmuneUntil.TryGetValue(num, out var value))
			{
				Plugin.Log.LogInfo((object)("Player " + num + " caught again; their immunity ended " + (Time.time - value).ToString("F1") + "s ago (negative = they were still immune)."));
			}
			bool flag = IsLocal(victim);
			try
			{
				CocoonRunner.Run(FailsafeRelease(num, cocoonState, Plugin.HoldSeconds.Value));
				Renderer[] componentsInChildren = ((Component)victim).gameObject.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null) && (val is SkinnedMeshRenderer || val is MeshRenderer) && !((Object)(object)((Component)val).GetComponentInParent<GrabbableObject>() != (Object)null))
					{
						cocoonState.Renderers.Add(val);
						cocoonState.WereEnabled.Add(val.enabled);
						val.enabled = false;
					}
				}
				if (!flag)
				{
					AddCollider(cocoonState, (Collider)(object)victim.thisController);
					AddCollider(cocoonState, victim.playerCollider);
					Collider[] componentsInChildren2 = ((Component)victim).gameObject.GetComponentsInChildren<Collider>(true);
					foreach (Collider val2 in componentsInChildren2)
					{
						if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).GetComponentInParent<GrabbableObject>() != (Object)null))
						{
							AddCollider(cocoonState, val2);
						}
					}
					DisableColliders(cocoonState);
					Plugin.Log.LogInfo((object)("Player " + num + ": switched off " + cocoonState.Colliders.Count + " collider(s) so nobody bumps into the hidden body."));
				}
				if (flag)
				{
					victim.disableMoveInput = true;
					victim.disableLookInput = true;
					if (Plugin.DropHeldItems.Value)
					{
						victim.DropAllHeldItemsAndSync(((Component)victim).transform.position, victim.localItemHolder.position, victim.localItemHolder.eulerAngles, victim.playerEye.position, victim.playerEye.eulerAngles);
					}
				}
				victim.SpawnDeadBody(num, Vector3.zero, 6, victim, 0, (Transform)null, (Transform)null, default(Vector3));
				MakeSpiderGrab(spider, victim);
				if (flag)
				{
					StartCamera(cocoonState);
				}
				Plugin.Log.LogInfo((object)("Player " + num + " cocooned (this is my own player: " + flag + ")."));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Cocoon.Begin failed, undoing: " + ex));
				End(num);
			}
		}

		public static void OnBodyHung(DeadBodyInfo body, SandSpiderAI spider = null)
		{
			if ((Object)(object)body == (Object)null && (Object)(object)spider == (Object)null)
			{
				return;
			}
			foreach (KeyValuePair<int, CocoonState> item in Active)
			{
				CocoonState value = item.Value;
				if (value.Hung || (Object)(object)value.Player == (Object)null || !(((Object)(object)body != (Object)null) ? ((Object)(object)value.Player.deadBody == (Object)(object)body) : ((Object)(object)value.Spider == (Object)(object)spider)))
				{
					continue;
				}
				value.Hung = true;
				CocoonRunner.Run(DeathAfter(item.Key, value, Plugin.HangSeconds.Value));
				Plugin.Log.LogInfo((object)("Player " + item.Key + " hung up. Death in " + Plugin.HangSeconds.Value + "s."));
				break;
			}
		}

		private static bool SpiderHoldsBody(SandSpiderAI spider)
		{
			return (Object)(object)spider != (Object)null && HeldBodyField.GetValue(spider) != null;
		}

		private static IEnumerator WaitForHeldBody(SandSpiderAI spider, Action<bool> ready)
		{
			float waited = 0f;
			while ((Object)(object)spider != (Object)null && !SpiderHoldsBody(spider) && waited < 10f)
			{
				waited += Time.deltaTime;
				yield return null;
			}
			ready((Object)(object)spider != (Object)null && !((EnemyAI)spider).isEnemyDead && SpiderHoldsBody(spider));
		}

		internal static IEnumerator WrapWhenReady(SandSpiderAI spider)
		{
			bool ok = false;
			yield return CocoonRunnerWait(spider, delegate(bool r)
			{
				ok = r;
			});
			if (!ok || CoroutineField.GetValue(spider) != null)
			{
				yield break;
			}
			try
			{
				CoroutineField.SetValue(spider, ((MonoBehaviour)spider).StartCoroutine((IEnumerator)WrapMethod.Invoke(spider, null)));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Late wrap failed: " + ex));
			}
		}

		internal static IEnumerator HangWhenReady(SandSpiderAI spider)
		{
			bool ok = false;
			yield return CocoonRunnerWait(spider, delegate(bool r)
			{
				ok = r;
			});
			if (!ok)
			{
				OnBodyHung(null, spider);
				yield break;
			}
			yield return (object)new WaitForSeconds(0.3f);
			float waited = 0f;
			while ((Object)(object)spider != (Object)null && CoroutineField.GetValue(spider) != null && waited < 8f)
			{
				waited += Time.deltaTime;
				yield return null;
			}
			if ((Object)(object)spider == (Object)null || ((EnemyAI)spider).isEnemyDead || !SpiderHoldsBody(spider))
			{
				yield break;
			}
			try
			{
				HangBodyMethod.Invoke(spider, null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Late hang failed: " + ex));
			}
		}

		private static IEnumerator CocoonRunnerWait(SandSpiderAI spider, Action<bool> ready)
		{
			return WaitForHeldBody(spider, ready);
		}

		private static IEnumerator FailsafeRelease(int id, CocoonState owner, float seconds)
		{
			yield return (object)new WaitForSeconds(seconds);
			if (Active.TryGetValue(id, out var s) && s == owner && !s.Hung)
			{
				Plugin.Log.LogInfo((object)("Player " + id + " was never hung up: safety release."));
				End(id);
			}
		}

		private static IEnumerator DeathAfter(int id, CocoonState owner, float seconds)
		{
			yield return (object)new WaitForSeconds(seconds);
			if (!Active.TryGetValue(id, out var current) || current != owner)
			{
				yield break;
			}
			try
			{
				Kill(id);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Kill failed: " + ex));
			}
		}

		public static void Kill(int id)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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)
			if (Active.TryGetValue(id, out var value))
			{
				PlayerControllerB player = value.Player;
				if (IsLocal(player))
				{
					Active.Remove(id);
					StopCamera(value, backToPlayer: false);
					player.disableMoveInput = false;
					player.disableLookInput = false;
					Plugin.Log.LogInfo((object)("Player " + id + " dies in the cocoon."));
					player.KillPlayer(Vector3.zero, false, (CauseOfDeath)6, 0, default(Vector3), false);
				}
			}
		}

		public static void EndAll()
		{
			foreach (int item in new List<int>(Active.Keys))
			{
				End(item);
			}
		}

		public static void EmergencyRelease()
		{
			GameNetworkManager instance = GameNetworkManager.Instance;
			PlayerControllerB val = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null);
			if (!((Object)(object)val == (Object)null))
			{
				int num = (int)val.playerClientId;
				if (Active.ContainsKey(num))
				{
					Plugin.Log.LogInfo((object)("Emergency release (F9) for player " + num + "."));
					End(num);
					CocoonNet.RequestRelease(num);
				}
			}
		}

		private static void AddCollider(CocoonState state, Collider c)
		{
			if (!((Object)(object)c == (Object)null) && !state.Colliders.Contains(c))
			{
				state.Colliders.Add(c);
				state.ColliderWasEnabled.Add(c.enabled);
			}
		}

		private static void DisableColliders(CocoonState state)
		{
			for (int i = 0; i < state.Colliders.Count; i++)
			{
				if ((Object)(object)state.Colliders[i] != (Object)null && state.Colliders[i].enabled)
				{
					state.Colliders[i].enabled = false;
				}
			}
		}

		private static void RestoreColliders(CocoonState state)
		{
			for (int i = 0; i < state.Colliders.Count; i++)
			{
				if ((Object)(object)state.Colliders[i] != (Object)null)
				{
					state.Colliders[i].enabled = state.ColliderWasEnabled[i];
				}
			}
		}

		public static void End(int id, bool teleportToBody = false)
		{
			if (!Active.TryGetValue(id, out var value))
			{
				return;
			}
			Active.Remove(id);
			PlayerControllerB player = value.Player;
			if ((Object)(object)player != (Object)null && !player.isPlayerDead)
			{
				RestoreColliders(value);
			}
			if ((Object)(object)player == (Object)null || player.isPlayerDead)
			{
				StopCamera(value, backToPlayer: false);
				return;
			}
			ImmuneUntil[id] = Time.time + Plugin.ImmunitySeconds.Value;
			StopCamera(value, backToPlayer: true);
			for (int i = 0; i < value.Renderers.Count; i++)
			{
				if ((Object)(object)value.Renderers[i] != (Object)null)
				{
					value.Renderers[i].enabled = value.WereEnabled[i];
				}
			}
			if (IsLocal(player))
			{
				player.disableMoveInput = false;
				player.disableLookInput = false;
			}
			if ((Object)(object)player.deadBody != (Object)null)
			{
				SandSpiderAI spider = value.Spider;
				if ((Object)(object)spider != (Object)null && !((EnemyAI)spider).isEnemyDead && HeldBodyField.GetValue(spider) == player.deadBody)
				{
					CancelSpoolingMethod.Invoke(spider, null);
					CoroutineField.SetValue(spider, null);
				}
				if (teleportToBody && value.Hung && IsLocal(player))
				{
					MoveVictimUnderBody(player);
				}
				Transform attachedTo = player.deadBody.attachedTo;
				Object.Destroy((Object)(object)((Component)player.deadBody).gameObject);
				player.deadBody = null;
				if (value.Hung && (Object)(object)attachedTo != (Object)null)
				{
					DestroyRope(attachedTo);
				}
			}
			Plugin.Log.LogInfo((object)("Player " + id + " released (this is my own player: " + IsLocal(player) + ")."));
		}

		public static void WatchSpiders()
		{
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			if (Active.Count == 0)
			{
				return;
			}
			foreach (CocoonState item in new List<CocoonState>(Active.Values))
			{
				SandSpiderAI spider = item.Spider;
				if (!item.DiagLogged && !item.Hung && (Object)(object)spider != (Object)null && (Object)(object)item.Player != (Object)null && Time.time - item.BeganAt > 25f)
				{
					item.DiagLogged = true;
					try
					{
						Plugin.Log.LogWarning((object)("Spider diagnostic: player " + item.Player.playerClientId + " wrapped 25s but not hung. state=" + ((EnemyAI)spider).currentBehaviourStateIndex + " owner=" + ((NetworkBehaviour)spider).IsOwner + " spooling=" + SpoolingField.GetValue(spider)?.ToString() + " spooled=" + SpooledField.GetValue(spider)?.ToString() + " wrapRoutineSet=" + (CoroutineField.GetValue(spider) != null) + " holdingTheirBody=" + (HeldBodyField.GetValue(spider) == item.Player.deadBody) + " stunTimer=" + ((StunField != null) ? StunField.GetValue(spider) : null)));
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Spider diagnostic failed: " + ex.Message));
					}
				}
				if (item.Hung || (Object)(object)spider == (Object)null || ((EnemyAI)spider).isEnemyDead || !((NetworkBehaviour)spider).IsOwner || (Object)(object)item.Player == (Object)null)
				{
					continue;
				}
				DeadBodyInfo deadBody = item.Player.deadBody;
				if ((Object)(object)deadBody == (Object)null || HeldBodyField.GetValue(spider) != deadBody)
				{
					item.StillSince = -1f;
					if ((Object)(object)deadBody != (Object)null && Time.time - item.BeganAt > 6f)
					{
						if (item.LostSince < 0f)
						{
							item.LostSince = Time.time;
						}
						else if (Time.time - item.LostSince > 4f)
						{
							Plugin.Log.LogWarning((object)("Spider dropped player " + item.Player.playerClientId + " without hanging them: releasing them."));
							item.LostSince = -1f;
							CocoonNet.RequestRelease((int)item.Player.playerClientId);
						}
					}
					continue;
				}
				item.LostSince = -1f;
				bool flag = (bool)SpoolingField.GetValue(spider);
				if (StunField != null && (float)StunField.GetValue(spider) > 0f)
				{
					flag = true;
				}
				Vector3 val = (((Object)(object)spider.meshContainer != (Object)null) ? spider.meshContainer.position : ((Component)spider).transform.position);
				if (item.StillSince < 0f || flag || Vector3.Distance(val, item.LastSpiderPos) > 0.5f)
				{
					item.LastSpiderPos = val;
					item.StillSince = Time.time;
				}
				else
				{
					if (Time.time - item.StillSince < Plugin.StuckSeconds.Value)
					{
						continue;
					}
					Plugin.Log.LogWarning((object)("Spider stuck while carrying player " + item.Player.playerClientId + ": hanging them where it stands."));
					item.StillSince = -1f;
					try
					{
						HangBodyMethod.Invoke(spider, null);
						spider.SpiderHangBodyServerRpc();
						((EnemyAI)spider).targetPlayer = null;
						if (((EnemyAI)spider).currentBehaviourStateIndex == 2)
						{
							((EnemyAI)spider).SwitchToBehaviourState(0);
						}
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogError((object)("Unsticking the spider failed: " + ex2));
					}
				}
			}
		}

		public static void ApplyRelease(int id)
		{
			if (Active.TryGetValue(id, out var _))
			{
				Plugin.Log.LogInfo((object)("Player " + id + " was cut down."));
				End(id, teleportToBody: true);
			}
		}

		private static void MoveVictimUnderBody(PlayerControllerB p)
		{
			//IL_0014: 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_001a: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Vector3 val = ((Component)p.deadBody.bodyParts[6]).transform.position;
				RaycastHit val2 = default(RaycastHit);
				if (Physics.Raycast(val, Vector3.down, ref val2, 25f, StartOfRound.Instance.collidersAndRoomMask, (QueryTriggerInteraction)1))
				{
					val = ((RaycastHit)(ref val2)).point + Vector3.up * 0.3f;
				}
				p.TeleportPlayer(val, false, 0f, false, true);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not move the freed player to the cocoon: " + ex));
			}
		}

		private static void DestroyRope(Transform hangPoint)
		{
			try
			{
				SetLineRendererPoints componentInParent = ((Component)hangPoint).GetComponentInParent<SetLineRendererPoints>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)componentInParent).gameObject);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not remove the rope: " + ex.Message));
			}
		}

		public static void UpdateRescue()
		{
			//IL_00be: 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_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			GameNetworkManager instance = GameNetworkManager.Instance;
			PlayerControllerB val = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int num = -1;
			if (val.isPlayerControlled && !val.isPlayerDead && !IsCocooned(val) && !val.isTypingChat && !val.inTerminalMenu && !val.inSpecialMenu && ((Object)(object)val.quickMenuManager == (Object)null || !val.quickMenuManager.isMenuOpen) && Time.time - lastRequestTime > 2f && Active.Count > 0)
			{
				float num2 = 5f;
				Vector3 position = ((Component)val.gameplayCamera).transform.position;
				foreach (KeyValuePair<int, CocoonState> item in Active)
				{
					CocoonState value = item.Value;
					if (!value.Hung || (Object)(object)value.Player == (Object)null || (Object)(object)value.Player == (Object)(object)val)
					{
						continue;
					}
					DeadBodyInfo deadBody = value.Player.deadBody;
					if (!((Object)(object)deadBody == (Object)null) && deadBody.bodyParts != null && deadBody.bodyParts.Length > 6)
					{
						float num3 = Vector3.Distance(position, ((Component)deadBody.bodyParts[6]).transform.position);
						if (num3 < num2)
						{
							num2 = num3;
							num = item.Key;
						}
					}
				}
			}
			if (num < 0)
			{
				cutTarget = -1;
				cutProgress = 0f;
				if (promptShown)
				{
					promptShown = false;
					((TMP_Text)val.cursorTip).text = "";
				}
				return;
			}
			if (num != cutTarget)
			{
				cutTarget = num;
				cutProgress = 0f;
			}
			Keyboard current2 = Keyboard.current;
			bool flag = current2 != null && ((ButtonControl)current2[Plugin.CutDownKey.Value]).isPressed;
			cutProgress = (flag ? (cutProgress + Time.deltaTime) : 0f);
			float num4 = Mathf.Max(0.5f, Plugin.CutDownSeconds.Value);
			int num5 = Mathf.Min(100, Mathf.RoundToInt(cutProgress / num4 * 100f));
			((TMP_Text)val.cursorTip).text = (flag ? ("Cutting them down... " + num5 + "%") : ("[Hold " + ((object)Plugin.CutDownKey.Value/*cast due to .constrained prefix*/).ToString() + "] Cut them down"));
			promptShown = true;
			if (cutProgress >= num4)
			{
				cutProgress = 0f;
				cutTarget = -1;
				lastRequestTime = Time.time;
				Plugin.Log.LogInfo((object)("Cutting down player " + num));
				CocoonNet.RequestRelease(num);
			}
		}

		public static void RemoveDeadVictims()
		{
			if (Active.Count == 0)
			{
				return;
			}
			foreach (int item in new List<int>(Active.Keys))
			{
				CocoonState cocoonState = Active[item];
				if ((Object)(object)cocoonState.Player == (Object)null || cocoonState.Player.isPlayerDead)
				{
					StopCamera(cocoonState, backToPlayer: false);
					Active.Remove(item);
				}
			}
		}

		private static void StartCamera(CocoonState s)
		{
			//IL_0033: 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_0044: 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)
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.spectateCamera == (Object)null))
			{
				Camera spectateCamera = instance.spectateCamera;
				s.SavedLocalPos = ((Component)spectateCamera).transform.localPosition;
				s.SavedLocalRot = ((Component)spectateCamera).transform.localRotation;
				instance.SwitchCamera(spectateCamera);
				s.Player.ChangeAudioListenerToObject(((Component)spectateCamera).gameObject);
				s.CameraActive = true;
			}
		}

		private static void StopCamera(CocoonState s, bool backToPlayer)
		{
			//IL_004d: 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)
			if (!s.CameraActive)
			{
				return;
			}
			s.CameraActive = false;
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				if ((Object)(object)instance.spectateCamera != (Object)null)
				{
					((Component)instance.spectateCamera).transform.localPosition = s.SavedLocalPos;
					((Component)instance.spectateCamera).transform.localRotation = s.SavedLocalRot;
				}
				if (backToPlayer && (Object)(object)s.Player != (Object)null && (Object)(object)s.Player.gameplayCamera != (Object)null)
				{
					instance.SwitchCamera(s.Player.gameplayCamera);
					s.Player.ChangeAudioListenerToObject(((Component)s.Player.gameplayCamera).gameObject);
				}
			}
		}

		public static void UpdateCameras()
		{
			if (Active.Count == 0)
			{
				return;
			}
			foreach (CocoonState value in Active.Values)
			{
				HideNameTag(value);
				if (!IsLocal(value.Player))
				{
					DisableColliders(value);
				}
				for (int i = 0; i < value.Renderers.Count; i++)
				{
					if ((Object)(object)value.Renderers[i] != (Object)null && value.Renderers[i].enabled)
					{
						value.Renderers[i].enabled = false;
					}
				}
				if (value.CameraActive && IsLocal(value.Player))
				{
					HideVisor(value.Player);
				}
				if (value.CameraActive)
				{
					try
					{
						UpdateCamera(value);
					}
					catch (Exception ex)
					{
						Plugin.Log.LogError((object)("Camera update failed, switching back: " + ex));
						StopCamera(value, backToPlayer: true);
					}
				}
			}
		}

		private static void HideVisor(PlayerControllerB p)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)p == (Object)null) && !((Object)(object)p.localVisor == (Object)null) && !((Object)(object)instance == (Object)null) && !((Object)(object)instance.notSpawnedPosition == (Object)null))
			{
				p.localVisor.position = instance.notSpawnedPosition.position;
			}
		}

		private static void HideNameTag(CocoonState s)
		{
			PlayerControllerB player = s.Player;
			if (!((Object)(object)player == (Object)null) && !IsLocal(player))
			{
				if ((Object)(object)player.usernameAlpha != (Object)null)
				{
					player.usernameAlpha.alpha = 0f;
				}
				if ((Object)(object)player.usernameCanvas != (Object)null && ((Component)player.usernameCanvas).gameObject.activeSelf)
				{
					((Component)player.usernameCanvas).gameObject.SetActive(false);
				}
			}
		}

		private static void UpdateCamera(CocoonState s)
		{
			//IL_0094: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Invalid comparison between Unknown and I4
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: 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_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: 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_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			PlayerControllerB player = s.Player;
			if ((Object)(object)instance == (Object)null || (Object)(object)player == (Object)null || (Object)(object)instance.spectateCamera == (Object)null || (Object)(object)player.deadBody == (Object)null || player.deadBody.bodyParts == null || player.deadBody.bodyParts.Length <= 6)
			{
				return;
			}
			Transform transform = ((Component)instance.spectateCamera).transform;
			Vector3 position = ((Component)player.deadBody.bodyParts[6]).transform.position;
			SandSpiderAI spider = s.Spider;
			if (!s.Hung && (Object)(object)spider != (Object)null && !((EnemyAI)spider).isEnemyDead && (Object)(object)spider.meshContainer != (Object)null)
			{
				Vector3 val = position - spider.meshContainer.position;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude > 0.25f)
				{
					s.CamDir = ((Vector3)(ref val)).normalized;
				}
			}
			Mouse current = Mouse.current;
			if (current != null && (int)Cursor.lockState == 1)
			{
				Vector2 val2 = ((InputControl<Vector2>)(object)((Pointer)current).delta).ReadValue();
				float value = Plugin.LookSensitivity.Value;
				s.OrbitYaw += val2.x * value;
				s.OrbitPitch = Mathf.Clamp(s.OrbitPitch - val2.y * value, -50f, 70f);
				float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y;
				if (Mathf.Abs(y) > 0.01f)
				{
					s.ZoomMul = Mathf.Clamp(s.ZoomMul - Mathf.Sign(y) * 0.15f, 0.5f, 2.5f);
				}
			}
			Vector3 val3 = Quaternion.AngleAxis(s.OrbitYaw, Vector3.up) * s.CamDir;
			float num = Mathf.Sqrt(13.690001f) * s.ZoomMul;
			float num2 = Mathf.Clamp(Mathf.Atan2(1.2f, 3.5f) * 57.29578f + s.OrbitPitch, -40f, 80f) * (MathF.PI / 180f);
			Vector3 val4 = val3 * (num * Mathf.Cos(num2)) + Vector3.up * (num * Mathf.Sin(num2));
			Vector3 val5 = position + val4;
			RaycastHit val6 = default(RaycastHit);
			if (Physics.Raycast(position, ((Vector3)(ref val4)).normalized, ref val6, ((Vector3)(ref val4)).magnitude, instance.collidersAndRoomMask, (QueryTriggerInteraction)1))
			{
				val5 = ((RaycastHit)(ref val6)).point - ((Vector3)(ref val4)).normalized * 0.25f;
			}
			float num3 = 1f - Mathf.Exp(-12f * Time.deltaTime);
			transform.position = (s.CamInitialized ? Vector3.Lerp(transform.position, val5, num3) : val5);
			Vector3 val7 = position - transform.position;
			if (((Vector3)(ref val7)).sqrMagnitude > 0.0001f)
			{
				Quaternion val8 = Quaternion.LookRotation(val7);
				transform.rotation = (s.CamInitialized ? Quaternion.Slerp(transform.rotation, val8, num3) : val8);
			}
			s.CamInitialized = true;
		}
	}
	internal static class CocoonNet
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnRequest;

			public static HandleNamedMessageDelegate <1>__OnRelease;
		}

		private const string RequestName = "SpiderCocoon.RequestRelease";

		private const string ReleaseName = "SpiderCocoon.Release";

		private static CustomMessagingManager registeredWith;

		private static bool reportedFailure;

		public static void EnsureRegistered()
		{
			//IL_0062: 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_006d: Expected O, but got Unknown
			//IL_0089: 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: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsListening)
			{
				registeredWith = null;
				return;
			}
			CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
			if (customMessagingManager == null || customMessagingManager == registeredWith)
			{
				return;
			}
			try
			{
				object obj = <>O.<0>__OnRequest;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnRequest;
					<>O.<0>__OnRequest = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("SpiderCocoon.RequestRelease", (HandleNamedMessageDelegate)obj);
				object obj2 = <>O.<1>__OnRelease;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = OnRelease;
					<>O.<1>__OnRelease = val2;
					obj2 = (object)val2;
				}
				customMessagingManager.RegisterNamedMessageHandler("SpiderCocoon.Release", (HandleNamedMessageDelegate)obj2);
				registeredWith = customMessagingManager;
				Plugin.Log.LogInfo((object)"Hung to Dry network messages registered.");
			}
			catch (Exception ex)
			{
				if (!reportedFailure)
				{
					reportedFailure = true;
					Plugin.Log.LogError((object)("Could not register network messages: " + ex));
				}
			}
		}

		public unsafe static void RequestRelease(int victimId)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null)
			{
				return;
			}
			if (singleton.IsServer)
			{
				Broadcast(victimId);
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteByteSafe((byte)victimId);
				singleton.CustomMessagingManager.SendNamedMessage("SpiderCocoon.RequestRelease", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private unsafe static void Broadcast(int victimId)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteByteSafe((byte)victimId);
				singleton.CustomMessagingManager.SendNamedMessageToAll("SpiderCocoon.Release", val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
			Cocoon.ApplyRelease(victimId);
		}

		private static void OnRequest(ulong senderClientId, FastBufferReader reader)
		{
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (!((Object)(object)singleton == (Object)null) && singleton.IsServer)
				{
					byte victimId = default(byte);
					((FastBufferReader)(ref reader)).ReadByteSafe(ref victimId);
					Broadcast(victimId);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Rescue request failed: " + ex));
			}
		}

		private static void OnRelease(ulong senderClientId, FastBufferReader reader)
		{
			try
			{
				byte id = default(byte);
				((FastBufferReader)(ref reader)).ReadByteSafe(ref id);
				Cocoon.ApplyRelease(id);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Rescue release failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "ShowNameBillboard")]
	internal static class NameBadgePatch
	{
		private static bool Prefix(PlayerControllerB __instance)
		{
			return !Cocoon.IsCocooned(__instance);
		}
	}
	internal static class SpiderTargetPatch
	{
		internal static void Postfix(EnemyAI __instance, object[] __args, ref bool __result)
		{
			try
			{
				if (__result && __instance is SandSpiderAI && __args != null && __args.Length != 0)
				{
					object obj = __args[0];
					PlayerControllerB player = (PlayerControllerB)((obj is PlayerControllerB) ? obj : null);
					if (Cocoon.IsCocooned(player) || Cocoon.IsImmune(player))
					{
						__result = false;
					}
				}
			}
			catch (Exception)
			{
			}
		}
	}
	[HarmonyPatch(typeof(SandSpiderAI), "OnCollideWithPlayer")]
	internal static class SpiderAttackPatch
	{
		private static bool Prefix(SandSpiderAI __instance, Collider other, ref float ___timeSinceHittingPlayer, bool ___onWall, bool ___spoolingPlayerBody, DeadBodyInfo ___currentlyHeldBody)
		{
			if (((EnemyAI)__instance).isEnemyDead || ___onWall)
			{
				return false;
			}
			if ((Object)(object)___currentlyHeldBody != (Object)null)
			{
				return false;
			}
			PlayerControllerB val = ((EnemyAI)__instance).MeetsStandardPlayerCollisionConditions(other, ___spoolingPlayerBody, false);
			if ((Object)(object)val != (Object)null && !Cocoon.IsCocooned(val) && !Cocoon.IsImmune(val) && ___timeSinceHittingPlayer > 1f)
			{
				___timeSinceHittingPlayer = 0f;
				Plugin.Log.LogInfo((object)"Spider hit intercepted: no damage, cocooning player.");
				__instance.HitPlayerServerRpc((int)GameNetworkManager.Instance.localPlayerController.playerClientId);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(SandSpiderAI), "HitPlayerClientRpc")]
	internal static class SpiderHitSyncPatch
	{
		private static void Postfix(SandSpiderAI __instance, int playerId)
		{
			try
			{
				PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
				if (playerId >= 0 && playerId < allPlayerScripts.Length)
				{
					Cocoon.Begin(allPlayerScripts[playerId], __instance);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("SpiderHitSyncPatch failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(SandSpiderAI), "HangBodyFromCeiling")]
	internal static class SpiderHangPatch
	{
		private static void Prefix(SandSpiderAI __instance, DeadBodyInfo ___currentlyHeldBody)
		{
			try
			{
				Cocoon.OnBodyHung(___currentlyHeldBody, __instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("SpiderHangPatch failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(SandSpiderAI), "SpiderTurnBodyIntoWebClientRpc")]
	internal static class SpiderWrapRpcPatch
	{
		private static bool Prefix(SandSpiderAI __instance, DeadBodyInfo ___currentlyHeldBody)
		{
			try
			{
				if (((NetworkBehaviour)__instance).IsOwner || (Object)(object)___currentlyHeldBody != (Object)null)
				{
					return true;
				}
				CocoonRunner.Run(Cocoon.WrapWhenReady(__instance));
				return false;
			}
			catch (Exception)
			{
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(SandSpiderAI), "SpiderHangBodyClientRpc")]
	internal static class SpiderHangRpcPatch
	{
		private static bool Prefix(SandSpiderAI __instance, DeadBodyInfo ___currentlyHeldBody)
		{
			try
			{
				if (((NetworkBehaviour)__instance).IsOwner || (Object)(object)___currentlyHeldBody != (Object)null)
				{
					return true;
				}
				CocoonRunner.Run(Cocoon.HangWhenReady(__instance));
				return false;
			}
			catch (Exception)
			{
				return true;
			}
		}
	}
}