Decompiled source of GhostPossession v0.2.0

GhostPossession.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using Photon.Pun;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[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 GhostPossession
{
	public static class ModConfig
	{
		public static ConfigFile Config { get; private set; }

		public static float GhostSpeed { get; private set; }

		public static float GhostSprintMultiplier { get; private set; }

		public static float PossessionScanRadius { get; private set; }

		public static float PossessionForce { get; private set; }

		public static float PossessionJumpForce { get; private set; }

		public static float PossessionTorque { get; private set; }

		public static bool DebugLogging { get; private set; }

		public static bool DebugPreventRunEnd { get; private set; }

		public static KeyCode ReviveKey { get; private set; }

		public static bool ReviveApplyStatus { get; private set; }

		public static void Init(ConfigFile config)
		{
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			Config = config;
			GhostSpeed = config.Bind<float>("Ghost", "GhostSpeed", 8f, "Free-fly ghost movement speed in meters per second.").Value;
			GhostSprintMultiplier = config.Bind<float>("Ghost", "GhostSprintMultiplier", 2f, "Sprint multiplier while holding Left Shift.").Value;
			PossessionScanRadius = config.Bind<float>("Possession", "PossessionScanRadius", 15f, "Search radius for possession candidates in meters.").Value;
			PossessionForce = config.Bind<float>("Possession", "PossessionForce", 18f, "Horizontal force applied to possessed rigid bodies.").Value;
			PossessionJumpForce = config.Bind<float>("Possession", "PossessionJumpForce", 7f, "Upward impulse applied when jumping in possession mode.").Value;
			PossessionTorque = config.Bind<float>("Possession", "PossessionTorque", 30f, "Torque used to steer possessed rigid bodies.").Value;
			DebugLogging = config.Bind<bool>("Debug", "DebugLogging", true, "Enables verbose plugin logs for debugging and hotkey testing.").Value;
			DebugPreventRunEnd = config.Bind<bool>("Debug", "DebugPreventRunEnd", true, "Prevents the run from ending during ghost debug tests.").Value;
			ReviveKey = config.Bind<KeyCode>("Ghost", "ReviveKey", (KeyCode)103, "While a ghost, press this key to stop being a ghost and revive your character at the ghost's current position.").Value;
			ReviveApplyStatus = config.Bind<bool>("Ghost", "ReviveApplyStatus", false, "When reviving at the ghost position, also apply the vanilla post-revive penalty (revival curse + hunger). Off by default because this is a debug tool.").Value;
		}

		public static void Refresh()
		{
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: 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)
			if (Config != null)
			{
				GhostSpeed = ((Config["Ghost", "GhostSpeed"].BoxedValue is float num) ? num : 8f);
				GhostSprintMultiplier = ((Config["Ghost", "GhostSprintMultiplier"].BoxedValue is float num2) ? num2 : 2f);
				PossessionScanRadius = ((Config["Possession", "PossessionScanRadius"].BoxedValue is float num3) ? num3 : 15f);
				PossessionForce = ((Config["Possession", "PossessionForce"].BoxedValue is float num4) ? num4 : 18f);
				PossessionJumpForce = ((Config["Possession", "PossessionJumpForce"].BoxedValue is float num5) ? num5 : 7f);
				PossessionTorque = ((Config["Possession", "PossessionTorque"].BoxedValue is float num6) ? num6 : 30f);
				DebugLogging = !(Config["Debug", "DebugLogging"].BoxedValue is bool flag) || flag;
				DebugPreventRunEnd = !(Config["Debug", "DebugPreventRunEnd"].BoxedValue is bool flag2) || flag2;
				ReviveKey = (KeyCode)((!(Config["Ghost", "ReviveKey"].BoxedValue is KeyCode val)) ? 103 : ((int)val));
				ReviveApplyStatus = Config["Ghost", "ReviveApplyStatus"].BoxedValue is bool flag3 && flag3;
			}
		}
	}
	public sealed class GlobalGravityController
	{
		private const float WorldScale = 1200f;

		private GameObject _antiSphere;

		private float _messageUntil;

		private bool _hotkeyHeld;

		public void Update()
		{
			if ((Object)(object)_antiSphere == (Object)null)
			{
				AntiSphere[] array = Object.FindObjectsOfType<AntiSphere>();
				foreach (AntiSphere val in array)
				{
					if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name.Contains("GhostPossession World AntiSphere"))
					{
						_antiSphere = ((Component)val).gameObject;
						Configure(_antiSphere);
						break;
					}
				}
			}
			bool flag = Input.GetKey((KeyCode)282) || Input.GetKey((KeyCode)292) || Input.GetKey((KeyCode)257);
			bool num = flag && !_hotkeyHeld;
			_hotkeyHeld = flag;
			if (num)
			{
				GhostPossessionPlugin.Instance?.LogState("Antizooka hotkey received (F1/F11/Num1)");
				if (!NetworkHelper.IsLocalHost())
				{
					GhostPossessionPlugin.Instance.LogState("Antizooka field: host only");
				}
				else if ((Object)(object)_antiSphere != (Object)null)
				{
					DisableField();
				}
				else
				{
					EnableField();
				}
			}
		}

		public void FixedUpdate()
		{
			if ((Object)(object)_antiSphere != (Object)null)
			{
				Configure(_antiSphere);
			}
		}

		public void OnGUI()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_antiSphere == (Object)null) || !(Time.unscaledTime > _messageUntil))
			{
				GUI.Box(new Rect((float)Screen.width - 350f, 20f, 330f, 58f), ((Object)(object)_antiSphere != (Object)null) ? "WORLD ANTIZOOKA FIELD: ON\nF1/F11 — remove field" : "WORLD ANTIZOOKA FIELD: OFF");
			}
		}

		public void Cleanup()
		{
			_antiSphere = null;
		}

		private void EnableField()
		{
			//IL_001e: 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_0023: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform.position : Vector3.zero);
			try
			{
				_antiSphere = PhotonNetwork.Instantiate("AntiSphere", val, Quaternion.identity, (byte)0, (object[])null);
				if ((Object)(object)_antiSphere == (Object)null)
				{
					throw new InvalidOperationException("Photon returned null for AntiSphere");
				}
				((Object)_antiSphere).name = "GhostPossession World AntiSphere";
				Configure(_antiSphere);
				_messageUntil = Time.unscaledTime + 2.5f;
				GhostPossessionPlugin.Instance?.LogState("WORLD ANTIZOOKA FIELD ON, scale=" + 1200f);
			}
			catch (Exception ex)
			{
				_antiSphere = null;
				Debug.LogError((object)("[GhostPossession] Vanilla AntiSphere spawn failed: " + ex));
			}
		}

		private void DisableField()
		{
			GameObject antiSphere = _antiSphere;
			_antiSphere = null;
			try
			{
				PhotonView val = (((Object)(object)antiSphere != (Object)null) ? antiSphere.GetComponent<PhotonView>() : null);
				if (PhotonNetwork.InRoom && (Object)(object)val != (Object)null && val.IsMine)
				{
					PhotonNetwork.Destroy(antiSphere);
				}
				else if ((Object)(object)antiSphere != (Object)null)
				{
					Object.Destroy((Object)(object)antiSphere);
				}
				_messageUntil = Time.unscaledTime + 2.5f;
				GhostPossessionPlugin.Instance?.LogState("World Antizooka field removed");
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] AntiSphere removal failed: " + ex));
			}
		}

		private static void Configure(GameObject sphereObject)
		{
			//IL_001b: 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)
			if ((Object)(object)sphereObject == (Object)null)
			{
				return;
			}
			((Object)sphereObject).name = "GhostPossession World AntiSphere";
			sphereObject.transform.localScale = Vector3.one * 1200f;
			AntiSphere val = sphereObject.GetComponent<AntiSphere>() ?? sphereObject.GetComponentInChildren<AntiSphere>();
			if (!((Object)(object)val == (Object)null))
			{
				SphereCollider component = ((Component)val).GetComponent<SphereCollider>();
				if ((Object)(object)component != (Object)null)
				{
					((Collider)component).enabled = true;
					((Collider)component).isTrigger = true;
				}
			}
		}
	}
	public static class NetworkHelper
	{
		public static bool IsLocalHost()
		{
			try
			{
				return !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient;
			}
			catch
			{
				return false;
			}
		}
	}
	public static class PlayerReflection
	{
		private const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		public static Character GetLocalCharacter()
		{
			try
			{
				return Character.localCharacter;
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
			return null;
		}

		public static bool IsLocalCharacter(Character c)
		{
			Character localCharacter = GetLocalCharacter();
			if ((Object)(object)localCharacter != (Object)null)
			{
				return (Object)(object)localCharacter == (Object)(object)c;
			}
			return false;
		}

		public static void KillLocalCharacter(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return;
			}
			try
			{
				MethodInfo methodInfo = typeof(Character).GetMethod("DieInstantlyLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(Character).GetMethod("DieInstantly", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(Character).GetMethod("Die", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (methodInfo == null)
				{
					Debug.LogError((object)"[GhostPossession] No compatible Character death method was found");
				}
				else
				{
					methodInfo.Invoke(character, null);
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] Die() call failed: " + ex));
			}
		}

		public static bool ReviveLocalCharacterAt(Character character, Vector3 position, bool applyStatus)
		{
			//IL_00b8: 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)
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			try
			{
				object? obj = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(character);
				PhotonView val = (PhotonView)(((obj is PhotonView) ? obj : null) ?? ((Component)character).GetComponentInParent<PhotonView>());
				if ((Object)(object)val != (Object)null && PhotonNetwork.InRoom)
				{
					val.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { position, applyStatus, -1 });
					return true;
				}
				MethodInfo method = typeof(Character).GetMethod("RPCA_ReviveAtPosition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Debug.LogError((object)"[GhostPossession] RPCA_ReviveAtPosition was not found on Character");
					return false;
				}
				method.Invoke(character, new object[3] { position, applyStatus, -1 });
				return true;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] Revive-at-position call failed: " + ex));
				return false;
			}
		}
	}
	public static class RunEndHelper
	{
		public static bool AllowNextRunEnd { get; set; }

		public static void ForceRunEndIfPossible()
		{
			try
			{
				Character localCharacter = PlayerReflection.GetLocalCharacter();
				if ((Object)(object)localCharacter != (Object)null)
				{
					MethodInfo method = typeof(Character).GetMethod("CheckEndGame", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (method == null)
					{
						Debug.LogWarning((object)"[GhostPossession] Character.CheckEndGame was not found");
						return;
					}
					AllowNextRunEnd = true;
					method.Invoke(localCharacter, null);
					Debug.Log((object)"[GhostPossession] Normal run-end check requested");
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] Run end helper failed: " + ex));
			}
		}
	}
	public sealed class SpawnedTestScoutMarker : MonoBehaviour
	{
		private static readonly List<SpawnedTestScoutMarker> Active = new List<SpawnedTestScoutMarker>();

		private Character _character;

		private Renderer[] _renderers;

		private FieldInfo _deadField;

		private FieldInfo _passedOutField;

		public Character TargetCharacter => _character;

		public Vector3 WorldCenter
		{
			get
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: 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_0029: Unknown result type (might be due to invalid IL or missing references)
				if (_renderers != null)
				{
					Renderer[] renderers = _renderers;
					foreach (Renderer val in renderers)
					{
						if ((Object)(object)val != (Object)null)
						{
							Bounds bounds = val.bounds;
							return ((Bounds)(ref bounds)).center;
						}
					}
				}
				return ((Component)this).transform.position;
			}
		}

		private void Awake()
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			_character = ((Component)this).GetComponent<Character>() ?? ((Component)this).GetComponentInChildren<Character>();
			_renderers = ((Component)this).GetComponentsInChildren<Renderer>(true);
			if ((Object)(object)_character != (Object)null && (Object)(object)_character.data != (Object)null)
			{
				BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
				_deadField = ((object)_character.data).GetType().GetField("<dead>k__BackingField", bindingAttr) ?? ((object)_character.data).GetType().GetField("dead", bindingAttr);
				_passedOutField = ((object)_character.data).GetType().GetField("fullyPassedOut", bindingAttr);
			}
			Behaviour[] componentsInChildren = ((Component)this).GetComponentsInChildren<Behaviour>(true);
			foreach (Behaviour val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)(object)this) && !((Object)(object)val == (Object)null))
				{
					switch (((object)val).GetType().Name)
					{
					case "LocalPlayerRenderer":
					case "HideTheBody":
					case "CharacterInput":
					case "CharacterMovement":
					case "PlayerGhost":
						val.enabled = false;
						break;
					}
				}
			}
			Rigidbody[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody obj in componentsInChildren2)
			{
				obj.velocity = Vector3.zero;
				obj.angularVelocity = Vector3.zero;
				obj.isKinematic = true;
			}
			Active.Add(this);
			ForceVisible();
		}

		private void LateUpdate()
		{
			if ((Object)(object)_character != (Object)null)
			{
				_character.isBot = false;
				_character.isZombie = false;
				_character.isScoutmaster = false;
				((Behaviour)_character).enabled = false;
				if ((Object)(object)_character.data != (Object)null)
				{
					_deadField?.SetValue(_character.data, false);
					_passedOutField?.SetValue(_character.data, false);
				}
			}
			ForceVisible();
		}

		private void OnDestroy()
		{
			Active.Remove(this);
			GhostPossessionPlugin.Instance?.LogState("Test scout destroyed");
		}

		private void ForceVisible()
		{
			if (_renderers == null)
			{
				return;
			}
			Renderer[] renderers = _renderers;
			foreach (Renderer val in renderers)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.enabled = true;
				}
			}
		}

		public static void ForceAllVisible()
		{
			for (int num = Active.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)Active[num] == (Object)null)
				{
					Active.RemoveAt(num);
				}
				else
				{
					Active[num].ForceVisible();
				}
			}
		}

		public void HoldAt(Vector3 position, Quaternion rotation)
		{
			//IL_0006: 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_002f: 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)
			((Component)this).transform.position = position;
			((Component)this).transform.rotation = rotation;
			Rigidbody[] componentsInChildren = ((Component)this).GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody obj in componentsInChildren)
			{
				obj.isKinematic = true;
				obj.velocity = Vector3.zero;
				obj.angularVelocity = Vector3.zero;
			}
		}

		public void Throw(Vector3 velocity)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody[] componentsInChildren = ((Component)this).GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody obj in componentsInChildren)
			{
				obj.isKinematic = false;
				obj.velocity = velocity;
			}
		}
	}
	[BepInPlugin("GhostPossession", "GhostPossession", "0.2.0")]
	public class GhostPossessionPlugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		private GhostController _ghostController;

		private PossessionManager _possessionManager;

		private DebugOverlay _debugOverlay;

		private CreatureSpawnMenu _spawnMenu;

		private ItemSpawnMenu _itemSpawnMenu;

		private EventMenu _eventMenu;

		private PlayerTeleportMenu _playerTeleportMenu;

		private GlobalGravityController _globalGravity;

		private bool _initialized;

		private float _debugHotkeyCooldown;

		public static GhostPossessionPlugin Instance { get; private set; }

		public bool IsGhostMode
		{
			get
			{
				if (_ghostController != null)
				{
					return _ghostController.IsGhostMode;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			Instance = this;
			ModConfig.Init(((BaseUnityPlugin)this).Config);
			_ghostController = new GhostController();
			_possessionManager = new PossessionManager();
			_debugOverlay = new DebugOverlay();
			_spawnMenu = new CreatureSpawnMenu();
			_itemSpawnMenu = new ItemSpawnMenu();
			_eventMenu = new EventMenu();
			_playerTeleportMenu = new PlayerTeleportMenu();
			_globalGravity = new GlobalGravityController();
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(HandleCameraPreCull));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Plugin loaded");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Attempting to patch death and run-end hooks");
			try
			{
				_harmony = new Harmony("GhostPossession.Patches");
				_harmony.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Harmony patches active");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"[GhostPossession] Harmony patch failed: {arg}");
			}
			_initialized = true;
		}

		private void Update()
		{
			if (!_initialized)
			{
				return;
			}
			_debugHotkeyCooldown -= Time.deltaTime;
			HandleDebugHotkeys();
			_ghostController.Update();
			_possessionManager.Update();
			_debugOverlay.Update();
			_spawnMenu.Update();
			_itemSpawnMenu.Update();
			_eventMenu.Update();
			_playerTeleportMenu.Update();
			_globalGravity.Update();
			if (Input.GetKeyDown((KeyCode)101) && _ghostController.IsGhostMode)
			{
				if (_possessionManager.IsPossessing)
				{
					_possessionManager.Release();
				}
				else
				{
					_possessionManager.TryPossessCurrentTarget();
				}
			}
		}

		private void OnDestroy()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(HandleCameraPreCull));
			_ghostController?.Cleanup();
			_possessionManager?.Release();
			_globalGravity?.Cleanup();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void HandleDebugHotkeys()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (_debugHotkeyCooldown > 0f)
			{
				return;
			}
			if (IsGhostMode && Input.GetKeyDown(ModConfig.ReviveKey))
			{
				_debugHotkeyCooldown = 0.25f;
				if (ModConfig.DebugLogging)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: revive-at-ghost hotkey received");
				}
				ReviveAtGhostSpot();
				return;
			}
			KeyCode[] array = new KeyCode[4];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			if (IsAnyKeyDown((KeyCode[])(object)array))
			{
				_debugHotkeyCooldown = 0.25f;
				if (ModConfig.DebugLogging)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: death hotkey received");
				}
				TriggerDebugDeath();
				return;
			}
			KeyCode[] array2 = new KeyCode[4];
			RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			if (IsAnyKeyDown((KeyCode[])(object)array2))
			{
				_debugHotkeyCooldown = 0.25f;
				if (ModConfig.DebugLogging)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: run-end hotkey received");
				}
				if (ModConfig.DebugPreventRunEnd)
				{
					if (ModConfig.DebugLogging)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Debug run end requested");
					}
					RunEndHelper.ForceRunEndIfPossible();
				}
				return;
			}
			KeyCode[] array3 = new KeyCode[3];
			RuntimeHelpers.InitializeArray(array3, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			if (IsAnyKeyDown((KeyCode[])(object)array3))
			{
				_debugHotkeyCooldown = 0.25f;
				if (ModConfig.DebugLogging)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: overlay hotkey received");
				}
				_debugOverlay.Enabled = !_debugOverlay.Enabled;
			}
		}

		private void HandleCameraPreCull(Camera camera)
		{
			if (_initialized && (Object)(object)camera == (Object)(object)Camera.main)
			{
				_ghostController.ApplyCameraPose();
				SpawnedTestScoutMarker.ForceAllVisible();
			}
		}

		private void LateUpdate()
		{
			if (_initialized && !_spawnMenu.IsOpen && !_itemSpawnMenu.IsOpen && !_eventMenu.IsOpen && !_playerTeleportMenu.IsOpen)
			{
				_ghostController.LateUpdate();
			}
		}

		private void FixedUpdate()
		{
			if (_initialized)
			{
				_globalGravity?.FixedUpdate();
			}
		}

		private void OnGUI()
		{
			if (_initialized)
			{
				_spawnMenu.OnGUI();
				_itemSpawnMenu.OnGUI();
				_eventMenu.OnGUI();
				_playerTeleportMenu.OnGUI();
				_globalGravity.OnGUI();
				_possessionManager.DrawHud();
			}
		}

		private static bool IsAnyKeyDown(params KeyCode[] keys)
		{
			for (int i = 0; i < keys.Length; i++)
			{
				if (Input.GetKeyDown(keys[i]))
				{
					return true;
				}
			}
			return false;
		}

		public void TriggerDebugDeath()
		{
			if (IsGhostMode)
			{
				LogState("Already in ghost mode");
				return;
			}
			Character localCharacter = PlayerReflection.GetLocalCharacter();
			if ((Object)(object)localCharacter == (Object)null)
			{
				if (ModConfig.DebugLogging)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[GhostPossession] Debug death hotkey pressed but local Character was not found");
				}
				return;
			}
			if (ModConfig.DebugLogging)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] DEBUG: killing local player");
			}
			PlayerReflection.KillLocalCharacter(localCharacter);
			EnterGhostModeAfterDeath();
			if (ModConfig.DebugPreventRunEnd && ModConfig.DebugLogging)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[GhostPossession] Prevented run end for debug ghost test");
			}
		}

		public void EnterGhostModeAfterDeath()
		{
			if (!_ghostController.IsGhostMode)
			{
				_ghostController.EnterGhostMode();
			}
		}

		public void ReviveAtGhostSpot()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (_ghostController == null || !_ghostController.IsGhostMode)
			{
				LogState("Revive-at-ghost ignored: not in ghost mode");
				return;
			}
			if (!TryGetGhostTeleportPosition(out var position))
			{
				LogState("Revive-at-ghost failed: ghost position is unavailable");
				return;
			}
			if (_possessionManager != null && _possessionManager.IsPossessing)
			{
				_possessionManager.Release();
			}
			_ghostController.ReviveAtGhostPosition(position, ModConfig.ReviveApplyStatus);
		}

		public void SetPossessionCameraTarget(GameObject target)
		{
			_ghostController.SetPossessionTarget(((Object)(object)target != (Object)null) ? target.transform : null);
		}

		public void ReapplyGhostCamera()
		{
			_ghostController?.ApplyCameraPose();
			_possessionManager?.ReapplyCreatureFacing();
		}

		public bool TryGetPossessionCameraAnchor(out Vector3 position)
		{
			//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)
			if (_possessionManager != null)
			{
				return _possessionManager.TryGetCameraAnchor(out position);
			}
			position = Vector3.zero;
			return false;
		}

		public bool TryGetGhostTeleportPosition(out Vector3 position)
		{
			//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_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)
			if (_possessionManager != null && _possessionManager.TryGetCameraAnchor(out position))
			{
				return true;
			}
			if (_ghostController != null && _ghostController.IsGhostMode)
			{
				position = _ghostController.GhostPosition;
				return true;
			}
			position = Vector3.zero;
			return false;
		}

		public void ApplyPossessionFixedInput(Character character)
		{
			_possessionManager?.ApplyBeforeCharacterFixedUpdate(character);
		}

		public void LogLocalTarget(string message)
		{
			if (ModConfig.DebugLogging)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[GhostPossession] Target: " + message));
			}
		}

		public void LogState(string message)
		{
			if (ModConfig.DebugLogging)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[GhostPossession] " + message));
			}
		}
	}
	public class GhostController
	{
		private Transform _cameraTransform;

		private float _pitch;

		private float _yaw;

		private Character _character;

		private CharacterInput _characterInput;

		private Transform _possessionTarget;

		private Vector3 _ghostPosition;

		private Quaternion _cameraRotation = Quaternion.identity;

		private readonly Dictionary<Renderer, bool> _rendererStates = new Dictionary<Renderer, bool>();

		public bool IsGhostMode { get; private set; }

		public bool IsFreeFlyEnabled { get; private set; }

		public Vector3 GhostPosition => _ghostPosition;

		public void Update()
		{
		}

		public void LateUpdate()
		{
			if (IsGhostMode)
			{
				UpdateGhostMovement();
			}
		}

		public void EnterGhostMode()
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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)
			IsGhostMode = true;
			IsFreeFlyEnabled = true;
			_character = PlayerReflection.GetLocalCharacter();
			if ((Object)(object)_character != (Object)null)
			{
				_characterInput = _character.input;
				if ((Object)(object)_characterInput != (Object)null)
				{
					ResetInput(_characterInput);
					((Behaviour)_characterInput).enabled = false;
				}
				_rendererStates.Clear();
				Renderer[] componentsInChildren = ((Component)_character).GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren)
				{
					_rendererStates[val] = val.enabled;
					val.enabled = false;
				}
			}
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				_cameraTransform = ((Component)main).transform;
				_pitch = 0f;
				_yaw = _cameraTransform.eulerAngles.y;
				_ghostPosition = _cameraTransform.position;
				_cameraRotation = _cameraTransform.rotation;
			}
			GhostPossessionPlugin.Instance?.LogState("Entering free ghost mode");
		}

		public void ExitGhostMode()
		{
			IsGhostMode = false;
			IsFreeFlyEnabled = false;
			RestoreCharacter();
			GhostPossessionPlugin.Instance?.LogState("Leaving ghost mode");
		}

		public unsafe bool ReviveAtGhostPosition(Vector3 position, bool applyStatus)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!IsGhostMode)
			{
				return false;
			}
			Character val = PlayerReflection.GetLocalCharacter() ?? _character;
			if ((Object)(object)val == (Object)null)
			{
				GhostPossessionPlugin.Instance?.LogState("Revive failed: local Character was not found");
				return false;
			}
			if (!PlayerReflection.ReviveLocalCharacterAt(val, position, applyStatus))
			{
				return false;
			}
			IsGhostMode = false;
			IsFreeFlyEnabled = false;
			_possessionTarget = null;
			RestoreCharacter();
			GhostPossessionPlugin.Instance?.LogState("Revived as human at ghost position " + ((object)(*(Vector3*)(&position))/*cast due to .constrained prefix*/).ToString());
			return true;
		}

		public void SetPossessionTarget(Transform target)
		{
			_possessionTarget = target;
		}

		public void Cleanup()
		{
			IsGhostMode = false;
			IsFreeFlyEnabled = false;
			_possessionTarget = null;
			RestoreCharacter();
		}

		private void RestoreCharacter()
		{
			foreach (KeyValuePair<Renderer, bool> rendererState in _rendererStates)
			{
				if ((Object)(object)rendererState.Key != (Object)null)
				{
					rendererState.Key.enabled = rendererState.Value;
				}
			}
			_rendererStates.Clear();
			if ((Object)(object)_characterInput != (Object)null)
			{
				((Behaviour)_characterInput).enabled = true;
				ResetInput(_characterInput);
			}
			_characterInput = null;
			_character = null;
		}

		private static void ResetInput(CharacterInput input)
		{
			//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_000c: 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)
			input.movementInput = Vector2.zero;
			input.lookInput = Vector2.zero;
			input.sprintIsPressed = false;
			input.jumpIsPressed = false;
			input.jumpWasPressed = false;
			input.usePrimaryIsPressed = false;
			input.usePrimaryWasPressed = false;
			input.useSecondaryIsPressed = false;
			input.useSecondaryWasPressed = false;
		}

		private void UpdateGhostMovement()
		{
			//IL_0093: 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_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_00bd: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: 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_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: 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_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: 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_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Camera.main == (Object)null)
			{
				return;
			}
			float num = ModConfig.GhostSpeed;
			if (Input.GetKey((KeyCode)304))
			{
				num *= ModConfig.GhostSprintMultiplier;
			}
			float axis = Input.GetAxis("Mouse X");
			float axis2 = Input.GetAxis("Mouse Y");
			_yaw += axis * 2.2f;
			_pitch -= axis2 * 1.8f;
			_pitch = Mathf.Clamp(_pitch, -85f, 85f);
			_cameraRotation = Quaternion.Euler(_pitch, _yaw, 0f);
			if ((Object)(object)_possessionTarget != (Object)null)
			{
				ApplyCameraPose();
				return;
			}
			Vector3 val = _cameraRotation * Vector3.forward;
			Vector3 val2 = _cameraRotation * Vector3.right;
			Vector3 up = Vector3.up;
			Vector3 val3 = Vector3.zero;
			if (Input.GetKey((KeyCode)119))
			{
				val3 += val;
			}
			if (Input.GetKey((KeyCode)115))
			{
				val3 -= val;
			}
			if (Input.GetKey((KeyCode)100))
			{
				val3 += val2;
			}
			if (Input.GetKey((KeyCode)97))
			{
				val3 -= val2;
			}
			if (Input.GetKey((KeyCode)32))
			{
				val3 += up;
			}
			if (Input.GetKey((KeyCode)306))
			{
				val3 -= up;
			}
			if (((Vector3)(ref val3)).sqrMagnitude > 0f)
			{
				((Vector3)(ref val3)).Normalize();
				_ghostPosition += val3 * num * Time.deltaTime;
			}
			ApplyCameraPose();
		}

		public void ApplyCameraPose()
		{
			//IL_0020: 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_0059: 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_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_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_0079: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			if (!IsGhostMode)
			{
				return;
			}
			Camera main = Camera.main;
			if (!((Object)(object)main == (Object)null))
			{
				((Component)main).transform.rotation = _cameraRotation;
				if ((Object)(object)_possessionTarget != (Object)null && (Object)(object)GhostPossessionPlugin.Instance != (Object)null && GhostPossessionPlugin.Instance.TryGetPossessionCameraAnchor(out var position))
				{
					((Component)main).transform.position = position + Vector3.up * 2.2f - _cameraRotation * Vector3.forward * 4f;
				}
				else
				{
					((Component)main).transform.position = _ghostPosition;
				}
			}
		}
	}
	[HarmonyPatch(typeof(MainCameraMovement), "LateUpdate")]
	public static class MainCameraMovementGhostPatch
	{
		public static void Postfix()
		{
			GhostPossessionPlugin.Instance?.ReapplyGhostCamera();
		}
	}
	[HarmonyPatch(typeof(MainCamera), "LateUpdate")]
	public static class MainCameraGhostPatch
	{
		public static void Postfix()
		{
			GhostPossessionPlugin.Instance?.ReapplyGhostCamera();
		}
	}
	[HarmonyPatch(typeof(Character), "FixedUpdate")]
	public static class PossessedCharacterFixedUpdatePatch
	{
		public static void Prefix(Character __instance)
		{
			GhostPossessionPlugin.Instance?.ApplyPossessionFixedInput(__instance);
		}
	}
	[HarmonyPatch(typeof(Character), "Die")]
	public static class DiePatch
	{
		public static void Prefix(Character __instance, ref bool __state)
		{
			__state = PlayerReflection.IsLocalCharacter(__instance);
		}

		public static void Postfix(bool __state)
		{
			if (__state)
			{
				GhostPossessionPlugin.Instance?.LogState("Local player died");
				GhostPossessionPlugin.Instance?.EnterGhostModeAfterDeath();
			}
		}
	}
	[HarmonyPatch(typeof(Character), "NobodyIsAlive")]
	public static class NobodyIsAlivePatch
	{
		public static void Postfix(ref bool __result)
		{
			if ((Object)(object)GhostPossessionPlugin.Instance != (Object)null && GhostPossessionPlugin.Instance.IsGhostMode)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Scoutmaster), "CanSeeTarget")]
	public static class ScoutmasterCanSeeGhostPatch
	{
		public static void Postfix(Character currentTarget, ref bool __result)
		{
			if (__result && (Object)(object)GhostPossessionPlugin.Instance != (Object)null && GhostPossessionPlugin.Instance.IsGhostMode && PlayerReflection.IsLocalCharacter(currentTarget))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Character), "CheckEndGame")]
	public static class RunEndPatch
	{
		public static bool Prefix(Character __instance)
		{
			if (!ModConfig.DebugPreventRunEnd || RunEndHelper.AllowNextRunEnd)
			{
				RunEndHelper.AllowNextRunEnd = false;
				return true;
			}
			if (PlayerReflection.IsLocalCharacter(__instance))
			{
				GhostPossessionPlugin.Instance?.LogState("Prevented run end for debug ghost test");
				return false;
			}
			return true;
		}
	}
	public class CreaturePossessable : IPossessable
	{
		private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private readonly Component _component;

		private readonly Scoutmaster _scoutmaster;

		private readonly Mob _mob;

		private readonly Character _controlledCharacter;

		private readonly CharacterInput _input;

		private readonly Rigidbody _body;

		private readonly Behaviour _aiBehaviour;

		private readonly GameObject _followObject;

		private readonly Rigidbody[] _characterBodies;

		private readonly FieldInfo _mobSleepingField;

		private readonly FieldInfo _mobForceNoMovementField;

		private bool _wasAiEnabled;

		private SpawnedTestScoutMarker _heldDummy;

		public bool IsValid
		{
			get
			{
				if ((Object)(object)_component != (Object)null)
				{
					return (Object)(object)_component.gameObject != (Object)null;
				}
				return false;
			}
		}

		public GameObject GameObject => _followObject;

		public Vector3 CameraAnchorPosition
		{
			get
			{
				//IL_003f: 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_0027: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_controlledCharacter != (Object)null))
				{
					if (!((Object)(object)_body != (Object)null))
					{
						return _component.transform.position;
					}
					return _body.worldCenterOfMass;
				}
				return _controlledCharacter.Center;
			}
		}

		public string DisplayName
		{
			get
			{
				if (!((Object)(object)_component != (Object)null))
				{
					return "Creature";
				}
				return ((object)_component).GetType().Name;
			}
		}

		public string ControlsText
		{
			get
			{
				if ((Object)(object)_scoutmaster != (Object)null)
				{
					return "WASD move | C climb | Space jump | Shift sprint | LMB grab | RMB FORCE THROW | E exit";
				}
				if (_component is Beetle)
				{
					return "WASD move | Shift sprint | LMB bonk player | E exit";
				}
				if (_component is Scorpion)
				{
					return "WASD move | Shift sprint | LMB sting player | E exit";
				}
				if (_component is MushroomZombie)
				{
					return "WASD move | Shift sprint | LMB lunge at player | E exit";
				}
				if (_component is BeeSwarm)
				{
					return "WASD fly | Space up | LMB anger at player | E exit";
				}
				if (_component is Spider)
				{
					return "LMB grab player | RMB release | E exit";
				}
				if (_component is FrogTongue)
				{
					return "WASD move | Shift sprint | LMB tongue attack | E exit";
				}
				if (_component is GhostBall)
				{
					return "WASD float | Space jump | Shift sprint | E exit";
				}
				return "WASD move | Space jump | Shift sprint | E exit";
			}
		}

		public CreaturePossessable(Component component)
		{
			_component = component;
			_scoutmaster = (Scoutmaster)(object)((component is Scoutmaster) ? component : null);
			_mob = (Mob)(object)((component is Mob) ? component : null);
			_controlledCharacter = (((Object)(object)component != (Object)null) ? (component.GetComponent<Character>() ?? component.GetComponentInChildren<Character>() ?? component.GetComponentInParent<Character>()) : null);
			_input = (((Object)(object)_controlledCharacter != (Object)null) ? _controlledCharacter.input : null);
			_body = (Rigidbody)(((Object)(object)_mob != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)(((Object)(object)component != (Object)null) ? (component.GetComponent<Rigidbody>() ?? component.GetComponentInChildren<Rigidbody>() ?? component.GetComponentInParent<Rigidbody>()) : null)));
			_aiBehaviour = (Behaviour)(object)((component is Behaviour) ? component : null);
			_followObject = (((Object)(object)_controlledCharacter != (Object)null) ? ((Component)_controlledCharacter).gameObject : (((Object)(object)_body != (Object)null) ? ((Component)_body).gameObject : component.gameObject));
			_characterBodies = (Rigidbody[])(((Object)(object)_controlledCharacter != (Object)null) ? ((Array)((Component)_controlledCharacter).GetComponentsInChildren<Rigidbody>(true)) : ((Array)new Rigidbody[0]));
			_mobSleepingField = typeof(Mob).GetField("sleeping", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_mobForceNoMovementField = typeof(Mob).GetField("forceNoMovement", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}

		public void Enter()
		{
			if ((Object)(object)_input == (Object)null && (Object)(object)_body == (Object)null)
			{
				GhostPossessionPlugin.Instance?.LogState("Creature has no movable controller");
				return;
			}
			_wasAiEnabled = (Object)(object)_aiBehaviour != (Object)null && _aiBehaviour.enabled;
			if ((Object)(object)_aiBehaviour != (Object)null && !(_component is BeeSwarm) && !(_component is FrogTongue))
			{
				_aiBehaviour.enabled = false;
			}
			ResetInput();
			GhostPossessionPlugin.Instance?.LogState("Creature control enabled");
		}

		public void Exit()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_heldDummy != (Object)null)
			{
				_heldDummy.Throw(Vector3.zero);
				_heldDummy = null;
			}
			ResetInput();
			if ((Object)(object)_aiBehaviour != (Object)null)
			{
				_aiBehaviour.enabled = _wasAiEnabled;
			}
			GhostPossessionPlugin.Instance?.LogState("Creature possession released");
		}

		public void UpdateInput()
		{
			//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_00c8: 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)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: 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_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: 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_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: 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_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			if (!IsValid)
			{
				return;
			}
			Camera main = Camera.main;
			ApplyFacing(main);
			UpdateHeldDummy(main);
			if ((Object)(object)_input != (Object)null)
			{
				_input.movementInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
				_input.sprintIsPressed = Input.GetKey((KeyCode)304);
				_input.jumpIsPressed = Input.GetKey((KeyCode)32);
				_input.jumpWasPressed = Input.GetKeyDown((KeyCode)32);
				if ((Object)(object)_scoutmaster != (Object)null)
				{
					UpdateScoutmasterClimbing(main);
				}
			}
			else if ((Object)(object)_body != (Object)null && (Object)(object)main != (Object)null)
			{
				Vector3 val = ((Component)main).transform.forward * Input.GetAxisRaw("Vertical") + ((Component)main).transform.right * Input.GetAxisRaw("Horizontal");
				val.y = 0f;
				float num = (Input.GetKey((KeyCode)304) ? 6f : 3.5f);
				if ((Object)(object)_mob != (Object)null)
				{
					_mobSleepingField?.SetValue(_mob, false);
					_mobForceNoMovementField?.SetValue(_mob, _component is FrogTongue);
					if (((Vector3)(ref val)).sqrMagnitude > 0f)
					{
						_body.MovePosition(_body.position + ((Vector3)(ref val)).normalized * num * Time.deltaTime);
					}
				}
				else
				{
					Vector3 val2 = ((((Vector3)(ref val)).sqrMagnitude > 0f) ? (((Vector3)(ref val)).normalized * num) : Vector3.zero);
					Vector3 val3 = Vector3.MoveTowards(new Vector3(_body.velocity.x, 0f, _body.velocity.z), val2, 12f * Time.deltaTime);
					_body.velocity = new Vector3(val3.x, _body.velocity.y, val3.z);
					if (Input.GetKeyDown((KeyCode)32))
					{
						_body.AddForce(Vector3.up * ModConfig.PossessionJumpForce, (ForceMode)1);
					}
				}
			}
			if (Input.GetMouseButtonDown(0))
			{
				UsePrimaryAttack();
			}
			if (((Object)(object)_scoutmaster != (Object)null || _component is Spider) && Input.GetMouseButtonDown(1))
			{
				if ((Object)(object)_heldDummy != (Object)null)
				{
					Vector3 val4 = (((Object)(object)main != (Object)null) ? ((Component)main).transform.forward : _component.transform.forward);
					_heldDummy.Throw(val4 * 14f + Vector3.up * 5f);
					_heldDummy = null;
				}
				else if ((Object)(object)_scoutmaster != (Object)null)
				{
					ForceScoutmasterThrow(main);
				}
				else
				{
					Invoke("RPCA_LetGo");
				}
			}
		}

		private void ForceScoutmasterThrow(Camera camera)
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_controlledCharacter == (Object)null || (Object)(object)_controlledCharacter.data == (Object)null || _controlledCharacter.refs == null || (Object)(object)_controlledCharacter.refs.grabbing == (Object)null)
			{
				GhostPossessionPlugin.Instance?.LogState("Scoutmaster throw: grabbing controller is unavailable");
				return;
			}
			object? obj = typeof(CharacterData).GetField("grabbedPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(_controlledCharacter.data);
			Character val = (Character)((obj is Character) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				GhostPossessionPlugin.Instance?.LogState("Scoutmaster throw: no grabbed player (grab with LMB first)");
				return;
			}
			Vector3 val2 = (((Object)(object)camera != (Object)null) ? ((Component)camera).transform.forward : _component.transform.forward);
			if (((Vector3)(ref val2)).sqrMagnitude < 0.001f)
			{
				val2 = _component.transform.forward;
			}
			((Vector3)(ref val2)).Normalize();
			val2.y = Mathf.Max(val2.y, 0.3f);
			try
			{
				MethodInfo? method = typeof(CharacterGrabbing).GetMethod("Throw", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					throw new MissingMethodException("CharacterGrabbing.Throw");
				}
				method.Invoke(_controlledCharacter.refs.grabbing, new object[2]
				{
					val2 * 1500f,
					3f
				});
				typeof(Scoutmaster).GetField("isThrowing", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(_scoutmaster, false);
				GhostPossessionPlugin.Instance?.LogState("Scoutmaster force-threw " + ((Object)val).name);
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] Scoutmaster forced throw failed: " + ex));
			}
		}

		private void ApplyFacing(Camera camera)
		{
			//IL_0010: 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_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_003d: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)camera == (Object)null)
			{
				return;
			}
			Vector3 forward = ((Component)camera).transform.forward;
			forward.y = 0f;
			if (!(((Vector3)(ref forward)).sqrMagnitude < 0.001f))
			{
				Quaternion val = Quaternion.LookRotation(((Vector3)(ref forward)).normalized, Vector3.up);
				if ((Object)(object)_scoutmaster != (Object)null && (Object)(object)_controlledCharacter != (Object)null)
				{
					Invoke("LookAt", _controlledCharacter.Center + ((Vector3)(ref forward)).normalized * 10f);
				}
				else if (_component is MushroomZombie && (Object)(object)_controlledCharacter != (Object)null)
				{
					Invoke("LookAt", _controlledCharacter.Center + ((Vector3)(ref forward)).normalized * 10f);
				}
				else if ((Object)(object)_body != (Object)null)
				{
					_body.MoveRotation(val);
				}
				else
				{
					_component.transform.rotation = val;
				}
			}
		}

		public void ReapplyFacing()
		{
			if (IsValid)
			{
				ApplyFacing(Camera.main);
			}
		}

		public void ApplyBeforeCharacterFixedUpdate(Character character)
		{
			//IL_0048: 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)
			if (IsValid && !((Object)(object)character == (Object)null) && !((Object)(object)character != (Object)(object)_controlledCharacter) && !((Object)(object)_input == (Object)null))
			{
				_input.movementInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
				_input.sprintIsPressed = Input.GetKey((KeyCode)304);
				_input.jumpIsPressed = Input.GetKey((KeyCode)32);
				_input.jumpWasPressed = Input.GetKeyDown((KeyCode)32);
				if ((Object)(object)_scoutmaster != (Object)null)
				{
					UpdateScoutmasterClimbing(Camera.main);
					ApplyScoutmasterClimbForce(Camera.main);
				}
			}
		}

		private void UsePrimaryAttack()
		{
			SpawnedTestScoutMarker spawnedTestScoutMarker = FindNearestDummy(4f);
			if ((Object)(object)spawnedTestScoutMarker != (Object)null)
			{
				AttackDummy(spawnedTestScoutMarker);
				return;
			}
			Character val = FindNearestLivingPlayer(6f);
			if ((Object)(object)val == (Object)null)
			{
				GhostPossessionPlugin.Instance?.LogState("Attack: no target within 6 meters");
			}
			else if ((Object)(object)_scoutmaster != (Object)null)
			{
				ForceScoutmasterGrab(val);
			}
			else if (_component is Beetle || _component is Scorpion)
			{
				ForceMobAttack(val);
			}
			else if (_component is MushroomZombie)
			{
				Invoke("SetCurrentTarget", val, 5f);
				Invoke("StartLunging");
			}
			else if (_component is BeeSwarm)
			{
				((object)_component).GetType().GetField("currentAggroCharacter", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(_component, val);
				Invoke("SetBeesAngryRPC", true);
				Invoke("GetAngry", 12f);
			}
			else if (_component is Spider)
			{
				object obj = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val);
				Invoke("RPCA_GrabCharacter", obj);
			}
			else if (_component is FrogTongue)
			{
				ForceFrogAttack(val);
			}
		}

		private void ForceScoutmasterGrab(Character target)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				object? obj = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(_controlledCharacter);
				object? obj2 = ((obj is PhotonView) ? obj : null);
				object? obj3 = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target);
				PhotonView val = (PhotonView)((obj3 is PhotonView) ? obj3 : null);
				if ((Object)obj2 == (Object)null || (Object)(object)val == (Object)null)
				{
					throw new InvalidOperationException("missing PhotonView");
				}
				((PhotonView)obj2).RPC("RPCA_GrabAttach", (RpcTarget)0, new object[3]
				{
					val,
					0,
					Vector3.zero
				});
				Invoke("SetCurrentTarget", target, 8f);
				GhostPossessionPlugin.Instance?.LogState("Scoutmaster grabbed " + target.characterName + " (RMB to throw)");
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] Scoutmaster forced grab failed: " + ex));
			}
		}

		private void ForceMobAttack(Character target)
		{
			try
			{
				PhotonView val = (((Object)(object)_mob != (Object)null) ? ((MonoBehaviourPun)_mob).photonView : null);
				object? obj = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target);
				PhotonView val2 = (PhotonView)((obj is PhotonView) ? obj : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					throw new InvalidOperationException("missing PhotonView");
				}
				val.RPC("RPC_SyncTargetCharacter", (RpcTarget)0, new object[1] { val2.ViewID });
				val.RPC("RPC_StartAttack", (RpcTarget)0, Array.Empty<object>());
				typeof(Mob).GetField("inRangeForAttackTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(_mob, typeof(Mob).GetField("attackTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(_mob) ?? ((object)0f));
				GhostPossessionPlugin.Instance?.LogState(DisplayName + " network attack -> " + target.characterName);
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] Mob network attack failed: " + ex));
			}
		}

		private void ForceFrogAttack(Character target)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Component component = _component;
				FrogTongue val = (FrogTongue)(object)((component is FrogTongue) ? component : null);
				PhotonView obj = (((Object)(object)val != (Object)null) ? ((MonoBehaviourPun)val).photonView : null);
				object? obj2 = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target);
				PhotonView val2 = (PhotonView)((obj2 is PhotonView) ? obj2 : null);
				if ((Object)(object)obj == (Object)null || (Object)(object)val2 == (Object)null)
				{
					throw new InvalidOperationException("missing PhotonView");
				}
				obj.RPC("RPCA_FrogAction", (RpcTarget)0, new object[3]
				{
					val2,
					(object)(FrogActionType)1,
					target.Center
				});
				GhostPossessionPlugin.Instance?.LogState("Frog tongue attack -> " + target.characterName);
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] Frog network attack failed: " + ex));
			}
		}

		private void AttackDummy(SpawnedTestScoutMarker dummy)
		{
			Character targetCharacter = dummy.TargetCharacter;
			if ((Object)(object)_scoutmaster != (Object)null || _component is Spider)
			{
				_heldDummy = dummy;
				GhostPossessionPlugin.Instance?.LogState(DisplayName + " grabbed Test scout");
			}
			else if ((_component is Beetle || _component is Scorpion) && (Object)(object)targetCharacter != (Object)null)
			{
				Invoke("InflictAttack", targetCharacter);
				GhostPossessionPlugin.Instance?.LogState(DisplayName + " attacked Test scout");
			}
			else if (_component is MushroomZombie && (Object)(object)targetCharacter != (Object)null)
			{
				Invoke("OnBitCharacter", targetCharacter);
				GhostPossessionPlugin.Instance?.LogState("MushroomZombie bit Test scout");
			}
			else if (_component is BeeSwarm && (Object)(object)targetCharacter != (Object)null)
			{
				((object)_component).GetType().GetField("currentAggroCharacter", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(_component, targetCharacter);
				Invoke("SetBeesAngryRPC", true);
				Invoke("GetAngry", 12f);
				GhostPossessionPlugin.Instance?.LogState("BeeSwarm angered at Test scout");
			}
		}

		private SpawnedTestScoutMarker FindNearestDummy(float maxDistance)
		{
			//IL_0005: 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_001c: 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)
			SpawnedTestScoutMarker result = null;
			float num = maxDistance;
			Vector3 cameraAnchorPosition = CameraAnchorPosition;
			SpawnedTestScoutMarker[] array = Object.FindObjectsOfType<SpawnedTestScoutMarker>();
			foreach (SpawnedTestScoutMarker spawnedTestScoutMarker in array)
			{
				float num2 = Vector3.Distance(cameraAnchorPosition, spawnedTestScoutMarker.WorldCenter);
				if (num2 < num)
				{
					result = spawnedTestScoutMarker;
					num = num2;
				}
			}
			return result;
		}

		private Character FindNearestLivingPlayer(float maxDistance)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_006c: 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)
			Character result = null;
			float num = maxDistance;
			Vector3 val = (((Object)(object)_controlledCharacter != (Object)null) ? _controlledCharacter.Center : CameraAnchorPosition);
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.isBot && !((Object)(object)allCharacter.data == (Object)null) && !allCharacter.data.dead)
				{
					float num2 = Vector3.Distance(val, allCharacter.Center);
					if (num2 < num)
					{
						result = allCharacter;
						num = num2;
					}
				}
			}
			return result;
		}

		private void UpdateScoutmasterClimbing(Camera camera)
		{
			//IL_0028: 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_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_0043: 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_004d: 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_004f: 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_0067: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_0080: 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_008f: 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_009e: 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_00c5: 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)
			if (!((Object)(object)camera == (Object)null) && !((Object)(object)_controlledCharacter == (Object)null) && Input.GetKey((KeyCode)99))
			{
				Vector3 forward = ((Component)camera).transform.forward;
				Vector3 val = _controlledCharacter.Center + Vector3.up * 0.5f;
				RaycastHit val3 = default(RaycastHit);
				Vector3 val2 = ((Physics.Raycast(val, forward, ref val3, 3f, -1, (QueryTriggerInteraction)1) && Vector3.Angle(((RaycastHit)(ref val3)).normal, Vector3.up) > 45f) ? (((RaycastHit)(ref val3)).point + Vector3.up * 3f) : (val + ((Vector3)(ref forward)).normalized * 5f + Vector3.up * 3f));
				Invoke("ClimbTowards", val2, Input.GetKey((KeyCode)304) ? 1.6f : 1f);
			}
		}

		private void ApplyScoutmasterClimbForce(Camera camera)
		{
			//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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_00a2: 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)
			if (!Input.GetKey((KeyCode)99) || (Object)(object)camera == (Object)null)
			{
				return;
			}
			Vector3 forward = ((Component)camera).transform.forward;
			forward.y = 0f;
			if (((Vector3)(ref forward)).sqrMagnitude > 0f)
			{
				((Vector3)(ref forward)).Normalize();
			}
			float num = (Input.GetKey((KeyCode)304) ? 5f : 3.2f);
			Rigidbody[] characterBodies = _characterBodies;
			foreach (Rigidbody val in characterBodies)
			{
				if (!((Object)(object)val == (Object)null) && !val.isKinematic)
				{
					Vector3 val2 = forward * 1.8f + Vector3.up * num;
					val.velocity = Vector3.MoveTowards(val.velocity, val2, 14f * Time.fixedDeltaTime);
				}
			}
		}

		private void UpdateHeldDummy(Camera camera)
		{
			//IL_004b: 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_0050: 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)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00d4: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_heldDummy == (Object)null) && (!((Object)(object)_scoutmaster == (Object)null) || _component is Spider))
			{
				Vector3 val = (((Object)(object)camera != (Object)null) ? ((Component)camera).transform.forward : _component.transform.forward);
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
				{
					val = _component.transform.forward;
				}
				Vector3 val2 = (((Object)(object)_controlledCharacter != (Object)null) ? _controlledCharacter.Center : _component.transform.position);
				_heldDummy.HoldAt(val2 + Vector3.up * 1.2f + ((Vector3)(ref val)).normalized * 1.8f, Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up));
			}
		}

		private void Invoke(string name, params object[] arguments)
		{
			try
			{
				((object)_component).GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(_component, arguments);
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[GhostPossession] Creature action failed: " + ex));
			}
		}

		private void ResetInput()
		{
			//IL_0015: 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_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)
			if (!((Object)(object)_input == (Object)null))
			{
				_input.movementInput = Vector2.zero;
				_input.lookInput = Vector2.zero;
				_input.sprintIsPressed = false;
				_input.jumpIsPressed = false;
				_input.jumpWasPressed = false;
				_input.usePrimaryIsPressed = false;
				_input.usePrimaryWasPressed = false;
				_input.useSecondaryIsPressed = false;
				_input.useSecondaryWasPressed = false;
			}
		}
	}
	public static class CreatureSupport
	{
		public static Component FindCreature(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			Component val = (Component)(object)(gameObject.GetComponentInParent<Scoutmaster>() ?? gameObject.GetComponentInChildren<Scoutmaster>());
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = (Component)(object)(gameObject.GetComponentInParent<MushroomZombie>() ?? gameObject.GetComponentInChildren<MushroomZombie>());
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = (Component)(object)(gameObject.GetComponentInParent<Beetle>() ?? gameObject.GetComponentInChildren<Beetle>());
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = (Component)(object)(gameObject.GetComponentInParent<Scorpion>() ?? gameObject.GetComponentInChildren<Scorpion>());
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = (Component)(object)(gameObject.GetComponentInParent<BeeSwarm>() ?? gameObject.GetComponentInChildren<BeeSwarm>());
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = (Component)(object)(gameObject.GetComponentInParent<FrogTongue>() ?? gameObject.GetComponentInChildren<FrogTongue>());
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = (Component)(object)(gameObject.GetComponentInParent<GhostBall>() ?? gameObject.GetComponentInChildren<GhostBall>());
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			return (Component)(object)(gameObject.GetComponentInParent<Spider>() ?? gameObject.GetComponentInChildren<Spider>());
		}
	}
	public class InteractablePossessable : IPossessable
	{
		private readonly Component _component;

		public bool IsValid
		{
			get
			{
				if ((Object)(object)_component != (Object)null)
				{
					return (Object)(object)_component.gameObject != (Object)null;
				}
				return false;
			}
		}

		public GameObject GameObject
		{
			get
			{
				if (!((Object)(object)_component != (Object)null))
				{
					return null;
				}
				return _component.gameObject;
			}
		}

		public string DisplayName
		{
			get
			{
				if (!((Object)(object)_component != (Object)null))
				{
					return "Interactable";
				}
				return ((Object)_component).name;
			}
		}

		public InteractablePossessable(Component component)
		{
			_component = component;
		}

		public void Enter()
		{
			GhostPossessionPlugin.Instance?.LogState("Interactable possession placeholder");
		}

		public void Exit()
		{
			GhostPossessionPlugin.Instance?.LogState("Released interactable possession");
		}

		public void UpdateInput()
		{
		}
	}
	public interface IPossessable
	{
		bool IsValid { get; }

		GameObject GameObject { get; }

		string DisplayName { get; }

		void Enter();

		void Exit();

		void UpdateInput();
	}
	public class PossessionManager
	{
		private IPossessable _currentPossession;

		private readonly List<GameObject> _recentTargets = new List<GameObject>();

		private float _scanTimer;

		private const float ScanInterval = 2f;

		public bool IsPossessing
		{
			get
			{
				if (_currentPossession != null)
				{
					return _currentPossession.IsValid;
				}
				return false;
			}
		}

		public void DrawHud()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (IsPossessing)
			{
				string text = ((_currentPossession is CreaturePossessable creaturePossessable) ? creaturePossessable.ControlsText : "WASD — движение | Space — импульс | E — выйти");
				GUI.Box(new Rect(20f, 20f, 460f, 74f), "ВСЕЛЕНИЕ: " + _currentPossession.DisplayName + "\n" + text);
			}
		}

		public void ReapplyCreatureFacing()
		{
			(_currentPossession as CreaturePossessable)?.ReapplyFacing();
		}

		public bool TryGetCameraAnchor(out Vector3 position)
		{
			//IL_006b: 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_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_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)
			if (_currentPossession is CreaturePossessable { IsValid: not false } creaturePossessable)
			{
				position = creaturePossessable.CameraAnchorPosition;
				return true;
			}
			if (_currentPossession != null && _currentPossession.IsValid && (Object)(object)_currentPossession.GameObject != (Object)null)
			{
				position = _currentPossession.GameObject.transform.position;
				return true;
			}
			position = Vector3.zero;
			return false;
		}

		public void ApplyBeforeCharacterFixedUpdate(Character character)
		{
			(_currentPossession as CreaturePossessable)?.ApplyBeforeCharacterFixedUpdate(character);
		}

		public void Update()
		{
			if ((Object)(object)GhostPossessionPlugin.Instance == (Object)null)
			{
				return;
			}
			if (!GhostPossessionPlugin.Instance.IsGhostMode)
			{
				if (_currentPossession != null)
				{
					Release();
				}
				return;
			}
			if (_currentPossession != null && !_currentPossession.IsValid)
			{
				Release();
				return;
			}
			if (_currentPossession != null)
			{
				_currentPossession.UpdateInput();
				return;
			}
			_scanTimer -= Time.deltaTime;
			if (_scanTimer <= 0f)
			{
				_scanTimer = 2f;
				ScanNearbyTargets();
			}
		}

		public void TryPossessCurrentTarget()
		{
			GameObject nearestCandidate = GetNearestCandidate();
			if ((Object)(object)nearestCandidate == (Object)null)
			{
				GhostPossessionPlugin.Instance?.LogState("No possession target in range");
				return;
			}
			if (!IsLocalHost())
			{
				GhostPossessionPlugin.Instance?.LogState("Cannot possess network object: no authority");
				return;
			}
			Component val = CreatureSupport.FindCreature(nearestCandidate);
			if ((Object)(object)val != (Object)null)
			{
				_currentPossession = new CreaturePossessable(val);
				_currentPossession.Enter();
				GhostPossessionPlugin.Instance?.SetPossessionCameraTarget(_currentPossession.GameObject);
				GhostPossessionPlugin.Instance?.LogState("Possessing " + ((object)val).GetType().Name);
				return;
			}
			Rigidbody val2 = nearestCandidate.GetComponent<Rigidbody>() ?? nearestCandidate.GetComponentInChildren<Rigidbody>();
			if ((Object)(object)val2 != (Object)null)
			{
				_currentPossession = new RigidbodyPossessable(val2);
				_currentPossession.Enter();
				GhostPossessionPlugin.Instance?.SetPossessionCameraTarget(_currentPossession.GameObject);
				GhostPossessionPlugin.Instance?.LogState("Possessing");
			}
		}

		public void Release()
		{
			if (_currentPossession != null)
			{
				_currentPossession.Exit();
				_currentPossession = null;
				GhostPossessionPlugin.Instance?.SetPossessionCameraTarget(null);
				GhostPossessionPlugin.Instance?.LogState("Released");
			}
		}

		private void ScanNearbyTargets()
		{
			if ((Object)(object)Camera.main == (Object)null)
			{
				return;
			}
			List<GameObject> list = PossessionScanner.FindCandidates(ModConfig.PossessionScanRadius);
			_recentTargets.Clear();
			_recentTargets.AddRange(list);
			if (list.Count != 0)
			{
				GameObject nearestCandidate = GetNearestCandidate();
				if ((Object)(object)nearestCandidate != (Object)null && ModConfig.DebugPreventRunEnd)
				{
					GhostPossessionPlugin.Instance?.LogLocalTarget(((Object)nearestCandidate).name);
				}
			}
		}

		private GameObject GetNearestCandidate()
		{
			//IL_0040: 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)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return null;
			}
			GameObject result = null;
			float num = float.MaxValue;
			foreach (GameObject recentTarget in _recentTargets)
			{
				if (!((Object)(object)recentTarget == (Object)null))
				{
					float num2 = Vector3.Distance(((Component)main).transform.position, recentTarget.transform.position);
					if (num2 < num)
					{
						result = recentTarget;
						num = num2;
					}
				}
			}
			return result;
		}

		private bool IsLocalHost()
		{
			return NetworkHelper.IsLocalHost();
		}
	}
	public class PossessionScanner
	{
		private const int MaxColliders = 256;

		private static readonly Collider[] ColliderBuffer = (Collider[])(object)new Collider[256];

		public static List<GameObject> FindCandidates(float radius)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			List<GameObject> list = new List<GameObject>();
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return list;
			}
			HashSet<GameObject> hashSet = new HashSet<GameObject>();
			Character localCharacter = PlayerReflection.GetLocalCharacter();
			int num = Physics.OverlapSphereNonAlloc(((Component)main).transform.position, radius, ColliderBuffer);
			for (int i = 0; i < num; i++)
			{
				Collider val = ColliderBuffer[i];
				ColliderBuffer[i] = null;
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
				{
					continue;
				}
				GameObject gameObject = ((Component)val).gameObject;
				if ((Object)(object)gameObject == (Object)null || string.IsNullOrEmpty(((Object)gameObject).name) || ((Object)(object)localCharacter != (Object)null && ((Object)(object)gameObject == (Object)(object)((Component)localCharacter).gameObject || gameObject.transform.IsChildOf(((Component)localCharacter).transform))) || IsExcluded(gameObject))
				{
					continue;
				}
				Rigidbody val2 = gameObject.GetComponentInParent<Rigidbody>() ?? gameObject.GetComponentInChildren<Rigidbody>();
				GameObject val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : null);
				if ((Object)(object)val3 != (Object)null && (Object)(object)localCharacter != (Object)null && ((Object)(object)val3 == (Object)(object)((Component)localCharacter).gameObject || val3.transform.IsChildOf(((Component)localCharacter).transform)))
				{
					continue;
				}
				Component val4 = CreatureSupport.FindCreature(gameObject);
				if ((Object)(object)val4 != (Object)null)
				{
					if (hashSet.Add(val4.gameObject))
					{
						list.Add(val4.gameObject);
					}
				}
				else if ((Object)(object)val3 != (Object)null && hashSet.Add(val3))
				{
					list.Add(val3);
				}
			}
			return list;
		}

		public static bool IsExcluded(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return true;
			}
			if (((Object)go).name.Contains("Camera") || ((Object)go).name.Contains("UI") || (((Object)go).name.Contains("Ghost") && (Object)(object)CreatureSupport.FindCreature(go) == (Object)null))
			{
				return true;
			}
			string tag = go.tag;
			if (!string.Equals(tag, "Terrain", StringComparison.Ordinal))
			{
				string.Equals(tag, "Untagged", StringComparison.Ordinal);
			}
			return false;
		}
	}
	public class RigidbodyPossessable : IPossessable
	{
		private readonly Rigidbody _rigidbody;

		private readonly Transform _transform;

		private readonly Camera _camera;

		public bool IsValid
		{
			get
			{
				if ((Object)(object)_rigidbody != (Object)null)
				{
					return (Object)(object)((Component)_rigidbody).gameObject != (Object)null;
				}
				return false;
			}
		}

		public GameObject GameObject
		{
			get
			{
				if (!((Object)(object)_rigidbody != (Object)null))
				{
					return null;
				}
				return ((Component)_rigidbody).gameObject;
			}
		}

		public string DisplayName
		{
			get
			{
				if (!((Object)(object)_rigidbody != (Object)null))
				{
					return "Rigidbody";
				}
				return ((Object)_rigidbody).name;
			}
		}

		public RigidbodyPossessable(Rigidbody rigidbody)
		{
			_rigidbody = rigidbody;
			_transform = (((Object)(object)rigidbody != (Object)null) ? ((Component)rigidbody).transform : null);
			_camera = Camera.main;
		}

		public void Enter()
		{
			GhostPossessionPlugin.Instance?.LogState("Possessing Rigidbody");
		}

		public void Exit()
		{
			GhostPossessionPlugin.Instance?.LogState("Released Rigidbody possession");
		}

		public void UpdateInput()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_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_003c: 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_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)
			//IL_005c: 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_0072: 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_007c: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_00ac: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: 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)
			if (IsValid && !((Object)(object)_camera == (Object)null))
			{
				Vector3 val = Vector3.zero;
				if (Input.GetKey((KeyCode)119))
				{
					val += ((Component)_camera).transform.forward;
				}
				if (Input.GetKey((KeyCode)115))
				{
					val -= ((Component)_camera).transform.forward;
				}
				if (Input.GetKey((KeyCode)100))
				{
					val += ((Component)_camera).transform.right;
				}
				if (Input.GetKey((KeyCode)97))
				{
					val -= ((Component)_camera).transform.right;
				}
				if (Input.GetKey((KeyCode)32))
				{
					_rigidbody.AddForce(Vector3.up * ModConfig.PossessionJumpForce, (ForceMode)1);
				}
				if (((Vector3)(ref val)).sqrMagnitude > 0f)
				{
					((Vector3)(ref val)).Normalize();
					_rigidbody.AddForce(val * ModConfig.PossessionForce, (ForceMode)5);
				}
				if (Input.GetKey((KeyCode)304))
				{
					_rigidbody.AddForce(((Component)_camera).transform.forward * ModConfig.PossessionForce * 0.6f, (ForceMode)5);
				}
				if (Input.GetKey((KeyCode)113))
				{
					_rigidbody.AddTorque(Vector3.up * ModConfig.PossessionTorque, (ForceMode)5);
				}
				Input.GetKey((KeyCode)101);
			}
		}
	}
	public sealed class CreatureSpawnMenu
	{
		private struct SpawnEntry
		{
			public readonly string DisplayName;

			public readonly string PrefabName;

			public readonly Type ComponentType;

			public readonly bool IsTestScout;

			public SpawnEntry(string displayName, string prefabName, Type componentType, bool isTestScout = false)
			{
				DisplayName = displayName;
				PrefabName = prefabName;
				ComponentType = componentType;
				IsTestScout = isTestScout;
			}
		}

		private static readonly SpawnEntry[] Entries = new SpawnEntry[9]
		{
			new SpawnEntry("Scoutmaster", "Character_Scoutmaster", typeof(Scoutmaster)),
			new SpawnEntry("Beetle", "Beetle", typeof(Beetle)),
			new SpawnEntry("Scorpion", "Scorpion", typeof(Scorpion)),
			new SpawnEntry("Bee swarm", "BeeSwarm", typeof(BeeSwarm)),
			new SpawnEntry("Mushroom zombie", "MushroomZombie_Player", typeof(MushroomZombie)),
			new SpawnEntry("Spider", "Spider", typeof(Spider)),
			new SpawnEntry("Frog", "Frog", typeof(FrogTongue)),
			new SpawnEntry("Exploding ghost", "GhostBall", typeof(GhostBall)),
			new SpawnEntry("Test scout", null, typeof(Character), isTestScout: true)
		};

		private Rect _windowRect = new Rect(0f, 0f, 400f, 540f);

		private CursorLockMode _previousLockMode;

		private bool _previousCursorVisible;

		private int _selectedIndex;

		private bool _isPlacing;

		private SpawnEntry _placementEntry;

		private GameObject _placementMarker;

		private Vector3 _placementPosition;

		private Vector3 _placementNormal;

		private bool _placementValid;

		public bool IsOpen { get; private set; }

		public void Update()
		{
			if (_isPlacing)
			{
				UpdatePlacement();
				return;
			}
			if (Input.GetKeyDown((KeyCode)286))
			{
				SetOpen(!IsOpen);
			}
			if (Input.GetKeyDown((KeyCode)127))
			{
				DeleteNearestTestScout();
			}
			if (IsOpen && Input.GetKeyDown((KeyCode)27))
			{
				SetOpen(open: false);
			}
			if (!IsOpen)
			{
				return;
			}
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			if (Input.GetKeyDown((KeyCode)274) || Input.GetKeyDown((KeyCode)115))
			{
				_selectedIndex = (_selectedIndex + 1) % Entries.Length;
			}
			if (Input.GetKeyDown((KeyCode)273) || Input.GetKeyDown((KeyCode)119))
			{
				_selectedIndex = (_selectedIndex + Entries.Length - 1) % Entries.Length;
			}
			if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271))
			{
				BeginPlacement(Entries[_selectedIndex]);
			}
			for (int i = 0; i < Entries.Length; i++)
			{
				if (Input.GetKeyDown((KeyCode)(49 + i)) || Input.GetKeyDown((KeyCode)(257 + i)))
				{
					_selectedIndex = i;
					BeginPlacement(Entries[i]);
					break;
				}
			}
		}

		public void OnGUI()
		{
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//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_0061: 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)
			if (_isPlacing)
			{
				string text = (_placementValid ? (_placementEntry.DisplayName + "\nЛКМ — создать | ПКМ/Esc — отменить") : (_placementEntry.DisplayName + "\nНаведитесь на подходящую поверхность"));
				GUI.Box(new Rect((float)Screen.width * 0.5f - 190f, 80f, 380f, 58f), text);
				GUI.Label(new Rect((float)Screen.width * 0.5f - 10f, (float)Screen.height * 0.5f - 14f, 40f, 30f), _placementValid ? "+" : "X");
			}
			else if (IsOpen)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				((Rect)(ref _windowRect)).x = ((float)Screen.width - ((Rect)(ref _windowRect)).width) * 0.5f;
				((Rect)(ref _windowRect)).y = ((float)Screen.height - ((Rect)(ref _windowRect)).height) * 0.5f;
				_windowRect = GUI.Window(904206, _windowRect, new WindowFunction(DrawWindow), "GhostPossession — существа");
			}
		}

		private void DrawWindow(int id)
		{
			GUILayout.Label("Выберите существо, затем укажите место камерой.", Array.Empty<GUILayoutOption>());
			GUILayout.Label("Стрелки/W/S + Enter или клавиши 1–7", Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			for (int i = 0; i < Entries.Length; i++)
			{
				if (GUILayout.Button(((i == _selectedIndex) ? "> " : "  ") + (i + 1) + ". " + Entries[i].DisplayName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) }))
				{
					_selectedIndex = i;
					BeginPlacement(Entries[i]);
				}
			}
			GUILayout.Space(5f);
			if (GUILayout.Button("Удалить ближайшего Test scout", Array.Empty<GUILayoutOption>()))
			{
				DeleteNearestTestScout();
			}
			if (GUILayout.Button("Удалить всех Test scout", Array.Empty<GUILayoutOption>()))
			{
				DeleteAllTestScouts();
			}
			if (GUILayout.Button("Закрыть", Array.Empty<GUILayoutOption>()))
			{
				SetOpen(open: false);
			}
		}

		private void BeginPlacement(SpawnEntry entry)
		{
			_placementEntry = entry;
			_isPlacing = true;
			SetOpen(open: false);
			CreatePlacementMarker();
			GhostPossessionPlugin.Instance?.LogState("Placement mode: " + entry.DisplayName);
		}

		private void UpdatePlacement()
		{
			//IL_0008: 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_0029: 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)
			//IL_005f: 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_0093: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			RaycastHit val = default(RaycastHit);
			_placementValid = (Object)(object)main != (Object)null && Physics.Raycast(((Component)main).transform.position, ((Component)main).transform.forward, ref val, 100f, -1, (QueryTriggerInteraction)1);
			if (_placementValid)
			{
				_placementNormal = ((RaycastHit)(ref val)).normal;
				_placementPosition = ((RaycastHit)(ref val)).point + ((RaycastHit)(ref val)).normal * ((_placementEntry.ComponentType == typeof(Spider)) ? 0.15f : 1.2f);
				if ((Object)(object)_placementMarker != (Object)null)
				{
					_placementMarker.transform.position = _placementPosition;
					_placementMarker.SetActive(true);
				}
			}
			else if ((Object)(object)_placementMarker != (Object)null)
			{
				_placementMarker.SetActive(false);
			}
			if (Input.GetMouseButtonDown(1) || Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)286))
			{
				EndPlacement();
			}
			else if (_placementValid && Input.GetMouseButtonDown(0))
			{
				Spawn(_placementEntry, _placementPosition, _placementNormal);
				EndPlacement();
			}
		}

		private void Spawn(SpawnEntry entry, Vector3 position, Vector3 normal)
		{
			//IL_003d: 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)
			//IL_0051: 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_01a0: 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)
			//IL_00d8: 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_005d: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkHelper.IsLocalHost())
			{
				GhostPossessionPlugin.Instance?.LogState("Creature spawning requires host authority");
				return;
			}
			Camera main = Camera.main;
			Quaternion val = Quaternion.Euler(0f, ((Object)(object)main != (Object)null) ? ((Component)main).transform.eulerAngles.y : 0f, 0f);
			try
			{
				GameObject val2 = null;
				if (entry.IsTestScout)
				{
					val2 = TrySpawnTestScout(position, val);
				}
				else
				{
					try
					{
						val2 = PhotonNetwork.InstantiateRoomObject(entry.PrefabName, position, val, (byte)0, (object[])null);
					}
					catch
					{
					}
					if ((Object)(object)val2 == (Object)null && (entry.ComponentType == typeof(Beetle) || entry.ComponentType == typeof(Scorpion) || entry.ComponentType == typeof(FrogTongue)))
					{
						try
						{
							val2 = PhotonNetwork.InstantiateItemRoom(entry.PrefabName, position, val);
						}
						catch (Exception ex)
						{
							Debug.LogError((object)("[GhostPossession] Network mob spawn failed for " + entry.DisplayName + ": " + ex));
						}
					}
				}
				if (!entry.IsTestScout && ((Object)(object)val2 == (Object)null || (Object)(object)val2.GetComponentInChildren(entry.ComponentType) == (Object)null))
				{
					if ((Object)(object)val2 != (Object)null)
					{
						PhotonView component = val2.GetComponent<PhotonView>();
						if (PhotonNetwork.InRoom && (Object)(object)component != (Object)null && component.IsMine)
						{
							PhotonNetwork.Destroy(val2);
						}
						else
						{
							Object.Destroy((Object)(object)val2);
						}
					}
					if (!PhotonNetwork.InRoom)
					{
						val2 = TrySpawnLoadedCreature(entry, position, val);
					}
				}
				if ((Object)(object)val2 == (Object)null)
				{
					throw new InvalidOperationException("No network prefab for " + entry.DisplayName + "; local-only spawn was blocked");
				}
				PrepareSpawnedCreature(val2, entry, position, normal);
				GhostPossessionPlugin.Instance?.LogState("Spawned " + entry.DisplayName + " at selected position");
			}
			catch (Exception ex2)
			{
				Debug.LogError((object)("[GhostPossession] Creature spawn failed: " + ex2));
			}
		}

		private static GameObject TrySpawnTestScout(Vector3 position, Quaternion rotation)
		{
			//IL_0017: 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)
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)localCharacter).gameObject, position, rotation);
			Character.localCharacter = localCharacter;
			((Object)val).name = "Test Scout (GhostPossession)";
			val.AddComponent<SpawnedTestScoutMarker>();
			val.SetActive(true);
			Character val2 = val.GetComponent<Character>() ?? val.GetComponentInChildren<Character>();
			if ((Object)(object)val2 !=