Decompiled source of I am a BigGhost v0.0.1

plugins/Thanks.I_am_a_BigGhost.dll

Decompiled 7 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
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: AssemblyTitle("Thanks.I_am_a_BigGhost")]
[assembly: AssemblyDescription("Client-side controllable big-ghost form for PEAK. Press B in the Airport lobby to become the big ghost that rises from the misty swamp.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Thanks")]
[assembly: AssemblyProduct("I'm a Ghost")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3a7b9c51-4d2e-4f6a-8b10-2c3d4e5f6a7b")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.1.0.0")]
[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 ImGhost
{
	[BepInPlugin("com.github.Thanks.ImGhost", "I'm a Ghost", "0.1.0")]
	public sealed class GhostPlugin : BaseUnityPlugin
	{
		public const string Id = "com.github.Thanks.ImGhost";

		public const string Name = "I'm a Ghost";

		public const string Version = "0.1.0";

		public const string LobbySceneName = "Airport";

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyCode> ToggleKey;

		internal static ConfigEntry<KeyCode> AttackKey;

		internal static ConfigEntry<KeyCode> UpKey;

		internal static ConfigEntry<KeyCode> DownKey;

		internal static ConfigEntry<KeyCode> SprintKey;

		internal static ConfigEntry<float> MovementSpeed;

		internal static ConfigEntry<float> VerticalSpeed;

		internal static ConfigEntry<float> SprintMultiplier;

		internal static ConfigEntry<float> AttackChargeSeconds;

		internal static ConfigEntry<float> AttackRevertSeconds;

		internal static ConfigEntry<float> AttackRadius;

		internal static ConfigEntry<float> KnockbackForce;

		internal static ConfigEntry<float> CameraDistance;

		internal static ConfigEntry<float> CameraHeight;

		internal static ConfigEntry<float> CameraFov;

		internal static ConfigEntry<bool> ShowGhostVisual;

		private readonly Harmony _harmony = new Harmony("com.github.Thanks.ImGhost");

		private GhostController _controller;

		private bool _switching;

		private bool _lastTogglePressed;

		internal static bool IsInLobby()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				return ((Scene)(ref activeScene)).name == "Airport";
			}
			catch
			{
				return false;
			}
		}

		private void Awake()
		{
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Expected O, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Expected O, but got Unknown
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Expected O, but got Unknown
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Expected O, but got Unknown
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Expected O, but got Unknown
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Expected O, but got Unknown
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Expected O, but got Unknown
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony.PatchAll(typeof(GhostHarmonyPatches).Assembly);
			ConfigureOptionalCharacterPatches();
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ToggleKey", (KeyCode)98, "Press to become the big ghost (only in the Airport lobby). Press again to return to normal.");
			AttackKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "AttackKey", (KeyCode)324, "Right-click while in ghost form to trigger the ghost explosion attack. The player reverts after the attack.");
			UpKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "UpKey", (KeyCode)32, "Hold Space to fly up while in ghost form.");
			DownKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "DownKey", (KeyCode)306, "Hold Ctrl to fly down while in ghost form.");
			SprintKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "SprintKey", (KeyCode)304, "Hold Shift to sprint (move faster) while in ghost form.");
			MovementSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Ghost", "MovementSpeed", 14f, new ConfigDescription("How fast the ghost glides with WASD.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), Array.Empty<object>()));
			VerticalSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Ghost", "VerticalSpeed", 12f, new ConfigDescription("How fast the ghost rises and sinks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			SprintMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Ghost", "SprintMultiplier", 2f, new ConfigDescription("Speed multiplier while holding the sprint key.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
			AttackChargeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Ghost", "AttackChargeSeconds", 0.8f, new ConfigDescription("How long the ghost glows before exploding after the attack is triggered.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
			AttackRevertSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Ghost", "AttackRevertSeconds", 1f, new ConfigDescription("Seconds after the explosion until the player automatically reverts to normal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 6f), Array.Empty<object>()));
			AttackRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Ghost", "AttackRadius", 10f, new ConfigDescription("Radius in which nearby players are knocked down by the ghost explosion.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), Array.Empty<object>()));
			KnockbackForce = ((BaseUnityPlugin)this).Config.Bind<float>("Ghost", "KnockbackForce", 15f, new ConfigDescription("How strongly nearby players are launched by the ghost explosion.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), Array.Empty<object>()));
			CameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Distance", 16f, new ConfigDescription("Third-person ghost camera distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 30f), Array.Empty<object>()));
			CameraHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Height", 5f, new ConfigDescription("Third-person ghost camera height above the player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 14f), Array.Empty<object>()));
			CameraFov = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Fov", 80f, new ConfigDescription("Field of view while in ghost form.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(60f, 110f), Array.Empty<object>()));
			ShowGhostVisual = ((BaseUnityPlugin)this).Config.Bind<bool>("Ghost", "ShowGhostVisual", true, "Show the big ghost visual while transformed.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[I'm a Ghost] Loaded version 0.1.0.");
		}

		private void ConfigureOptionalCharacterPatches()
		{
			TryPatchOptionalCharacterMethod("RPCA_Die", Type.EmptyTypes, "CharacterRpcDiePrefix", "Character.RPCA_Die()");
			TryPatchOptionalCharacterMethod("RPCA_SetDead", Type.EmptyTypes, "CharacterRpcSetDeadPrefix", "Character.RPCA_SetDead()");
			TryPatchOptionalCharacterMethod("RPCA_PassOut", Type.EmptyTypes, "CharacterRpcPassOutPrefix", "Character.RPCA_PassOut()");
			TryPatchOptionalCharacterMethod("DieInstantly", Type.EmptyTypes, "CharacterDieInstantlyPrefix", "Character.DieInstantly()");
			TryPatchOptionalCharacterMethod("HandleDeath", Type.EmptyTypes, "CharacterHandleDeathPrefix", "Character.HandleDeath()");
			TryPatchOptionalCharacterMethod("WarpPlayerRPC", new Type[2]
			{
				typeof(Vector3),
				typeof(bool)
			}, "CharacterWarpPlayerRpcPrefix", "Character.WarpPlayerRPC(Vector3,bool)");
			TryPatchOptionalCharacterMethod("WarpPlayer", new Type[2]
			{
				typeof(Vector3),
				typeof(bool)
			}, "CharacterWarpPlayerPrefix", "Character.WarpPlayer(Vector3,bool)");
			TryPatchOptionalCharacterMethod("Fall", new Type[2]
			{
				typeof(float),
				typeof(float)
			}, "CharacterFallPrefix", "Character.Fall(float,float)");
			TryPatchOptionalCharacterMethod("RPCA_Fall", new Type[2]
			{
				typeof(float),
				typeof(float)
			}, "CharacterRpcFallPrefix", "Character.RPCA_Fall(float,float)");
		}

		private void TryPatchOptionalCharacterMethod(string methodName, Type[] parameterTypes, string prefixName, string description)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Character), methodName, parameterTypes, (Type[])null);
				if (methodInfo == null)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[I'm a Ghost] Optional " + description + " patch skipped; method is not present in this game build."));
					return;
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeof(GhostHarmonyPatches), prefixName, (Type[])null, (Type[])null);
				if (methodInfo2 == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("[I'm a Ghost] Optional " + description + " patch skipped; prefix method was not found."));
				}
				else
				{
					_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[I'm a Ghost] Optional " + description + " patch failed: " + ex.Message));
			}
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((int)ToggleKey.Value != 0)
				{
					bool key = Input.GetKey(ToggleKey.Value);
					if (key && !_lastTogglePressed)
					{
						ToggleGhostForm();
					}
					_lastTogglePressed = key;
					if ((Object)(object)_controller != (Object)null && _controller.Active && !_controller.IsValid())
					{
						ForceExit();
					}
					if ((Object)(object)_controller != (Object)null && _controller.Active && !IsInLobby())
					{
						ForceExit();
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("[I'm a Ghost] Plugin.Update: " + ex));
				}
			}
		}

		private void OnDestroy()
		{
			try
			{
				ForceExit();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[I'm a Ghost] Exit during cleanup failed: " + ex.Message));
				}
			}
			try
			{
				_harmony.UnpatchSelf();
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[I'm a Ghost] Harmony unpatch failed (non-fatal): " + ex2.Message));
				}
			}
		}

		private void ToggleGhostForm()
		{
			if (_switching)
			{
				return;
			}
			if ((Object)(object)_controller != (Object)null && _controller.Active)
			{
				ExitGhost();
				return;
			}
			Character localCharacter = Character.localCharacter;
			if (CanTransform(localCharacter))
			{
				_switching = true;
				((MonoBehaviour)this).StartCoroutine(EnterGhostRoutine(localCharacter));
			}
		}

		private static bool CanTransform(Character character)
		{
			if (!IsInLobby())
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)"[I'm a Ghost] Ghost form is only available in the Airport lobby.");
				}
				return false;
			}
			if ((Object)(object)character == (Object)null)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[I'm a Ghost] No local character found.");
				}
				return false;
			}
			if (GhostController.IsLocalGhostCharacter(character))
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogWarning((object)"[I'm a Ghost] Already in ghost form.");
				}
				return false;
			}
			if (character.isZombie || character.isBot || character.isScoutmaster)
			{
				ManualLogSource log4 = Log;
				if (log4 != null)
				{
					log4.LogWarning((object)"[I'm a Ghost] Cannot transform while in another special form.");
				}
				return false;
			}
			if ((Object)(object)character.data == (Object)null || character.refs == null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null)
			{
				ManualLogSource log5 = Log;
				if (log5 != null)
				{
					log5.LogWarning((object)"[I'm a Ghost] Local character is not ready yet.");
				}
				return false;
			}
			if (character.data.dead || character.data.passedOut || character.data.fullyPassedOut || character.data.fallSeconds > 0f || character.data.isClimbing || character.data.isRopeClimbing || character.data.isVineClimbing)
			{
				ManualLogSource log6 = Log;
				if (log6 != null)
				{
					log6.LogWarning((object)"[I'm a Ghost] Local character is not in a valid state to transform.");
				}
				return false;
			}
			return true;
		}

		private IEnumerator EnterGhostRoutine(Character character)
		{
			try
			{
				_controller = ((Component)character).gameObject.GetComponent<GhostController>();
				if ((Object)(object)_controller == (Object)null)
				{
					_controller = ((Component)character).gameObject.AddComponent<GhostController>();
				}
				_controller.EnterGhost(character);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("[I'm a Ghost] Failed to enter ghost form:\n" + ex));
				}
				_controller = null;
			}
			finally
			{
				_switching = false;
			}
			yield break;
		}

		private void ExitGhost()
		{
			_switching = true;
			try
			{
				_controller?.ExitGhost();
				_controller = null;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("[I'm a Ghost] Failed to exit ghost form:\n" + ex));
				}
			}
			finally
			{
				_switching = false;
			}
		}

		private void ForceExit()
		{
			if ((Object)(object)_controller == (Object)null)
			{
				return;
			}
			try
			{
				_controller.ExitGhost();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[I'm a Ghost] ForceExit failed: " + ex.Message));
				}
			}
			_controller = null;
		}
	}
	[DefaultExecutionOrder(600)]
	public sealed class GhostController : MonoBehaviour
	{
		private const float VelocitySharpness = 7f;

		private const float MaxVelocity = 55f;

		private const float AngularVelocityDamping = 0.92f;

		private const float MaxAngularVelocity = 10f;

		private const float GroundClearanceMin = 0.8f;

		private const float BallFaceMoveSharpness = 6f;

		private const float CameraLookAhead = 4f;

		private const float CameraCollisionRadius = 0.35f;

		private const float CameraTerrainClearance = 0.8f;

		private const float CameraSmoothTime = 0.08f;

		private const float CameraRotationSharpness = 12f;

		private const float DefaultCameraDistance = 16f;

		private const float DefaultCameraHeight = 5f;

		private const float DefaultCameraFov = 80f;

		private Character _character;

		private Vector3 _prevCenter;

		private Vector3 _cameraVelocity;

		private Vector3 _cameraSmoothedPosition;

		private Quaternion _cameraSmoothedRotation;

		private bool _cameraHasSmoothedPosition;

		private Vector3 _moveDirection;

		private GameObject _ghostVisualRoot;

		private GhostBall _ghostBall;

		private PhotonView _ghostPhotonView;

		private Rigidbody _ghostRigidbody;

		private Animator _ghostAnimator;

		private bool _ghostIsNetworked;

		private bool _attacking;

		private float _attackStartedAt;

		private bool _attackExploded;

		internal const string NetworkVisualMarker = "ImGhost.Visual";

		private static readonly FieldInfo ReadyToExplodeField = typeof(GhostBall).GetField("_readyToExplode", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo ExplodingField = typeof(GhostBall).GetField("exploding", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo TickUntilDespawnField = typeof(GhostBall).GetField("tickUntilDespawn", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly int AnReadyToExplode = Animator.StringToHash("ReadyToExplode");

		private static readonly int AnFadeOut = Animator.StringToHash("FadeOut");

		private static readonly int AnExploded = Animator.StringToHash("Exploded");

		private readonly Dictionary<GameObject, bool> _hiddenHudStates = new Dictionary<GameObject, bool>();

		public static GhostBall ActiveGhostBall { get; private set; }

		public static Character ActiveGhostCharacter { get; private set; }

		public bool Active { get; private set; }

		public Character CharacterRef => _character;

		public bool IsValid()
		{
			if (!Active || (Object)(object)_character == (Object)null || (Object)(object)_character.data == (Object)null)
			{
				return false;
			}
			if (!_character.data.dead)
			{
				return !_character.data.fullyPassedOut;
			}
			return false;
		}

		private static void LogInfo(string message)
		{
			ManualLogSource log = GhostPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("[I'm a Ghost] " + message));
			}
		}

		private static void LogError(string entryPoint, Exception ex)
		{
			ManualLogSource log = GhostPlugin.Log;
			if (log != null)
			{
				log.LogError((object)("[I'm a Ghost] " + entryPoint + ": " + ex));
			}
		}

		public static bool IsLocalGhostCharacter(Character character)
		{
			if ((Object)(object)character == (Object)null || !character.IsLocal)
			{
				return false;
			}
			GhostController component = ((Component)character).GetComponent<GhostController>();
			if ((Object)(object)component != (Object)null)
			{
				return component.Active;
			}
			return false;
		}

		public void EnterGhost(Character character)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			_character = character;
			_prevCenter = character.Center;
			_cameraVelocity = Vector3.zero;
			_cameraHasSmoothedPosition = false;
			_attacking = false;
			_attackExploded = false;
			_attackStartedAt = 0f;
			Active = true;
			ActiveGhostCharacter = character;
			((Behaviour)this).enabled = true;
			BuildGhostVisual();
			HideHud();
			LogInfo("Entered ghost form.");
		}

		public void ExitGhost()
		{
			if (Active || !((Object)(object)_ghostVisualRoot == (Object)null))
			{
				Active = false;
				ActiveGhostCharacter = null;
				((Behaviour)this).enabled = false;
				_attacking = false;
				_attackExploded = false;
				_attackStartedAt = 0f;
				DestroyGhostVisual();
				RestoreHud();
				LogInfo("Exited ghost form.");
			}
		}

		private void Update()
		{
			if (!Active || (Object)(object)_character == (Object)null)
			{
				return;
			}
			try
			{
				ClearNonMovementInput();
				KeepPlayerAlive();
				UpdateAttack();
				if (Active)
				{
					UpdateGhostVisual();
					HideHud();
				}
			}
			catch (Exception ex)
			{
				LogError("GhostController.Update", ex);
			}
		}

		private void FixedUpdate()
		{
			if (!Active || (Object)(object)_character == (Object)null || _character.refs == null || (Object)(object)_character.refs.ragdoll == (Object)null)
			{
				return;
			}
			try
			{
				ApplyMovementVelocity();
				StabilizeRagdoll();
			}
			catch (Exception ex)
			{
				LogError("GhostController.FixedUpdate", ex);
			}
		}

		private void LateUpdate()
		{
			if (!Active || (Object)(object)_character == (Object)null)
			{
				return;
			}
			try
			{
				SyncCharacterData();
				RefreshCamera();
			}
			catch (Exception ex)
			{
				LogError("GhostController.LateUpdate", ex);
			}
		}

		private void OnDestroy()
		{
			if (Active)
			{
				Active = false;
				ActiveGhostCharacter = null;
				DestroyGhostVisual();
				RestoreHud();
			}
		}

		private void HideHud()
		{
			if (_hiddenHudStates.Count < 2)
			{
				TryHideCanvas("Canvas_HUD");
				TryHideCanvas("Canvas_Names");
			}
		}

		private void TryHideCanvas(string canvasName)
		{
			GameObject val = GameObject.Find(canvasName);
			if (!((Object)(object)val == (Object)null) && !_hiddenHudStates.ContainsKey(val))
			{
				_hiddenHudStates[val] = val.activeSelf;
				if (val.activeSelf)
				{
					val.SetActive(false);
				}
			}
		}

		private void RestoreHud()
		{
			if (_hiddenHudStates.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<GameObject, bool> hiddenHudState in _hiddenHudStates)
			{
				if ((Object)(object)hiddenHudState.Key != (Object)null)
				{
					hiddenHudState.Key.SetActive(hiddenHudState.Value);
				}
			}
			_hiddenHudStates.Clear();
		}

		private void ClearNonMovementInput()
		{
			if (!((Object)(object)_character == (Object)null) && !((Object)(object)_character.input == (Object)null))
			{
				_character.input.jumpWasPressed = false;
				_character.input.jumpIsPressed = false;
				_character.input.sprintIsPressed = false;
				_character.input.sprintWasPressed = false;
				_character.input.sprintToggleWasPressed = false;
				_character.input.usePrimaryWasPressed = false;
				_character.input.usePrimaryIsPressed = false;
				_character.input.useSecondaryWasPressed = false;
				_character.input.useSecondaryIsPressed = false;
				_character.input.crouchWasPressed = false;
				_character.input.crouchIsPressed = false;
				_character.input.crouchToggleWasPressed = false;
				_character.input.dropWasPressed = false;
				_character.input.dropIsPressed = false;
				_character.input.interactWasPressed = false;
				_character.input.interactIsPressed = false;
			}
		}

		private void KeepPlayerAlive()
		{
			if (!((Object)(object)_character == (Object)null) && !((Object)(object)_character.data == (Object)null))
			{
				_character.data.dead = false;
				_character.data.zombified = false;
				_character.data.passedOut = false;
				_character.data.fullyPassedOut = false;
				_character.data.fallSeconds = 0f;
				_character.data.isSprinting = false;
			}
		}

		private Vector2 GetMovementInput()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			if ((Object)(object)_character == (Object)null || (Object)(object)_character.input == (Object)null)
			{
				return Vector2.zero;
			}
			Vector2 movementInput = _character.input.movementInput;
			movementInput.x = Mathf.Clamp(movementInput.x, -1f, 1f);
			movementInput.y = Mathf.Clamp(movementInput.y, -1f, 1f);
			return movementInput;
		}

		private void ApplyMovementVelocity()
		{
			//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)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: 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_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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_013b: 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_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_01ad: 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_0076: 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_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: 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_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			if (_attacking)
			{
				_moveDirection = Vector3.zero;
				Vector3 zero = Vector3.zero;
				{
					foreach (Bodypart part in _character.refs.ragdoll.partList)
					{
						Rigidbody val = (((Object)(object)part != (Object)null) ? part.Rig : null);
						if (!((Object)(object)val == (Object)null) && !val.isKinematic)
						{
							val.linearVelocity = Vector3.Lerp(val.linearVelocity, zero, Time.fixedDeltaTime * 7f);
						}
					}
					return;
				}
			}
			Vector3 val2 = (((Object)(object)_character.data != (Object)null) ? _character.data.lookDirection_Flat : Vector3.zero);
			if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f)
			{
				val2 = Vector3.ProjectOnPlane(((Component)this).transform.forward, Vector3.up);
			}
			Vector3 val3 = Vector3.ProjectOnPlane(val2, Vector3.up);
			val2 = ((Vector3)(ref val3)).normalized;
			if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f)
			{
				val2 = Vector3.forward;
			}
			Vector2 movementInput = GetMovementInput();
			val3 = Vector3.Cross(Vector3.up, val2);
			Vector3 normalized = ((Vector3)(ref val3)).normalized;
			Vector3 val4 = val2 * movementInput.y + normalized * movementInput.x;
			if (((Vector3)(ref val4)).sqrMagnitude > 1f)
			{
				((Vector3)(ref val4)).Normalize();
			}
			float num = 0f;
			if ((int)GhostPlugin.UpKey.Value != 0 && Input.GetKey(GhostPlugin.UpKey.Value))
			{
				num += 1f;
			}
			if ((int)GhostPlugin.DownKey.Value != 0 && Input.GetKey(GhostPlugin.DownKey.Value))
			{
				num -= 1f;
			}
			float num2 = 1f;
			if ((int)GhostPlugin.SprintKey.Value != 0 && Input.GetKey(GhostPlugin.SprintKey.Value))
			{
				num2 = Mathf.Max(1f, GhostPlugin.SprintMultiplier.Value);
			}
			Vector3 val5 = (val4 * GhostPlugin.MovementSpeed.Value + Vector3.up * (num * GhostPlugin.VerticalSpeed.Value)) * num2;
			if (num < 0f)
			{
				float groundHeight = GetGroundHeight(_character.Center);
				if (!float.IsNaN(groundHeight) && _character.Center.y <= groundHeight + 0.8f)
				{
					val5.y = Mathf.Max(val5.y, 0f);
				}
			}
			_moveDirection = ((((Vector3)(ref val4)).sqrMagnitude > 0.0001f) ? val4 : Vector3.zero);
			foreach (Bodypart part2 in _character.refs.ragdoll.partList)
			{
				Rigidbody val6 = (((Object)(object)part2 != (Object)null) ? part2.Rig : null);
				if (!((Object)(object)val6 == (Object)null) && !val6.isKinematic)
				{
					Vector3 val7 = Vector3.Lerp(val6.linearVelocity, val5, Time.fixedDeltaTime * 7f);
					val6.linearVelocity = Vector3.ClampMagnitude(val7, 55f);
				}
			}
		}

		private float GetGroundHeight(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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)
			try
			{
				RaycastHit groundPosRaycast = HelperFunctions.GetGroundPosRaycast(position + Vector3.up * 400f, (LayerType)2, 0f);
				if ((Object)(object)((RaycastHit)(ref groundPosRaycast)).transform != (Object)null)
				{
					return ((RaycastHit)(ref groundPosRaycast)).point.y;
				}
			}
			catch
			{
			}
			try
			{
				RaycastHit groundPosRaycast2 = HelperFunctions.GetGroundPosRaycast(position + Vector3.up * 400f, (LayerType)1, 0f);
				if ((Object)(object)((RaycastHit)(ref groundPosRaycast2)).transform != (Object)null)
				{
					return ((RaycastHit)(ref groundPosRaycast2)).point.y;
				}
			}
			catch
			{
			}
			return float.NaN;
		}

		private void StabilizeRagdoll()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: 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)_character.refs.ragdoll == (Object)null)
			{
				return;
			}
			foreach (Bodypart part in _character.refs.ragdoll.partList)
			{
				Rigidbody val = (((Object)(object)part != (Object)null) ? part.Rig : null);
				if (!((Object)(object)val == (Object)null) && !val.isKinematic)
				{
					val.useGravity = false;
					part.forcesToAdd = Vector3.zero;
					val.angularVelocity *= 0.92f;
					Vector3 angularVelocity = val.angularVelocity;
					if (((Vector3)(ref angularVelocity)).magnitude > 10f)
					{
						val.angularVelocity = Vector3.ClampMagnitude(val.angularVelocity, 10f);
					}
					if (val.linearVelocity.y < -55f)
					{
						Vector3 linearVelocity = val.linearVelocity;
						linearVelocity.y = -55f;
						val.linearVelocity = linearVelocity;
					}
				}
			}
		}

		private void SyncCharacterData()
		{
			//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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0040: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00bb: 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_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_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_character == (Object)null) && !((Object)(object)_character.data == (Object)null))
			{
				Vector3 center = _character.Center;
				Vector3 avarageVelocity = ((((Vector3)(ref _prevCenter)).sqrMagnitude > 0f) ? ((center - _prevCenter) / Mathf.Max(Time.deltaTime, 0.0001f)) : Vector3.zero);
				_prevCenter = center;
				_character.data.avarageLastFrameVelocity = _character.data.avarageVelocity;
				_character.data.avarageVelocity = avarageVelocity;
				_character.data.worldMovementInput = (_character.data.worldMovementInput_Grounded = Vector3.zero);
				_character.data.sinceGrounded = Mathf.Min(_character.data.sinceGrounded, 0.1f);
			}
		}

		private void UpdateAttack()
		{
			//IL_000d: 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)
			if (!_attacking)
			{
				if ((int)GhostPlugin.AttackKey.Value != 0 && Input.GetKeyDown(GhostPlugin.AttackKey.Value))
				{
					StartAttack();
				}
				return;
			}
			float num = Time.unscaledTime - _attackStartedAt;
			if (!_attackExploded && num >= GhostPlugin.AttackChargeSeconds.Value)
			{
				_attackExploded = true;
				DoExplode();
			}
			if (num >= GhostPlugin.AttackChargeSeconds.Value + GhostPlugin.AttackRevertSeconds.Value)
			{
				ExitGhost();
			}
		}

		private void StartAttack()
		{
			_attacking = true;
			_attackExploded = false;
			_attackStartedAt = Time.unscaledTime;
			SetGhostValue(ReadyToExplodeField, true);
			if ((Object)(object)_ghostAnimator != (Object)null)
			{
				_ghostAnimator.SetBool(AnReadyToExplode, true);
			}
			LogInfo("Ghost attack charging...");
		}

		private void DoExplode()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			LogInfo("Ghost attack exploded!");
			if ((Object)(object)_ghostBall != (Object)null && (Object)(object)_ghostBall.explosionPrefab != (Object)null)
			{
				try
				{
					Object.Instantiate<GameObject>(_ghostBall.explosionPrefab, _character.Center, Quaternion.identity);
				}
				catch (Exception ex)
				{
					LogError("GhostController.DoExplode (explosion prefab)", ex);
				}
			}
			SetGhostValue(ExplodingField, true);
			if ((Object)(object)_ghostAnimator != (Object)null)
			{
				_ghostAnimator.SetBool(AnExploded, true);
			}
			KnockDownNearbyPlayers();
		}

		private void KnockDownNearbyPlayers()
		{
			//IL_001c: 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_00a2: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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_00d6: 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_00e7: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			float value = GhostPlugin.AttackRadius.Value;
			float value2 = GhostPlugin.KnockbackForce.Value;
			Vector3 center = _character.Center;
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if ((Object)(object)allCharacter == (Object)null || (Object)(object)allCharacter == (Object)(object)_character || (Object)(object)allCharacter.data == (Object)null || !allCharacter.data.fullyConscious || allCharacter.refs == null || (Object)(object)allCharacter.refs.view == (Object)null)
				{
					continue;
				}
				Vector3 val = allCharacter.Center - center;
				float magnitude = ((Vector3)(ref val)).magnitude;
				if (!(magnitude > value) && !(magnitude < 0.001f))
				{
					Vector3 val2 = val / magnitude * value2 + Vector3.up * (value2 * 0.55f);
					try
					{
						allCharacter.refs.view.RPC("RPCA_AddForceAtPosition", (RpcTarget)0, new object[3] { val2, center, value });
					}
					catch (Exception ex)
					{
						LogError("GhostController.KnockDownNearbyPlayers (force)", ex);
					}
					try
					{
						allCharacter.refs.view.RPC("RPCA_Fall", (RpcTarget)0, new object[2] { 1.2f, 0.25f });
					}
					catch (Exception ex2)
					{
						LogError("GhostController.KnockDownNearbyPlayers (fall)", ex2);
					}
				}
			}
		}

		private static void SetGhostValue(FieldInfo field, object value)
		{
			try
			{
				if (field != null && (Object)(object)ActiveGhostBall != (Object)null)
				{
					field.SetValue(ActiveGhostBall, value);
				}
			}
			catch
			{
			}
		}

		private void BuildGhostVisual()
		{
			if ((Object)(object)_ghostVisualRoot != (Object)null || (Object)(object)_character == (Object)null)
			{
				return;
			}
			try
			{
				GameObject val = Resources.Load<GameObject>("GhostBall");
				if ((Object)(object)val == (Object)null)
				{
					LogInfo("Resources.Load(\"GhostBall\") returned null; no ghost visual will be shown.");
				}
				else if (PhotonNetwork.InRoom && (Object)(object)((MonoBehaviourPun)_character).photonView != (Object)null && ((MonoBehaviourPun)_character).photonView.ViewID > 0)
				{
					BuildNetworkedGhost(val);
				}
				else
				{
					BuildLocalGhost(val);
				}
			}
			catch (Exception ex)
			{
				LogError("GhostController.BuildGhostVisual", ex);
				DestroyGhostVisual();
			}
		}

		private void BuildNetworkedGhost(GameObject prefab)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = PhotonNetwork.Instantiate("GhostBall", _character.Center, Quaternion.identity, (byte)0, new object[2]
			{
				"ImGhost.Visual",
				((MonoBehaviourPun)_character).photonView.ViewID
			});
			((Object)val).name = "ImGhostNetworked";
			_ghostVisualRoot = val;
			_ghostIsNetworked = true;
			_ghostBall = val.GetComponent<GhostBall>();
			ActiveGhostBall = _ghostBall;
			_ghostPhotonView = val.GetComponent<PhotonView>();
			_ghostRigidbody = val.GetComponent<Rigidbody>();
			_ghostAnimator = val.GetComponent<Animator>();
			if ((Object)(object)_ghostRigidbody != (Object)null)
			{
				_ghostRigidbody.isKinematic = true;
			}
			KeepGhostAliveIndefinitely();
			val.SetActive(GhostPlugin.ShowGhostVisual.Value);
			LogInfo("Spawned networked ghost visual with vanilla GhostBall prefab.");
		}

		private void BuildLocalGhost(GameObject prefab)
		{
			//IL_0007: 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)
			GameObject val = Object.Instantiate<GameObject>(prefab, _character.Center, Quaternion.identity);
			((Object)val).name = "ImGhostLocal";
			_ghostVisualRoot = val;
			_ghostIsNetworked = false;
			_ghostBall = val.GetComponent<GhostBall>();
			ActiveGhostBall = _ghostBall;
			_ghostRigidbody = val.GetComponent<Rigidbody>();
			_ghostAnimator = val.GetComponent<Animator>();
			if ((Object)(object)_ghostBall != (Object)null)
			{
				((Behaviour)_ghostBall).enabled = false;
			}
			if ((Object)(object)_ghostRigidbody != (Object)null)
			{
				_ghostRigidbody.isKinematic = true;
			}
			IgnoreCollisionWithOwnRagdoll(val);
			KeepGhostAliveIndefinitely();
			val.SetActive(GhostPlugin.ShowGhostVisual.Value);
			LogInfo("Spawned local-only ghost visual (offline / single-player).");
		}

		private void KeepGhostAliveIndefinitely()
		{
			SetGhostValue(TickUntilDespawnField, -1000f);
			if ((Object)(object)_ghostBall != (Object)null)
			{
				_ghostBall.lifetime = 9999f;
			}
		}

		private static void IgnoreCollisionWithOwnRagdoll(GameObject ghostRoot)
		{
			Character activeGhostCharacter = ActiveGhostCharacter;
			if ((Object)(object)activeGhostCharacter == (Object)null || activeGhostCharacter.refs == null || (Object)(object)activeGhostCharacter.refs.ragdoll == (Object)null)
			{
				return;
			}
			Collider[] componentsInChildren = ghostRoot.GetComponentsInChildren<Collider>(true);
			if (componentsInChildren.Length == 0)
			{
				return;
			}
			foreach (Bodypart part in activeGhostCharacter.refs.ragdoll.partList)
			{
				if ((Object)(object)part == (Object)null)
				{
					continue;
				}
				Collider[] componentsInChildren2 = ((Component)part).GetComponentsInChildren<Collider>(true);
				Collider[] array = componentsInChildren;
				foreach (Collider val in array)
				{
					Collider[] array2 = componentsInChildren2;
					foreach (Collider val2 in array2)
					{
						if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null && val.enabled && val2.enabled)
						{
							try
							{
								Physics.IgnoreCollision(val, val2, true);
							}
							catch
							{
							}
						}
					}
				}
			}
		}

		internal static void IgnoreCollisionWithCharacter(GameObject ghostRoot, Character character)
		{
			if ((Object)(object)ghostRoot == (Object)null || (Object)(object)character == (Object)null || character.refs == null || (Object)(object)character.refs.ragdoll == (Object)null)
			{
				return;
			}
			Collider[] componentsInChildren = ghostRoot.GetComponentsInChildren<Collider>(true);
			if (componentsInChildren.Length == 0)
			{
				return;
			}
			foreach (Bodypart part in character.refs.ragdoll.partList)
			{
				if ((Object)(object)part == (Object)null)
				{
					continue;
				}
				Collider[] componentsInChildren2 = ((Component)part).GetComponentsInChildren<Collider>(true);
				Collider[] array = componentsInChildren;
				foreach (Collider val in array)
				{
					Collider[] array2 = componentsInChildren2;
					foreach (Collider val2 in array2)
					{
						if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null && val.enabled && val2.enabled)
						{
							try
							{
								Physics.IgnoreCollision(val, val2, true);
							}
							catch
							{
							}
						}
					}
				}
			}
		}

		private void UpdateGhostVisual()
		{
			//IL_005a: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00ae: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_ghostVisualRoot == (Object)null) && !((Object)(object)_character == (Object)null))
			{
				if (_ghostVisualRoot.activeSelf != GhostPlugin.ShowGhostVisual.Value)
				{
					_ghostVisualRoot.SetActive(GhostPlugin.ShowGhostVisual.Value);
				}
				_ghostVisualRoot.transform.position = _character.Center;
				if (((Vector3)(ref _moveDirection)).sqrMagnitude > 0.01f)
				{
					Quaternion val = Quaternion.LookRotation(_moveDirection, Vector3.up);
					_ghostVisualRoot.transform.rotation = Quaternion.Slerp(_ghostVisualRoot.transform.rotation, val, Time.deltaTime * 6f);
				}
			}
		}

		private void DestroyGhostVisual()
		{
			ActiveGhostBall = null;
			if ((Object)(object)_ghostVisualRoot != (Object)null)
			{
				if (_ghostIsNetworked && PhotonNetwork.InRoom)
				{
					try
					{
						PhotonNetwork.Destroy(_ghostVisualRoot);
					}
					catch
					{
					}
				}
				else
				{
					Object.Destroy((Object)(object)_ghostVisualRoot);
				}
			}
			_ghostVisualRoot = null;
			_ghostBall = null;
			_ghostPhotonView = null;
			_ghostRigidbody = null;
			_ghostAnimator = null;
			_ghostIsNetworked = false;
		}

		private void RefreshCamera()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_003c: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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)
			try
			{
				Camera main = Camera.main;
				if (!((Object)(object)main == (Object)null))
				{
					Vector3 thirdPersonCameraLookTarget = GetThirdPersonCameraLookTarget(_character);
					Vector3 val = ResolveCameraCollision(thirdPersonCameraLookTarget, GetThirdPersonCameraPosition(_character));
					if (!_cameraHasSmoothedPosition)
					{
						_cameraSmoothedPosition = val;
						_cameraSmoothedRotation = GetCameraRotation(_cameraSmoothedPosition, thirdPersonCameraLookTarget);
						_cameraHasSmoothedPosition = true;
					}
					else
					{
						_cameraSmoothedPosition = Vector3.SmoothDamp(_cameraSmoothedPosition, val, ref _cameraVelocity, 0.08f);
						Quaternion cameraRotation = GetCameraRotation(_cameraSmoothedPosition, thirdPersonCameraLookTarget);
						float num = 1f - Mathf.Exp(-12f * Time.deltaTime);
						_cameraSmoothedRotation = Quaternion.Slerp(_cameraSmoothedRotation, cameraRotation, num);
					}
					((Component)main).transform.SetPositionAndRotation(_cameraSmoothedPosition, _cameraSmoothedRotation);
					main.fieldOfView = Mathf.Lerp(main.fieldOfView, GetCameraFov(), Time.deltaTime * 4f);
				}
			}
			catch (Exception ex)
			{
				LogError("GhostController.RefreshCamera", ex);
			}
		}

		private static Vector3 GetThirdPersonCameraPosition(Character character)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Vector3 cameraForward = GetCameraForward(character);
			return character.Center + Vector3.up * (GetCameraHeight() + 2f) - cameraForward * GetCameraDistance();
		}

		private static Vector3 GetThirdPersonCameraLookTarget(Character character)
		{
			//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_0023: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 cameraForward = GetCameraForward(character);
			float num = Mathf.Clamp((((Object)(object)character.data != (Object)null) ? ((Vector3)(ref character.data.lookDirection)).normalized : cameraForward).y, -0.35f, 0.65f);
			return character.Center + Vector3.up * (GetCameraHeight() + num * 3f) + cameraForward * 4f;
		}

		private static float GetCameraDistance()
		{
			return Mathf.Clamp((GhostPlugin.CameraDistance != null) ? GhostPlugin.CameraDistance.Value : 16f, 8f, 30f);
		}

		private static float GetCameraHeight()
		{
			return Mathf.Clamp((GhostPlugin.CameraHeight != null) ? GhostPlugin.CameraHeight.Value : 5f, 2f, 14f);
		}

		private static float GetCameraFov()
		{
			return Mathf.Clamp((GhostPlugin.CameraFov != null) ? GhostPlugin.CameraFov.Value : 80f, 60f, 110f);
		}

		private static Vector3 GetCameraForward(Character character)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_0061: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)character.data != (Object)null) ? character.data.lookDirection_Flat : Vector3.zero);
			val = Vector3.ProjectOnPlane(val, Vector3.up);
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && (Object)(object)Camera.main != (Object)null)
			{
				val = Vector3.ProjectOnPlane(((Component)Camera.main).transform.forward, Vector3.up);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				val = Vector3.ProjectOnPlane(((Component)character).transform.forward, Vector3.up);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				val = Vector3.forward;
			}
			return ((Vector3)(ref val)).normalized;
		}

		private Vector3 ResolveCameraCollision(Vector3 lookTarget, Vector3 desiredPosition)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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)
			RaycastHit val = HelperFunctions.LineCheck(lookTarget, desiredPosition, (LayerType)1, 0.35f, (QueryTriggerInteraction)1);
			if ((Object)(object)((RaycastHit)(ref val)).transform != (Object)null)
			{
				desiredPosition = ((RaycastHit)(ref val)).point + ((RaycastHit)(ref val)).normal * 0.8f;
			}
			float groundHeight = GetGroundHeight(desiredPosition);
			if (!float.IsNaN(groundHeight) && desiredPosition.y < groundHeight + 0.8f)
			{
				desiredPosition.y = groundHeight + 0.8f;
			}
			return desiredPosition;
		}

		private static Quaternion GetCameraRotation(Vector3 cameraPosition, Vector3 lookTarget)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = lookTarget - cameraPosition;
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				val = Vector3.forward;
			}
			return Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up);
		}
	}
	[HarmonyPatch]
	public static class GhostHarmonyPatches
	{
		private static readonly HashSet<int> CollisionIgnoredInstances = new HashSet<int>();

		private static bool IsGhostVisual(GhostBall ghostBall)
		{
			if ((Object)(object)ghostBall == (Object)null)
			{
				return false;
			}
			PhotonView component = ((Component)ghostBall).GetComponent<PhotonView>();
			object[] array = (((Object)(object)component != (Object)null) ? component.InstantiationData : null);
			if (array != null && array.Length != 0 && array[0] is string text)
			{
				return text == "ImGhost.Visual";
			}
			return false;
		}

		private static bool IsGhost(Character character)
		{
			return GhostController.IsLocalGhostCharacter(character);
		}

		[HarmonyPatch(typeof(GhostBall), "Update")]
		[HarmonyPrefix]
		private static bool GhostBallUpdatePrefix(GhostBall __instance)
		{
			if (!IsGhostVisual(__instance))
			{
				return true;
			}
			return false;
		}

		[HarmonyPatch(typeof(GhostBall), "FixedUpdate")]
		[HarmonyPrefix]
		private static bool GhostBallFixedUpdatePrefix(GhostBall __instance)
		{
			if (!IsGhostVisual(__instance))
			{
				return true;
			}
			TrySetupCollisionIgnore(__instance);
			return false;
		}

		private static void TrySetupCollisionIgnore(GhostBall ghostBall)
		{
			try
			{
				GameObject gameObject = ((Component)ghostBall).gameObject;
				int instanceID = ((Object)gameObject).GetInstanceID();
				if (CollisionIgnoredInstances.Contains(instanceID))
				{
					return;
				}
				PhotonView component = ((Component)ghostBall).GetComponent<PhotonView>();
				object[] array = (((Object)(object)component != (Object)null) ? component.InstantiationData : null);
				if (array != null && array.Length >= 2 && array[1] is int num)
				{
					PhotonView val = PhotonView.Find(num);
					Character val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Character>() : null);
					if (!((Object)(object)val2 == (Object)null))
					{
						GhostController.IgnoreCollisionWithCharacter(gameObject, val2);
						CollisionIgnoredInstances.Add(instanceID);
					}
				}
			}
			catch
			{
			}
		}

		internal static bool CharacterRpcDiePrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}

		internal static bool CharacterRpcSetDeadPrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}

		internal static bool CharacterRpcPassOutPrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}

		internal static bool CharacterDieInstantlyPrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}

		internal static bool CharacterHandleDeathPrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}

		internal static bool CharacterWarpPlayerRpcPrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}

		internal static bool CharacterWarpPlayerPrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}

		internal static bool CharacterFallPrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}

		internal static bool CharacterRpcFallPrefix(Character __instance)
		{
			return !IsGhost(__instance);
		}
	}
}