Decompiled source of I am Zombie v1.0.1

plugins/Thanks.I_am_a_Zombie.dll

Decompiled a month 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 ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Thanks.I_am_a_Zombie")]
[assembly: AssemblyDescription("Client-side controllable zombie form for PEAK. Press F to become the game's original mushroom zombie with WASD movement, jump, sprint, crouch, wall climb, and lunge attack.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Thanks")]
[assembly: AssemblyProduct("I'm a Zombie")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3a7b9c51-4d2e-4f6a-8b10-9c8d7e6f5a4b")]
[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 ImZombie
{
	[BepInPlugin("com.github.Thanks.ImZombie", "I'm a Zombie", "1.0.2")]
	public sealed class ZombiePlugin : BaseUnityPlugin
	{
		public enum ZombieAppearanceOption
		{
			Player,
			Mushroom
		}

		public const string Id = "com.github.Thanks.ImZombie";

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

		public const string Version = "1.0.2";

		private const byte BodyVisibilityEventCode = 199;

		private const int BodyVisibilityMagic = 1512112921;

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyCode> ToggleKey;

		internal static ConfigEntry<KeyCode> AttackKey;

		internal static ConfigEntry<KeyCode> SprintKey;

		internal static ConfigEntry<KeyCode> JumpKey;

		internal static ConfigEntry<KeyCode> CrouchKey;

		internal static ConfigEntry<float> MovementSpeed;

		internal static ConfigEntry<float> SprintMultiplier;

		internal static ConfigEntry<float> CrouchMultiplier;

		internal static ConfigEntry<float> JumpForce;

		internal static ConfigEntry<float> MaxVelocity;

		internal static ConfigEntry<float> AttackDuration;

		internal static ConfigEntry<float> AttackCooldown;

		internal static ConfigEntry<float> AttackRevertSeconds;

		internal static ConfigEntry<float> CameraDistance;

		internal static ConfigEntry<float> CameraHeight;

		internal static ConfigEntry<float> CameraFov;

		internal static ConfigEntry<bool> HidePlayerBody;

		internal static ConfigEntry<bool> ShowZombieName;

		internal static ConfigEntry<float> HiddenBodyDepth;

		internal static ConfigEntry<ZombieAppearanceOption> ZombieAppearance;

		internal static ConfigEntry<bool> VerboseLogging;

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

		private ZombieController _controller;

		private bool _switching;

		private bool _lastTogglePressed;

		private float _nextPeakStatsRetry;

		internal static bool Verbose
		{
			get
			{
				if (VerboseLogging != null)
				{
					return VerboseLogging.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony.PatchAll(typeof(ZombieHarmonyPatches).Assembly);
			ConfigureOptionalCharacterPatches();
			ConfigureOptionalEndgamePatches();
			SceneManager.sceneLoaded += OnSceneLoaded;
			PhotonNetwork.NetworkingClient.EventReceived += OnPhotonEvent;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[I'm a Zombie] Loaded version 1.0.2.");
		}

		private void Start()
		{
			BindConfig();
		}

		private void BindConfig()
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Expected O, but got Unknown
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Expected O, but got Unknown
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Expected O, but got Unknown
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Expected O, but got Unknown
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Expected O, but got Unknown
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Expected O, but got Unknown
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Expected O, but got Unknown
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ToggleKey", (KeyCode)102, "Press to transform into the game's original zombie (mushroom man). Press again to revert to normal.");
			AttackKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "AttackKey", (KeyCode)324, "Right-click while in zombie form to lunge forward and bite.");
			SprintKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "SprintKey", (KeyCode)304, "Hold to sprint (move faster) while in zombie form.");
			JumpKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "JumpKey", (KeyCode)32, "Press to jump while in zombie form.");
			CrouchKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "CrouchKey", (KeyCode)306, "Hold to crouch (move slower, lower camera) while in zombie form.");
			MovementSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie", "MovementSpeed", 12f, new ConfigDescription("How fast the zombie walks with WASD.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), Array.Empty<object>()));
			SprintMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie", "SprintMultiplier", 2f, new ConfigDescription("Speed multiplier while holding the sprint key.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
			CrouchMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie", "CrouchMultiplier", 0.5f, new ConfigDescription("Speed multiplier while holding the crouch key.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
			JumpForce = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie", "JumpForce", 10f, new ConfigDescription("Upward impulse when jumping.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 25f), Array.Empty<object>()));
			MaxVelocity = ((BaseUnityPlugin)this).Config.Bind<float>("Zombie", "MaxVelocity", 50f, new ConfigDescription("Maximum velocity cap for the zombie ragdoll.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 100f), Array.Empty<object>()));
			AttackDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Attack", "Duration", 1.5f, new ConfigDescription("How long the vanilla-style lunge charge lasts (seconds). Fallback when the zombie prefab's own lungeTime is unavailable.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
			AttackCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Attack", "Cooldown", 1f, new ConfigDescription("Minimum time between attacks (seconds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			AttackRevertSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Attack", "AutoRevertSeconds", 0f, new ConfigDescription("If > 0, auto-revert to normal form this many seconds after attacking. 0 = no auto-revert.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			CameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Distance", 2.8f, new ConfigDescription("Third-person zombie camera distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.5f, 6f), Array.Empty<object>()));
			CameraHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Height", 0.85f, new ConfigDescription("Third-person camera height offset above the zombie's center.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 1.8f), Array.Empty<object>()));
			CameraFov = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Fov", 80f, new ConfigDescription("Field of view while in zombie form (game FOV is preserved; this is a fallback only).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(60f, 110f), Array.Empty<object>()));
			HidePlayerBody = ((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "HidePlayerBody", true, "Hide the player's original body while in zombie form (synced to all clients).");
			ShowZombieName = ((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "ShowZombieName", false, "Show the player's name on the zombie's nameplate.");
			HiddenBodyDepth = ((BaseUnityPlugin)this).Config.Bind<float>("Misc", "HiddenBodyDepth", 30f, new ConfigDescription("How far below the player's feet to stash the hidden body while transformed. The body is moved underground and its position keeps being broadcast, so un-modded clients (incl. late joiners) can't see it; lighting stays correct because the local character is swapped to the zombie (on the ground).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
			ZombieAppearance = ((BaseUnityPlugin)this).Config.Bind<ZombieAppearanceOption>("Misc", "ZombieAppearance", ZombieAppearanceOption.Player, "Zombie appearance: Player = the zombie hides its own lower garments and wears the player's clothes/cosmetics (synced to all clients, incl. un-modded, via PhotonView ownership); Mushroom = pure mushroom-man appearance (un-modded clients will still see it with the player's outfit applied, since they run the vanilla CharacterCustomization");
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Enable verbose/diagnostic logging (animator state dumps, NPC prefab animator lists). Off by default to keep the log clean.");
		}

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

		private void ConfigureOptionalEndgamePatches()
		{
			TryPatchOptionalMethod(typeof(GameOverHandler), "BeginAirportLoadRPC", Type.EmptyTypes, "GameOverHandlerBeginAirportLoadRPCPrefix", "GameOverHandler.BeginAirportLoadRPC()");
			TryPatchOptionalMethod(typeof(EndScreen), "ReturnToAirport", Type.EmptyTypes, "EndScreenReturnToAirportPrefix", "EndScreen.ReturnToAirport()");
		}

		private void TryPatchOptionalMethod(Type declaringType, string methodName, Type[] parameterTypes, string prefixName, string description)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(declaringType, methodName, parameterTypes, (Type[])null);
				if (methodInfo == null)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[I'm a Zombie] Optional " + description + " patch skipped; method not present."));
					return;
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeof(ZombieHarmonyPatches), prefixName, (Type[])null, (Type[])null);
				if (methodInfo2 == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("[I'm a Zombie] Optional " + description + " prefix 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 Zombie] Optional " + description + " patch failed: " + ex.Message));
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			try
			{
				if (!((Object)(object)_controller == (Object)null) && _controller.Active)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogInfo((object)("[I'm a Zombie] Scene switched to '" + ((Scene)(ref scene)).name + "' while transformed; force-exiting so the new scene gets a clean player."));
					}
					ForceExit();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[I'm a Zombie] OnSceneLoaded: " + ex.Message));
				}
			}
		}

		private void Update()
		{
			//IL_000b: 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)
			try
			{
				TryInstallPeakStatsGuard();
				if ((int)ToggleKey.Value != 0)
				{
					bool key = Input.GetKey(ToggleKey.Value);
					if (key && !_lastTogglePressed)
					{
						ToggleZombieForm();
					}
					_lastTogglePressed = key;
					if ((Object)(object)_controller != (Object)null && _controller.Active && !_controller.IsValid())
					{
						ForceExit();
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("[I'm a Zombie] Plugin.Update: " + ex));
				}
			}
		}

		private void TryInstallPeakStatsGuard()
		{
			if (!PeakStatsGuard.IsInstalled && !(Time.unscaledTime < _nextPeakStatsRetry))
			{
				_nextPeakStatsRetry = Time.unscaledTime + 2f;
				PeakStatsGuard.Install(_harmony);
			}
		}

		private void OnDestroy()
		{
			try
			{
				SceneManager.sceneLoaded -= OnSceneLoaded;
			}
			catch
			{
			}
			try
			{
				PhotonNetwork.NetworkingClient.EventReceived -= OnPhotonEvent;
			}
			catch
			{
			}
			try
			{
				ForceExit();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[I'm a Zombie] Exit cleanup failed: " + ex.Message));
				}
			}
			try
			{
				_harmony.UnpatchSelf();
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[I'm a Zombie] Harmony unpatch failed: " + ex2.Message));
				}
			}
		}

		private void OnPhotonEvent(EventData photonEvent)
		{
			if (photonEvent.Code != 199)
			{
				return;
			}
			try
			{
				if (photonEvent.CustomData is object[] array && array.Length >= 3 && array[0] is int num && num == 1512112921)
				{
					int num2 = (int)array[1];
					object obj = array[2];
					bool flag = default(bool);
					int num3;
					if (obj is bool)
					{
						flag = (bool)obj;
						num3 = 1;
					}
					else
					{
						num3 = 0;
					}
					bool flag2 = (byte)((uint)num3 & (flag ? 1u : 0u)) != 0;
					PhotonView val = PhotonView.Find(num2);
					if (!((Object)(object)val == (Object)null))
					{
						SetRenderersVisible(((Component)val).gameObject, !flag2);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[I'm a Zombie] Body visibility event failed: " + ex.Message));
				}
			}
		}

		internal static void SendBodyVisibility(int viewId, bool hide)
		{
			//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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			try
			{
				if (PhotonNetwork.IsConnected)
				{
					object[] obj = new object[3] { 1512112921, viewId, hide };
					RaiseEventOptions val = new RaiseEventOptions
					{
						Receivers = (ReceiverGroup)0
					};
					SendOptions val2 = default(SendOptions);
					((SendOptions)(ref val2)).Reliability = true;
					PhotonNetwork.RaiseEvent((byte)199, (object)obj, val, val2);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[I'm a Zombie] Failed to send body visibility event: " + ex.Message));
				}
			}
		}

		internal static void SetRenderersVisible(GameObject root, bool visible)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.enabled = visible;
					val.forceRenderingOff = !visible;
				}
			}
		}

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

		private static bool CanTransform(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)"[I'm a Zombie] No local character.");
				}
				return false;
			}
			if ((Object)(object)character.data == (Object)null || character.refs == null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[I'm a Zombie] Character not ready.");
				}
				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 log3 = Log;
				if (log3 != null)
				{
					log3.LogWarning((object)"[I'm a Zombie] Character not in a valid state to transform.");
				}
				return false;
			}
			if (ZombieController.IsOtherTransformModActive())
			{
				ManualLogSource log4 = Log;
				if (log4 != null)
				{
					log4.LogWarning((object)"[I'm a Zombie] Another transform mod is active (Scoutmaster/Ghost/Tornado…) — exit it first.");
				}
				return false;
			}
			return true;
		}

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

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

		private void ForceExit()
		{
			if ((Object)(object)_controller == (Object)null)
			{
				return;
			}
			try
			{
				_controller.ExitZombie();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[I'm a Zombie] ForceExit: " + ex.Message));
				}
			}
			_controller = null;
		}
	}
	[DefaultExecutionOrder(-100)]
	public sealed class ZombieController : MonoBehaviour
	{
		private const float ThirdPersonCameraFollowSharpness = 18f;

		private const float ThirdPersonCameraPositionSharpness = 16f;

		private const float ThirdPersonCameraRotationSharpness = 22f;

		private const float ThirdPersonCameraSnapDistance = 8f;

		private const float ThirdPersonAttackHeightOffset = 0.45f;

		private const float DefaultCameraDistance = 2.8f;

		private const float DefaultCameraHeight = 0.85f;

		private const float DefaultCameraFov = 80f;

		private const float MaxVelocityConst = 50f;

		private const float AngularVelocityDamping = 0.92f;

		private const float MaxAngularVelocity = 10f;

		private const KeyCode ClimbKey = (KeyCode)323;

		private const float ClimbRagdollControl = 0.95f;

		private const float ClimbMaxLinearVelocity = 9f;

		private const float ClimbMaxAngularVelocity = 8f;

		private const float ClimbSurfaceProbeDistance = 2.25f;

		private const float ClimbStartRayDistance = 1.65f;

		private const float ClimbAttemptCooldownSeconds = 0.08f;

		private const float ClimbReleaseFallWindowSeconds = 0.7f;

		private const float ClimbReleaseFallSeconds = 1.25f;

		private const float ClimbRepeatedHitDistance = 0.28f;

		private const float ClimbRepeatedNormalDot = 0.94f;

		private const float ClimbForwardInputDeadzone = 0.05f;

		private static readonly MethodInfo ClimbStartClimbRpcMethod = FindClimbStartClimbRpcMethod();

		private static readonly FieldInfo ClimbClimbToggledOnField = typeof(CharacterClimbing).GetField("climbToggledOn", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo ClimbSinceLastClimbStartedField = typeof(CharacterClimbing).GetField("sinceLastClimbStarted", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo ClimbPlayerSlideField = typeof(CharacterClimbing).GetField("playerSlide", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo ClimbCanClimbMethod = typeof(CharacterClimbing).GetMethod("CanClimb", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);

		private const BindingFlags ClimbReflectFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private float _nextClimbAttemptTime;

		private float _climbReleaseFallUntil;

		private bool _hasLastClimbStart;

		private Vector3 _lastClimbStartPoint;

		private Vector3 _lastClimbStartNormal = Vector3.forward;

		private float _nextAnimatorLogTime;

		private const float DefaultHiddenBodyDepth = 30f;

		private Character _zombieCharacter;

		private Character _playerCharacter;

		private Vector3 _prevCenter;

		private bool _hasSmoothedCameraPose;

		private Vector3 _smoothedCameraPosition;

		private Quaternion _smoothedCameraRotation = Quaternion.identity;

		private bool _hasSmoothedCameraTarget;

		private Vector3 _smoothedCameraTarget;

		private ExitCameraBlend _exitCameraBlend;

		private const float ExitCameraBlendSeconds = 0.4f;

		private bool _lastJumpPressed;

		private bool _lastAttackPressed;

		private bool _jumpQueued;

		private bool _attacking;

		private float _attackStartedAt;

		private float _lastAttackTime;

		private GameObject _zombieRoot;

		private MushroomZombie _mushroomZombie;

		private PhotonView _zombiePhotonView;

		private bool _zombieIsNetworked;

		private bool _playerBodyHidden;

		private Coroutine _deferredExitRestore;

		private GameObject _pendingDestroyRoot;

		private bool _pendingDestroyNetworked;

		internal static int ExitSfxSuppressedFrame = int.MinValue;

		private Vector3 _hiddenBodyPos;

		private bool _hiddenBodyPosSet;

		private readonly List<MonoBehaviour> _disabledCameraScripts = new List<MonoBehaviour>();

		private readonly List<bool> _cameraScriptStates = new List<bool>();

		private CharacterMovement _disabledPlayerMovement;

		private readonly List<Rigidbody> _frozenBodyparts = new List<Rigidbody>();

		private readonly List<bool> _frozenKinematic = new List<bool>();

		private readonly List<bool> _frozenDetectCollisions = new List<bool>();

		private readonly List<bool> _frozenUseGravity = new List<bool>();

		private readonly List<Light> _playerLights = new List<Light>();

		private readonly List<bool> _playerLightStates = new List<bool>();

		private float _nextBodyVisibilityRebroadcast;

		private const float BodyVisibilityRebroadcastSeconds = 5f;

		private bool _localCharacterSwapped;

		private Character _localCharacterSwapTarget;

		internal const string NetworkVisualMarker = "ImZombie.Visual";

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

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

		private bool _hudHidden;

		private readonly List<Renderer> _playerRenderers = new List<Renderer>();

		private readonly List<bool> _playerRendererStates = new List<bool>();

		private ZombiePlugin.ZombieAppearanceOption _zombieAppearance;

		public static Character ActiveZombieCharacter { get; private set; }

		internal static Character ParkedPlayerCharacter { get; private set; }

		public bool Active { get; private set; }

		private static MethodInfo FindClimbStartClimbRpcMethod()
		{
			MethodInfo methodInfo = null;
			MethodInfo[] methods = typeof(CharacterClimbing).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (methodInfo2 == null || methodInfo2.Name != "StartClimbRpc")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo2.GetParameters();
				if (parameters.Length >= 2 && !(parameters[0].ParameterType != typeof(Vector3)) && !(parameters[1].ParameterType != typeof(Vector3)))
				{
					if (parameters.Length == 2)
					{
						return methodInfo2;
					}
					if ((object)methodInfo == null)
					{
						methodInfo = methodInfo2;
					}
				}
			}
			return methodInfo;
		}

		private static object[] BuildClimbRpcArguments(MethodInfo method, Vector3 climbPos, Vector3 climbNormal)
		{
			//IL_0057: 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)
			if (method == null)
			{
				return null;
			}
			ParameterInfo[] parameters = method.GetParameters();
			if (parameters.Length < 2 || parameters[0].ParameterType != typeof(Vector3) || parameters[1].ParameterType != typeof(Vector3))
			{
				return null;
			}
			object[] array = new object[parameters.Length];
			array[0] = climbPos;
			array[1] = climbNormal;
			for (int i = 2; i < parameters.Length; i++)
			{
				Type parameterType = parameters[i].ParameterType;
				array[i] = (parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null);
			}
			return array;
		}

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

		internal static bool IsOtherTransformModActive()
		{
			try
			{
				foreach (Character allCharacter in Character.AllCharacters)
				{
					if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter.data == (Object)null))
					{
						if (allCharacter.data.isScoutmaster)
						{
							return true;
						}
						string text = ((Object)allCharacter).name ?? string.Empty;
						if (text.IndexOf("Scoutmaster", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Ghost", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Tornado", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							return true;
						}
					}
				}
			}
			catch
			{
			}
			return false;
		}

		internal static void ForceExitForEndGame()
		{
			try
			{
				if ((Object)(object)ParkedPlayerCharacter != (Object)null)
				{
					ZombieController component = ((Component)ParkedPlayerCharacter).GetComponent<ZombieController>();
					if ((Object)(object)component != (Object)null && component.Active)
					{
						component.ExitZombie();
						return;
					}
				}
				ZombieController[] array = Object.FindObjectsByType<ZombieController>((FindObjectsSortMode)0);
				foreach (ZombieController zombieController in array)
				{
					if ((Object)(object)zombieController != (Object)null && zombieController.Active)
					{
						zombieController.ExitZombie();
						break;
					}
				}
			}
			catch (Exception ex)
			{
				LogError("ForceExitForEndGame", ex);
			}
		}

		private static void LogInfo(string m)
		{
			ZombiePlugin.Log.LogInfo((object)("[ImZombie] " + m));
		}

		private static void LogError(string c, Exception ex)
		{
			ZombiePlugin.Log.LogError((object)("[ImZombie] " + c + ": " + ex));
		}

		private static void LogVerbose(string m)
		{
			if (ZombiePlugin.Verbose)
			{
				ZombiePlugin.Log.LogInfo((object)("[ImZombie][V] " + m));
			}
		}

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

		public void EnterZombie(Character playerCharacter)
		{
			if (Active)
			{
				LogInfo("Already in zombie form.");
				return;
			}
			FlushDeferredExitRestore();
			StopExitCameraBlend();
			_playerCharacter = playerCharacter;
			FreezePlayerPhysics();
			HidePlayerBody();
			SendNetworkBodyVisibility(hide: true);
			GameObject val = SpawnZombiePrefab(playerCharacter);
			if ((Object)(object)val == (Object)null)
			{
				LogInfo("Failed to spawn zombie prefab.");
				AbortEnterZombie();
				return;
			}
			_zombieRoot = val;
			_zombieCharacter = val.GetComponent<Character>();
			_mushroomZombie = val.GetComponent<MushroomZombie>();
			_zombiePhotonView = val.GetComponent<PhotonView>();
			if ((Object)(object)_zombieCharacter == (Object)null)
			{
				LogInfo("No Character component on zombie! Aborting.");
				DestroyZombie();
				AbortEnterZombie();
				return;
			}
			SetupZombieVisuals();
			ClearPlayerInput();
			InitZombieState();
			_attacking = false;
			_attackStartedAt = 0f;
			_lastAttackTime = -10f;
			_lastJumpPressed = false;
			_lastAttackPressed = false;
			ResetCameraSmoothing();
			Active = true;
			ActiveZombieCharacter = _zombieCharacter;
			ParkedPlayerCharacter = _playerCharacter;
			((Behaviour)this).enabled = true;
			try
			{
				Character.localCharacter = _zombieCharacter;
				_localCharacterSwapTarget = _zombieCharacter;
				_localCharacterSwapped = true;
			}
			catch (Exception ex)
			{
				LogError("EnterZombie localCharacter swap", ex);
			}
			DisableOriginalCameraControl();
			HideHud();
			WarpPlayerToHiddenPosition();
			((MonoBehaviour)this).StartCoroutine(ReassertOutfitAfterEnter());
			((MonoBehaviour)this).StartCoroutine(PushIdleStateAfterEnter());
			_nextBodyVisibilityRebroadcast = Time.unscaledTime + 5f;
			LogInfo("Entered zombie form.");
		}

		private IEnumerator PushIdleStateAfterEnter()
		{
			for (int i = 0; i < 4; i++)
			{
				yield return (object)new WaitForSeconds(0.2f);
				if (!Active)
				{
					break;
				}
				PushZombieStateToRemote();
			}
		}

		private void PushZombieStateToRemote()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected I4, but got Unknown
			if ((Object)(object)_zombiePhotonView == (Object)null || !_zombiePhotonView.IsMine || (Object)(object)_zombieCharacter?.data == (Object)null)
			{
				return;
			}
			try
			{
				State val = (State)((!((Object)(object)_mushroomZombie != (Object)null)) ? 2 : ((int)_mushroomZombie.currentState));
				_zombiePhotonView.RPC("RPC_SyncState", (RpcTarget)1, new object[4]
				{
					(int)val,
					_zombieCharacter.data.isSprinting,
					_zombieCharacter.data.fallSeconds,
					_zombieCharacter.data.passedOut
				});
			}
			catch (Exception ex)
			{
				LogError("PushZombieStateToRemote", ex);
			}
		}

		private IEnumerator ReassertOutfitAfterEnter()
		{
			yield return (object)new WaitForSeconds(1.2f);
			if (!Active || (Object)(object)_mushroomZombie == (Object)null || (Object)(object)_playerCharacter == (Object)null || _zombieAppearance != ZombiePlugin.ZombieAppearanceOption.Mushroom || (Object)(object)_zombiePhotonView == (Object)null || !_zombiePhotonView.IsMine)
			{
				yield break;
			}
			try
			{
				bool playerWearingSkirt = GetPlayerWearingSkirt();
				_zombiePhotonView.RPC("RPC_SetOutfit", (RpcTarget)0, new object[1] { playerWearingSkirt });
				FieldInfo field = typeof(MushroomZombie).GetField("wearingSkirt", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field != null)
				{
					field.SetValue(_mushroomZombie, playerWearingSkirt);
				}
			}
			catch (Exception ex)
			{
				LogError("ReassertOutfitAfterEnter", ex);
			}
		}

		private bool GetPlayerWearingSkirt()
		{
			CustomizationRefs val = _playerCharacter?.refs?.customization?.refs;
			if ((Object)(object)val != (Object)null && (Object)(object)val.skirt != (Object)null && (Object)(object)val.shorts != (Object)null)
			{
				if (((Component)val.skirt).gameObject.activeSelf)
				{
					return !((Component)val.shorts).gameObject.activeSelf;
				}
				return false;
			}
			return false;
		}

		private void RestoreLocalCharacter()
		{
			if (!_localCharacterSwapped)
			{
				return;
			}
			_localCharacterSwapped = false;
			try
			{
				if ((Object)(object)_playerCharacter != (Object)null && (Object)(object)Character.localCharacter == (Object)(object)_localCharacterSwapTarget)
				{
					Character.localCharacter = _playerCharacter;
				}
				_localCharacterSwapTarget = null;
			}
			catch (Exception ex)
			{
				LogError("RestoreLocalCharacter", ex);
			}
		}

		private void AbortEnterZombie()
		{
			RestoreLocalCharacter();
			RestorePlayerPhysics();
			RestorePlayerBody();
			SendNetworkBodyVisibility(hide: false);
			RestoreOriginalCameraControl();
			RestoreHud();
			_playerCharacter = null;
			_playerBodyHidden = false;
			_hiddenBodyPosSet = false;
			ParkedPlayerCharacter = null;
		}

		public void ExitZombie()
		{
			//IL_0183: 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_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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_006f: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: 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)
			if (!Active && (Object)(object)_zombieRoot == (Object)null)
			{
				return;
			}
			ExitSfxSuppressedFrame = Time.frameCount;
			Vector3 val = Vector3.zero;
			Vector2 lookValues = Vector2.zero;
			bool flag = false;
			if ((Object)(object)_zombieCharacter != (Object)null && (Object)(object)_zombieCharacter.data != (Object)null)
			{
				val = _zombieCharacter.Center + Vector3.up * 0.25f;
				lookValues = _zombieCharacter.data.lookValues;
				flag = true;
			}
			Active = false;
			ActiveZombieCharacter = null;
			((Behaviour)this).enabled = false;
			_hiddenBodyPosSet = false;
			_attacking = false;
			_attackStartedAt = 0f;
			DeactivateZombieForDeferredDestroy();
			if (flag && (Object)(object)_playerCharacter != (Object)null)
			{
				_playerCharacter.data.lookValues = lookValues;
				RecalculateLookDirections(_playerCharacter);
				ResetPlayerState(_playerCharacter, val);
				SetCharacterPositionImmediate(_playerCharacter, val, ((Component)_playerCharacter).transform.rotation);
				try
				{
					if ((Object)(object)((MonoBehaviourPun)_playerCharacter).photonView != (Object)null && (PhotonNetwork.InRoom || PhotonNetwork.IsConnected))
					{
						((MonoBehaviourPun)_playerCharacter).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, false });
					}
					else
					{
						_playerCharacter.WarpPlayerRPC(val, false);
					}
				}
				catch (Exception ex)
				{
					LogError("ExitZombie warp", ex);
					_playerCharacter.WarpPlayerRPC(val, false);
				}
			}
			RestorePlayerPhysics();
			RestoreLocalCharacter();
			SendNetworkBodyVisibility(hide: false);
			RestoreOriginalCameraControl();
			StartExitCameraBlend();
			ParkedPlayerCharacter = null;
			if (_deferredExitRestore != null)
			{
				try
				{
					((MonoBehaviour)this).StopCoroutine(_deferredExitRestore);
				}
				catch
				{
				}
			}
			_deferredExitRestore = ((MonoBehaviour)this).StartCoroutine(DeferredExitRestoreRoutine());
			LogInfo("Exited zombie form.");
		}

		private IEnumerator DeferredExitRestoreRoutine()
		{
			yield return null;
			_deferredExitRestore = null;
			DestroyDeactivatedZombie();
			RestorePlayerBody();
			yield return null;
			RestoreHud();
		}

		internal void FlushDeferredExitRestore()
		{
			if (_deferredExitRestore != null)
			{
				try
				{
					((MonoBehaviour)this).StopCoroutine(_deferredExitRestore);
				}
				catch
				{
				}
				_deferredExitRestore = null;
			}
			DestroyDeactivatedZombie();
			RestorePlayerBody();
			RestoreHud();
		}

		private void OnDestroy()
		{
			FlushDeferredExitRestore();
			StopExitCameraBlend();
			if (Active)
			{
				Active = false;
				ActiveZombieCharacter = null;
				_hiddenBodyPosSet = false;
				DestroyZombie();
				RestoreOriginalCameraControl();
				RestorePlayerPhysics();
				RestorePlayerBody();
				RestoreLocalCharacter();
				SendNetworkBodyVisibility(hide: false);
				RestoreHud();
				ParkedPlayerCharacter = null;
			}
		}

		private void InitZombieState()
		{
			//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)
			try
			{
				_zombieCharacter.data.currentRagdollControll = 1f;
				_zombieCharacter.data.dead = false;
				_zombieCharacter.data.passedOut = false;
				_zombieCharacter.data.fullyPassedOut = false;
				_zombieCharacter.data.fallSeconds = 0f;
				_zombieCharacter.data.zombified = false;
				_zombieCharacter.data.isSprinting = false;
				_zombieCharacter.data.isCrouching = false;
				CharacterData data = _zombieCharacter.data;
				Character playerCharacter = _playerCharacter;
				float? obj;
				if (playerCharacter == null)
				{
					obj = null;
				}
				else
				{
					CharacterData data2 = playerCharacter.data;
					obj = ((data2 != null) ? new float?(data2.currentStamina) : ((float?)null));
				}
				data.currentStamina = obj ?? 1f;
				_zombieCharacter.data.extraStamina = 0f;
				try
				{
					CharacterMovement component = ((Component)_zombieCharacter).GetComponent<CharacterMovement>();
					CharacterMovement val = (((Object)(object)_playerCharacter != (Object)null) ? ((Component)_playerCharacter).GetComponent<CharacterMovement>() : null);
					if ((Object)(object)component != (Object)null && (Object)(object)val != (Object)null)
					{
						component.sprintStaminaUsage = val.sprintStaminaUsage;
						component.jumpStaminaUsage = val.jumpStaminaUsage;
						component.jumpStaminaUsageSprinting = val.jumpStaminaUsageSprinting;
					}
				}
				catch (Exception ex)
				{
					LogError("InitZombieState stamina rates", ex);
				}
				try
				{
					_zombieCharacter.InitializeRefs();
					if (_zombieCharacter.refs != null && (Object)(object)_zombieCharacter.refs.customization == (Object)null)
					{
						_zombieCharacter.refs.customization = ((Component)_zombieCharacter).GetComponentInChildren<CharacterCustomization>(true);
					}
					_zombieCharacter.isBot = false;
				}
				catch (Exception ex2)
				{
					LogError("InitZombieState refs", ex2);
				}
				if ((Object)(object)_playerCharacter != (Object)null && (Object)(object)_playerCharacter.data != (Object)null)
				{
					_zombieCharacter.data.lookValues = _playerCharacter.data.lookValues;
					RecalculateLookDirections(_zombieCharacter);
				}
				if (_zombieCharacter.refs != null && (Object)(object)_zombieCharacter.refs.ragdoll != (Object)null)
				{
					_zombieCharacter.refs.ragdoll.ToggleKinematic(false);
					CopyPlayerPoseToZombie();
					WakeZombieRagdoll();
				}
			}
			catch (Exception ex3)
			{
				LogError("InitZombieState", ex3);
			}
		}

		private void CopyPlayerPoseToZombie()
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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)
			if (_playerCharacter?.refs?.ragdoll?.partList == null || _zombieCharacter?.refs?.ragdoll?.partList == null)
			{
				return;
			}
			foreach (Bodypart part in _zombieCharacter.refs.ragdoll.partList)
			{
				if (!((Object)(object)part == (Object)null) && !((Object)(object)part.Rig == (Object)null))
				{
					Bodypart val = FindBodypart(_playerCharacter, part.partType);
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val.Rig == (Object)null))
					{
						part.Rig.MovePosition(val.Rig.position);
						part.Rig.MoveRotation(val.Rig.rotation);
					}
				}
			}
		}

		private static Bodypart FindBodypart(Character character, BodypartType type)
		{
			//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)
			if (character?.refs?.ragdoll?.partList == null)
			{
				return null;
			}
			foreach (Bodypart part in character.refs.ragdoll.partList)
			{
				if ((Object)(object)part != (Object)null && part.partType == type)
				{
					return part;
				}
			}
			return null;
		}

		private void WakeZombieRagdoll()
		{
			if (_zombieCharacter?.refs?.ragdoll?.partList == null)
			{
				return;
			}
			foreach (Bodypart part in _zombieCharacter.refs.ragdoll.partList)
			{
				Rigidbody val = ((part != null) ? part.Rig : null);
				if (!((Object)(object)val == (Object)null))
				{
					val.isKinematic = false;
					val.detectCollisions = true;
					val.useGravity = true;
					val.WakeUp();
				}
			}
		}

		private GameObject SpawnZombiePrefab(Character playerCharacter)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			Vector3 center = playerCharacter.Center;
			Quaternion rotation = ((Component)playerCharacter).transform.rotation;
			_zombieAppearance = GetAppearance();
			bool flag = _zombieAppearance == ZombiePlugin.ZombieAppearanceOption.Player;
			string text = (flag ? "MushroomZombie_Player" : "MushroomZombie");
			if (PhotonNetwork.InRoom && (Object)(object)((MonoBehaviourPun)playerCharacter).photonView != (Object)null && ((MonoBehaviourPun)playerCharacter).photonView.ViewID > 0)
			{
				try
				{
					GameObject val = PhotonNetwork.Instantiate(text, center, rotation, (byte)0, new object[3]
					{
						"ImZombie.Visual",
						((MonoBehaviourPun)playerCharacter).photonView.ViewID,
						(int)_zombieAppearance
					});
					if ((Object)(object)val != (Object)null)
					{
						((Object)val).name = "ImZombieNetworked";
						_zombieIsNetworked = true;
						LogInfo("Spawned networked zombie (" + text + ").");
						return val;
					}
				}
				catch (Exception ex)
				{
					LogError("PhotonNetwork.Instantiate " + text, ex);
				}
			}
			try
			{
				GameObject val2 = Resources.Load<GameObject>(text);
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = Resources.Load<GameObject>("PhotonPrefabs/" + text);
				}
				if ((Object)(object)val2 == (Object)null && !flag)
				{
					val2 = Resources.Load<GameObject>("MushroomZombie_Player");
				}
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = Resources.Load<GameObject>("PhotonPrefabs/MushroomZombie_Player");
				}
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = Resources.Load<GameObject>("MushroomZombie");
				}
				if ((Object)(object)val2 == (Object)null)
				{
					LogInfo("Could not find zombie prefab via Resources.Load (" + text + ").");
					return null;
				}
				GameObject obj = Object.Instantiate<GameObject>(val2, center, rotation);
				((Object)obj).name = "ImZombieLocal";
				_zombieIsNetworked = false;
				LogInfo("Spawned local zombie prefab (" + ((Object)val2).name + ").");
				return obj;
			}
			catch (Exception ex2)
			{
				LogError("Resources.Load zombie prefab", ex2);
				return null;
			}
		}

		private void SetupZombieVisuals()
		{
			if ((Object)(object)_mushroomZombie == (Object)null)
			{
				return;
			}
			try
			{
				_mushroomZombie.isNPCZombie = false;
				_mushroomZombie.initialWakeUpTime = 0f;
				_mushroomZombie.currentState = (State)2;
				_mushroomZombie.lifetime = 9999f;
				MethodInfo method = typeof(MushroomZombie).GetMethod("FadeInRenderers", BindingFlags.Instance | BindingFlags.NonPublic);
				if (method != null)
				{
					method.Invoke(_mushroomZombie, null);
				}
				MethodInfo method2 = typeof(MushroomZombie).GetMethod("SetZombieEyes", BindingFlags.Instance | BindingFlags.NonPublic);
				if (method2 != null)
				{
					method2.Invoke(_mushroomZombie, null);
				}
				ApplyZombieAnimator();
				ApplyZombieOutfit();
			}
			catch (Exception ex)
			{
				LogError("SetupZombieVisuals", ex);
			}
		}

		private void ApplyZombieAnimator()
		{
			if ((Object)(object)_zombieCharacter?.refs?.animator == (Object)null)
			{
				LogInfo("ApplyZombieAnimator: no zombie animator.");
				return;
			}
			try
			{
				GameObject val = null;
				try
				{
					object prefabPool = PhotonNetwork.PrefabPool;
					if (prefabPool != null)
					{
						MethodInfo method = prefabPool.GetType().GetMethod("LoadPrefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						if (method != null)
						{
							object? obj = method.Invoke(prefabPool, new object[1] { "MushroomZombie" });
							val = (GameObject)((obj is GameObject) ? obj : null);
						}
					}
				}
				catch (Exception ex)
				{
					LogError("ApplyZombieAnimator pool", ex);
				}
				if ((Object)(object)val == (Object)null)
				{
					val = Resources.Load<GameObject>("MushroomZombie");
				}
				if ((Object)(object)val == (Object)null)
				{
					val = Resources.Load<GameObject>("PhotonPrefabs/MushroomZombie");
				}
				if ((Object)(object)val == (Object)null)
				{
					LogInfo("ApplyZombieAnimator: NPC prefab not found (pool+resources).");
					return;
				}
				Animator componentInChildren = val.GetComponentInChildren<Animator>(true);
				if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.runtimeAnimatorController == (Object)null)
				{
					LogInfo("ApplyZombieAnimator: NPC animator/controller missing.");
					return;
				}
				if (ZombiePlugin.Verbose)
				{
					try
					{
						string text = string.Join(",", Array.ConvertAll(val.GetComponentsInChildren<Animator>(true), (Animator a) => (!((Object)(object)a.runtimeAnimatorController != (Object)null)) ? "null" : ((Object)a.runtimeAnimatorController).name));
						LogVerbose("ApplyZombieAnimator: NPC prefab animators=[" + text + "]");
					}
					catch
					{
					}
				}
				string text2 = (((Object)(object)_zombieCharacter.refs.animator.runtimeAnimatorController != (Object)null) ? ((Object)_zombieCharacter.refs.animator.runtimeAnimatorController).name : "null");
				_zombieCharacter.refs.animator.runtimeAnimatorController = componentInChildren.runtimeAnimatorController;
				LogInfo("ApplyZombieAnimator: switched " + text2 + " -> " + ((Object)componentInChildren.runtimeAnimatorController).name);
			}
			catch (Exception ex2)
			{
				LogError("ApplyZombieAnimator", ex2);
			}
		}

		private void LogAnimatorDiagnostics()
		{
			if (!ZombiePlugin.Verbose || (Object)(object)_zombieCharacter?.refs?.animator == (Object)null || Time.time < _nextAnimatorLogTime)
			{
				return;
			}
			_nextAnimatorLogTime = Time.time + 2f;
			try
			{
				string text = (((Object)(object)_zombieCharacter.refs.animator.runtimeAnimatorController != (Object)null) ? ((Object)_zombieCharacter.refs.animator.runtimeAnimatorController).name : "null");
				LogInfo("AnimatorDiag: ctrl=" + text + " input=" + (((Object)(object)_zombieCharacter.input != (Object)null) ? ((object)Unsafe.As<Vector2, Vector2>(ref _zombieCharacter.input.movementInput)/*cast due to .constrained prefix*/).ToString() : "null") + " sprint=" + _zombieCharacter.data.isSprinting + " vel=" + ((object)Unsafe.As<Vector3, Vector3>(ref _zombieCharacter.data.avarageVelocity)/*cast due to .constrained prefix*/).ToString() + " grounded=" + _zombieCharacter.data.isGrounded + " sinceGrounded=" + _zombieCharacter.data.sinceGrounded + " animators=[" + string.Join(",", Array.ConvertAll(((Component)_zombieCharacter).GetComponentsInChildren<Animator>(true), (Animator a) => (!((Object)(object)a.runtimeAnimatorController != (Object)null)) ? "null" : ((Object)a.runtimeAnimatorController).name)) + "]");
			}
			catch (Exception ex)
			{
				LogError("LogAnimatorDiagnostics", ex);
			}
		}

		private void ApplyZombieOutfit()
		{
			if ((Object)(object)_mushroomZombie == (Object)null || (Object)(object)_playerCharacter == (Object)null)
			{
				return;
			}
			try
			{
				if (_zombieAppearance == ZombiePlugin.ZombieAppearanceOption.Player)
				{
					if ((Object)(object)_zombieCharacter?.refs?.customization != (Object)null)
					{
						CharacterCustomization customization = _zombieCharacter.refs.customization;
						PhotonView photonView = ((MonoBehaviourPun)_playerCharacter).photonView;
						customization.overridePhotonPlayer = ((photonView != null) ? photonView.Owner : null);
						_zombieCharacter.refs.customization.ignorePlayerCosmetics = false;
					}
					try
					{
						if ((Object)(object)_zombieCharacter?.refs?.customization?.refs != (Object)null)
						{
							_zombieCharacter.refs.customization.refs.SetMushroomMan(false);
						}
					}
					catch
					{
					}
					HideMushroomParts();
					FieldInfo field = typeof(MushroomZombie).GetField("wearingSkirt", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						field.SetValue(_mushroomZombie, false);
					}
					return;
				}
				if ((Object)(object)_zombieCharacter?.refs?.customization != (Object)null)
				{
					_zombieCharacter.refs.customization.overridePhotonPlayer = null;
					_zombieCharacter.refs.customization.ignorePlayerCosmetics = true;
				}
				bool playerWearingSkirt = GetPlayerWearingSkirt();
				if ((Object)(object)_zombiePhotonView != (Object)null && _zombiePhotonView.IsMine)
				{
					try
					{
						_zombiePhotonView.RPC("RPC_SetOutfit", (RpcTarget)0, new object[1] { playerWearingSkirt });
					}
					catch
					{
					}
				}
				if ((Object)(object)_mushroomZombie.skirt != (Object)null)
				{
					_mushroomZombie.skirt.SetActive(playerWearingSkirt);
				}
				if ((Object)(object)_mushroomZombie.shorts != (Object)null)
				{
					_mushroomZombie.shorts.SetActive(!playerWearingSkirt);
				}
				FieldInfo field2 = typeof(MushroomZombie).GetField("wearingSkirt", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field2 != null)
				{
					field2.SetValue(_mushroomZombie, playerWearingSkirt);
				}
			}
			catch (Exception ex)
			{
				LogError("ApplyZombieOutfit", ex);
			}
		}

		private void HideMushroomParts()
		{
			if ((Object)(object)_mushroomZombie == (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)_mushroomZombie.skirt != (Object)null)
				{
					_mushroomZombie.skirt.SetActive(false);
				}
				if ((Object)(object)_mushroomZombie.shorts != (Object)null)
				{
					_mushroomZombie.shorts.SetActive(false);
				}
				if (_mushroomZombie.mushroomVisuals != null)
				{
					foreach (GameObject mushroomVisual in _mushroomZombie.mushroomVisuals)
					{
						if ((Object)(object)mushroomVisual != (Object)null)
						{
							mushroomVisual.SetActive(false);
						}
					}
				}
				CustomizationRefs val = _zombieCharacter?.refs?.customization?.refs;
				if ((Object)(object)val != (Object)null)
				{
					if ((Object)(object)val.skirt != (Object)null)
					{
						((Component)val.skirt).gameObject.SetActive(false);
					}
					if ((Object)(object)val.shorts != (Object)null)
					{
						((Component)val.shorts).gameObject.SetActive(false);
					}
					if ((Object)(object)val.skirtShadow != (Object)null)
					{
						((Component)val.skirtShadow).gameObject.SetActive(false);
					}
					if ((Object)(object)val.shortsShadow != (Object)null)
					{
						((Component)val.shortsShadow).gameObject.SetActive(false);
					}
					if ((Object)(object)val.sashRenderer != (Object)null)
					{
						val.sashRenderer.enabled = false;
					}
					if ((Object)(object)val.accessoryRenderer != (Object)null)
					{
						val.accessoryRenderer.enabled = false;
					}
				}
			}
			catch (Exception ex)
			{
				LogError("HideMushroomParts", ex);
			}
		}

		private void FreezePlayerPhysics()
		{
			//IL_00d1: 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)
			if ((Object)(object)_playerCharacter?.refs?.ragdoll == (Object)null)
			{
				return;
			}
			try
			{
				_frozenBodyparts.Clear();
				_frozenKinematic.Clear();
				_frozenDetectCollisions.Clear();
				_frozenUseGravity.Clear();
				foreach (Bodypart part in _playerCharacter.refs.ragdoll.partList)
				{
					Rigidbody val = ((part != null) ? part.Rig : null);
					if (!((Object)(object)val == (Object)null))
					{
						_frozenBodyparts.Add(val);
						_frozenKinematic.Add(val.isKinematic);
						_frozenDetectCollisions.Add(val.detectCollisions);
						_frozenUseGravity.Add(val.useGravity);
						val.linearVelocity = Vector3.zero;
						val.angularVelocity = Vector3.zero;
						val.detectCollisions = false;
						val.useGravity = false;
						val.isKinematic = true;
					}
				}
				_disabledPlayerMovement = ((Component)_playerCharacter).GetComponent<CharacterMovement>();
				if ((Object)(object)_disabledPlayerMovement != (Object)null && ((Behaviour)_disabledPlayerMovement).enabled)
				{
					((Behaviour)_disabledPlayerMovement).enabled = false;
				}
			}
			catch (Exception ex)
			{
				LogError("FreezePlayerPhysics", ex);
			}
		}

		private void RestorePlayerPhysics()
		{
			//IL_00a8: 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)
			try
			{
				if ((Object)(object)_disabledPlayerMovement != (Object)null)
				{
					((Behaviour)_disabledPlayerMovement).enabled = true;
					_disabledPlayerMovement = null;
				}
				for (int i = 0; i < _frozenBodyparts.Count; i++)
				{
					Rigidbody val = _frozenBodyparts[i];
					if (!((Object)(object)val == (Object)null))
					{
						val.isKinematic = i < _frozenKinematic.Count && _frozenKinematic[i];
						val.detectCollisions = i < _frozenDetectCollisions.Count && _frozenDetectCollisions[i];
						val.useGravity = i < _frozenUseGravity.Count && _frozenUseGravity[i];
						val.linearVelocity = Vector3.zero;
						val.angularVelocity = Vector3.zero;
					}
				}
				_frozenBodyparts.Clear();
				_frozenKinematic.Clear();
				_frozenDetectCollisions.Clear();
				_frozenUseGravity.Clear();
			}
			catch (Exception ex)
			{
				LogError("RestorePlayerPhysics", ex);
			}
		}

		private void SendNetworkBodyVisibility(bool hide)
		{
			Character playerCharacter = _playerCharacter;
			if (!((Object)(object)((playerCharacter != null) ? ((MonoBehaviourPun)playerCharacter).photonView : null) == (Object)null) && (PhotonNetwork.InRoom || PhotonNetwork.IsConnected))
			{
				ZombiePlugin.SendBodyVisibility(((MonoBehaviourPun)_playerCharacter).photonView.ViewID, hide);
			}
		}

		private void WarpPlayerToHiddenPosition()
		{
			//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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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)
			if ((Object)(object)_playerCharacter == (Object)null)
			{
				return;
			}
			try
			{
				Vector3 val = (_hiddenBodyPos = _playerCharacter.Center + Vector3.down * GetHiddenBodyDepth());
				_hiddenBodyPosSet = true;
				ResetPlayerBodyFallState(val);
				SetCharacterPositionImmediate(_playerCharacter, val, ((Component)_playerCharacter).transform.rotation);
				LogInfo($"Player body stashed underground ({val.y:F0}m).");
			}
			catch (Exception ex)
			{
				LogError("WarpPlayerToHiddenPosition", ex);
			}
		}

		private void ResetPlayerBodyFallState(Vector3 groundPosition)
		{
			//IL_007e: 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)
			if ((Object)(object)_playerCharacter?.data == (Object)null)
			{
				return;
			}
			try
			{
				CharacterData data = _playerCharacter.data;
				data.dead = false;
				data.zombified = false;
				data.passedOut = false;
				data.fullyPassedOut = false;
				data.fallSeconds = 0f;
				data.deathTimer = 0f;
				data.currentRagdollControll = 1f;
				data.isGrounded = true;
				data.isJumping = false;
				data.sinceGrounded = 0f;
				data.groundPos = groundPosition;
				data.sinceJump = 0f;
			}
			catch (Exception ex)
			{
				LogError("ResetPlayerBodyFallState", ex);
			}
		}

		private static void SetCharacterPositionImmediate(Character character, Vector3 position, Quaternion rotation)
		{
			//IL_0009: 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_0021: 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_0033: 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_002a: 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_0043: 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_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_0050: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//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_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: 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)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_0105: 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_0112: 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_0142: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || !IsFiniteVector(position))
			{
				return;
			}
			try
			{
				Transform transform = ((Component)character).transform;
				Quaternion rotation2 = transform.rotation;
				if (!IsFiniteQuaternion(rotation))
				{
					rotation = rotation2;
				}
				Vector3 val = character.Center;
				if (!IsFiniteVector(val))
				{
					val = transform.position;
				}
				Quaternion val2 = rotation * Quaternion.Inverse(rotation2);
				Vector3 val3 = position - val;
				transform.SetPositionAndRotation(transform.position + val3, rotation);
				if (character.refs?.ragdoll?.partList == null)
				{
					return;
				}
				foreach (Bodypart part in character.refs.ragdoll.partList)
				{
					if ((Object)(object)part == (Object)null)
					{
						continue;
					}
					if ((Object)(object)part.Rig != (Object)null)
					{
						Vector3 position2 = part.Rig.position;
						part.Rig.position = position + val2 * (position2 - val);
						part.Rig.rotation = val2 * part.Rig.rotation;
						if (!part.Rig.isKinematic)
						{
							part.Rig.linearVelocity = Vector3.zero;
							part.Rig.angularVelocity = Vector3.zero;
						}
					}
					else
					{
						Vector3 position3 = part.transform.position;
						part.transform.position = position + val2 * (position3 - val);
						part.transform.rotation = val2 * part.transform.rotation;
					}
				}
			}
			catch (Exception ex)
			{
				LogError("SetCharacterPositionImmediate", ex);
			}
		}

		private void HidePlayerBody()
		{
			if ((Object)(object)_playerCharacter == (Object)null || _playerCharacter.refs == null || !ZombiePlugin.HidePlayerBody.Value)
			{
				return;
			}
			_playerRenderers.Clear();
			_playerRendererStates.Clear();
			try
			{
				Renderer[] componentsInChildren = ((Component)_playerCharacter).GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null))
					{
						_playerRenderers.Add(val);
						_playerRendererStates.Add(val.enabled);
						val.enabled = false;
						val.forceRenderingOff = true;
						SetRendererMaterialFloat(val, "_VertexGhost", 1f);
						SetRendererMaterialFloat(val, "_Opacity", 0f);
						SetRendererMaterialFloat(val, "_Alpha", 0f);
					}
				}
				_playerLights.Clear();
				_playerLightStates.Clear();
				Light[] componentsInChildren2 = ((Component)_playerCharacter).GetComponentsInChildren<Light>(true);
				foreach (Light val2 in componentsInChildren2)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						_playerLights.Add(val2);
						_playerLightStates.Add(((Behaviour)val2).enabled);
						((Behaviour)val2).enabled = false;
					}
				}
				_playerBodyHidden = true;
			}
			catch (Exception ex)
			{
				LogError("HidePlayerBody", ex);
			}
		}

		private void RestorePlayerBody()
		{
			if (_playerBodyHidden)
			{
				try
				{
					for (int i = 0; i < _playerRenderers.Count && i < _playerRendererStates.Count; i++)
					{
						Renderer val = _playerRenderers[i];
						if (!((Object)(object)val == (Object)null))
						{
							val.enabled = _playerRendererStates[i];
							val.forceRenderingOff = false;
							if (val.enabled)
							{
								SetRendererMaterialFloat(val, "_VertexGhost", 0f);
								SetRendererMaterialFloat(val, "_Opacity", 1f);
								SetRendererMaterialFloat(val, "_Alpha", 1f);
							}
						}
					}
				}
				catch (Exception ex)
				{
					LogError("RestorePlayerBody", ex);
				}
				_playerRenderers.Clear();
				_playerRendererStates.Clear();
				_playerBodyHidden = false;
			}
			try
			{
				for (int j = 0; j < _playerLights.Count && j < _playerLightStates.Count; j++)
				{
					Light val2 = _playerLights[j];
					if ((Object)(object)val2 != (Object)null)
					{
						((Behaviour)val2).enabled = _playerLightStates[j];
					}
				}
				_playerLights.Clear();
				_playerLightStates.Clear();
			}
			catch (Exception ex2)
			{
				LogError("RestorePlayerBody lights", ex2);
			}
			try
			{
				if ((Object)(object)_playerCharacter != (Object)null && _playerCharacter.refs != null && (Object)(object)_playerCharacter.refs.customization != (Object)null)
				{
					_playerCharacter.refs.customization.ShowAllRenderers();
					if ((Object)(object)_playerCharacter.refs.customization.refs != (Object)null)
					{
						_playerCharacter.refs.customization.refs.SetMushroomMan(false);
					}
				}
				if ((Object)(object)_playerCharacter != (Object)null && _playerCharacter.refs != null && (Object)(object)_playerCharacter.refs.hideTheBody != (Object)null)
				{
					_playerCharacter.refs.hideTheBody.Refresh();
				}
			}
			catch (Exception ex3)
			{
				LogError("RestorePlayerBodyPresentation", ex3);
			}
		}

		private static void SetRendererMaterialFloat(Renderer renderer, string propertyName, float value)
		{
			if ((Object)(object)renderer == (Object)null)
			{
				return;
			}
			try
			{
				Material[] materials = renderer.materials;
				bool flag = false;
				for (int i = 0; i < materials.Length; i++)
				{
					if (!((Object)(object)materials[i] == (Object)null) && materials[i].HasProperty(propertyName))
					{
						materials[i].SetFloat(propertyName, value);
						flag = true;
					}
				}
				if (flag)
				{
					renderer.materials = materials;
				}
			}
			catch
			{
			}
		}

		internal static bool IsControlledZombieHideTheBody(HideTheBody hideTheBody, Character fallbackCharacter)
		{
			if ((Object)(object)hideTheBody == (Object)null)
			{
				return false;
			}
			Character activeZombieCharacter = ActiveZombieCharacter;
			if ((Object)(object)activeZombieCharacter != (Object)null)
			{
				if ((Object)(object)fallbackCharacter != (Object)null && (Object)(object)fallbackCharacter == (Object)(object)activeZombieCharacter)
				{
					return true;
				}
				try
				{
					Character componentInParent = ((Component)hideTheBody).GetComponentInParent<Character>();
					if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent == (Object)(object)activeZombieCharacter)
					{
						return true;
					}
				}
				catch
				{
				}
			}
			try
			{
				Character componentInParent2 = ((Component)hideTheBody).GetComponentInParent<Character>();
				if ((Object)(object)componentInParent2 == (Object)null)
				{
					return false;
				}
				if ((Object)(object)fallbackCharacter != (Object)null && IsNetworkZombieCharacter(fallbackCharacter))
				{
					return true;
				}
				return IsNetworkZombieCharacter(componentInParent2);
			}
			catch
			{
				return false;
			}
		}

		internal static bool IsNetworkZombieCharacter(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			try
			{
				PhotonView componentInParent = ((Component)character).GetComponentInParent<PhotonView>();
				object[] array = (((Object)(object)componentInParent != (Object)null) ? componentInParent.InstantiationData : null);
				return array != null && array.Length != 0 && array[0] is string text && text == "ImZombie.Visual";
			}
			catch
			{
				return false;
			}
		}

		internal static void RevealHideTheBody(HideTheBody hideTheBody)
		{
			if ((Object)(object)hideTheBody == (Object)null)
			{
				return;
			}
			try
			{
				RevealRenderer((Renderer)(object)hideTheBody.body);
				RevealRenderer(hideTheBody.headRend);
				RevealRenderer((Renderer)(object)hideTheBody.sash);
				if (hideTheBody.costumes != null)
				{
					SkinnedMeshRenderer[] costumes = hideTheBody.costumes;
					for (int i = 0; i < costumes.Length; i++)
					{
						RevealRenderer((Renderer)(object)costumes[i]);
					}
				}
				if ((Object)(object)hideTheBody.face != (Object)null)
				{
					Renderer[] componentsInChildren = ((Component)hideTheBody.face).GetComponentsInChildren<Renderer>(true);
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						RevealRenderer(componentsInChildren[i]);
					}
				}
				if ((Object)(object)hideTheBody.refs != (Object)null && hideTheBody.refs.playerHats != null)
				{
					Renderer[] componentsInChildren = hideTheBody.refs.playerHats;
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						RevealRenderer(componentsInChildren[i]);
					}
				}
			}
			catch
			{
			}
		}

		private static void RevealRenderer(Renderer renderer)
		{
			if ((Object)(object)renderer == (Object)null)
			{
				return;
			}
			try
			{
				Material sharedMaterial = renderer.sharedMaterial;
				if ((Object)(object)sharedMaterial != (Object)null && sharedMaterial.HasProperty("_VertexGhost") && sharedMaterial.GetFloat("_VertexGhost") <= 0.01f)
				{
					return;
				}
			}
			catch
			{
				return;
			}
			SetRendererMaterialFloat(renderer, "_VertexGhost", 0f);
			SetRendererMaterialFloat(renderer, "_Opacity", 1f);
			SetRendererMaterialFloat(renderer, "_Alpha", 1f);
		}

		private static void ResetPlayerState(Character character, Vector3 restorePosition)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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)
			if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null)
			{
				return;
			}
			try
			{
				CharacterData data = character.data;
				data.dead = false;
				data.zombified = false;
				data.passedOut = false;
				data.fullyPassedOut = false;
				data.fallSeconds = 0f;
				data.deathTimer = 0f;
				data.currentRagdollControll = 1f;
				data.isSprinting = false;
				data.isCrouching = false;
				character.isZombie = false;
				data.isGrounded = false;
				data.groundedFor = 0f;
				data.sinceGrounded = 0f;
				data.groundPos = restorePosition;
				data.isJumping = false;
				data.sinceJump = 0f;
				data.avarageVelocity = Vector3.zero;
				data.avarageLastFrameVelocity = Vector3.zero;
				data.sincePalJump = 10f;
				data.sinceStandOnPlayer = 10f;
				data.lastStoodOnPlayer = null;
				data.launchedByCannon = false;
			}
			catch (Exception ex)
			{
				LogError("ResetPlayerState", ex);
			}
		}

		private void ClearPlayerInput()
		{
			//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_0130: 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)
			if (!((Object)(object)_playerCharacter == (Object)null) && !((Object)(object)_playerCharacter.input == (Object)null))
			{
				_playerCharacter.input.movementInput = Vector2.zero;
				_playerCharacter.input.jumpWasPressed = false;
				_playerCharacter.input.jumpIsPressed = false;
				_playerCharacter.input.sprintIsPressed = false;
				_playerCharacter.input.sprintWasPressed = false;
				_playerCharacter.input.sprintToggleWasPressed = false;
				_playerCharacter.input.usePrimaryWasPressed = false;
				_playerCharacter.input.usePrimaryIsPressed = false;
				_playerCharacter.input.useSecondaryWasPressed = false;
				_playerCharacter.input.useSecondaryIsPressed = false;
				_playerCharacter.input.crouchWasPressed = false;
				_playerCharacter.input.crouchIsPressed = false;
				_playerCharacter.input.crouchToggleWasPressed = false;
				_playerCharacter.input.interactWasPressed = false;
				_playerCharacter.input.interactIsPressed = false;
				_playerCharacter.input.lookInput = Vector2.zero;
			}
		}

		private void DestroyZombie()
		{
			DeactivateZombieForDeferredDestroy();
			DestroyDeactivatedZombie();
		}

		private void DeactivateZombieForDeferredDestroy()
		{
			if ((Object)(object)_mushroomZombie != (Object)null)
			{
				ZombieHarmonyPatches.ClearAttackMouth(_mushroomZombie);
			}
			try
			{
				AudioSource val = (((Object)(object)_mushroomZombie != (Object)null) ? _mushroomZombie.gruntSource : null);
				if ((Object)(object)val != (Object)null && val.isPlaying)
				{
					val.Stop();
				}
			}
			catch
			{
			}
			if ((Object)(object)_zombieRoot != (Object)null)
			{
				_pendingDestroyRoot = _zombieRoot;
				_pendingDestroyNetworked = _zombieIsNetworked;
				try
				{
					_zombieRoot.SetActive(false);
				}
				catch
				{
				}
			}
			_zombieRoot = null;
			_zombieCharacter = null;
			_mushroomZombie = null;
			_zombiePhotonView = null;
			_zombieIsNetworked = false;
		}

		private void DestroyDeactivatedZombie()
		{
			GameObject pendingDestroyRoot = _pendingDestroyRoot;
			_pendingDestroyRoot = null;
			if ((Object)(object)pendingDestroyRoot == (Object)null)
			{
				return;
			}
			try
			{
				if (_pendingDestroyNetworked && PhotonNetwork.InRoom)
				{
					PhotonNetwork.Destroy(pendingDestroyRoot);
				}
				else
				{
					Object.Destroy((Object)(object)pendingDestroyRoot);
				}
			}
			catch (Exception ex)
			{
				LogError("DestroyDeactivatedZombie", ex);
			}
		}

		private void Update()
		{
			if (!Active || (Object)(object)_zombieCharacter == (Object)null)
			{
				return;
			}
			try
			{
				ClearPlayerInput();
				KeepZombieAlive();
				PinHiddenBody();
				if (Time.unscaledTime >= _nextBodyVisibilityRebroadcast)
				{
					_nextBodyVisibilityRebroadcast = Time.unscaledTime + 5f;
					SendNetworkBodyVisibility(hide: true);
				}
				DriveZombieInput();
				UpdateAttack();
				if (!Active)
				{
					return;
				}
				if (_localCharacterSwapped && (Object)(object)Character.localCharacter != (Object)(object)_zombieCharacter)
				{
					try
					{
						Character.localCharacter = _zombieCharacter;
					}
					catch
					{
					}
				}
				if (IsCharacterClimbing())
				{
					StabilizeControlledClimb();
				}
				EnsureClimbSurfaceStillValid();
				LogAnimatorDiagnostics();
				HideHud();
			}
			catch (Exception ex)
			{
				LogError("Update", ex);
			}
		}

		private void FixedUpdate()
		{
			if (!Active || (Object)(object)_zombieCharacter == (Object)null || _zombieCharacter.refs == null || (Object)(object)_zombieCharacter.refs.ragdoll == (Object)null)
			{
				return;
			}
			try
			{
				if (IsCharacterClimbing())
				{
					StabilizeControlledClimb();
				}
				if (_jumpQueued && !ViewIsMine())
				{
					_jumpQueued = false;
					if (_zombieCharacter.data.isGrounded && _zombieCharacter.data.jumpsRemaining > 0)
					{
						ApplyJumpImpulse();
					}
				}
			}
			catch (Exception ex)
			{
				LogError("FixedUpdate", ex);
			}
		}

		private void ApplyJumpImpulse()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			float value = ZombiePlugin.JumpForce.Value;
			foreach (Bodypart part in _zombieCharacter.refs.ragdoll.partList)
			{
				Rigidbody val = ((part != null) ? part.Rig : null);
				if (!((Object)(object)val == (Object)null) && !val.isKinematic)
				{
					Vector3 linearVelocity = val.linearVelocity;
					linearVelocity.y = value;
					val.linearVelocity = linearVelocity;
				}
			}
			CharacterData data = _zombieCharacter.data;
			data.jumpsRemaining--;
			_zombieCharacter.data.sinceJump = 0f;
		}

		private void LateUpdate()
		{
			if (!Active || (Object)(object)_zombieCharacter == (Object)null)
			{
				return;
			}
			try
			{
				PinHiddenBody();
				SyncCharacterData();
				if ((Object)(object)_mushroomZombie != (Object)null)
				{
					ZombieHarmonyPatches.UpdateControlledMouth(_mushroomZombie);
				}
				RefreshCamera();
			}
			catch (Exception ex)
			{
				LogError("LateUpdate", ex);
			}
		}

		private void DriveZombieInput()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0054: 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_00f5: 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)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Invalid comparison between Unknown and I4
			if ((Object)(object)_zombieCharacter.input == (Object)null)
			{
				return;
			}
			_zombieCharacter.input.lookInput = ReadLookDelta();
			Vector2 val = GetMovementInput();
			bool flag = Input.GetKey(ZombiePlugin.JumpKey.Value);
			bool sprintIsPressed = Input.GetKey(ZombiePlugin.SprintKey.Value);
			bool key = Input.GetKey(ZombiePlugin.CrouchKey.Value);
			bool flag2 = (int)ZombiePlugin.AttackKey.Value != 0 && Input.GetKey(ZombiePlugin.AttackKey.Value);
			bool num = flag && !_lastJumpPressed;
			bool flag3 = flag2 && !_lastAttackPressed;
			_lastJumpPressed = flag;
			_lastAttackPressed = flag2;
			bool flag4 = _zombieCharacter.data.fallSeconds > 0f;
			bool flag5 = IsCharacterClimbing();
			if (_attacking)
			{
				((Vector2)(ref val))..ctor(0f, 1.2f);
				sprintIsPressed = true;
				flag = false;
			}
			else if (flag5)
			{
				val.y = Mathf.Max(val.y, 1f);
				sprintIsPressed = false;
				flag = false;
				flag3 = false;
			}
			else if (flag4)
			{
				val = Vector2.zero;
				sprintIsPressed = false;
				flag = false;
			}
			if (!_attacking && !flag4 && (Object)(object)_mushroomZombie != (Object)null && (int)_mushroomZombie.currentState == 5)
			{
				_mushroomZombie.currentState = (State)2;
			}
			_zombieCharacter.input.movementInput = val;
			_zombieCharacter.input.jumpIsPressed = flag && !_attacking && !flag4;
			bool flag6 = num && !_attacking && !flag4;
			if (ViewIsMine())
			{
				_zombieCharacter.input.jumpWasPressed = flag6;
				_jumpQueued = false;
			}
			else
			{
				_zombieCharacter.input.jumpWasPressed = false;
				if (flag6)
				{
					_jumpQueued = true;
				}
			}
			_zombieCharacter.input.sprintIsPressed = sprintIsPressed;
			_zombieCharacter.input.crouchIsPressed = key && !_attacking && !flag4;
			if (!ViewIsMine())
			{
				_zombieCharacter.data.isSprinting = _zombieCharacter.input.sprintIsPressed;
				_zombieCharacter.data.isCrouching = _zombieCharacter.input.crouchIsPressed && _zombieCharacter.data.isGrounded;
			}
			if (flag3 && !_attacking && !flag4 && Time.unscaledTime - _lastAttackTime >= ZombiePlugin.AttackCooldown.Value)
			{
				StartAttack();
			}
			SyncPlayerStamina();
			ForwardClimbInput();
		}

		private void SyncPlayerStamina()
		{
			if ((Object)(object)_playerCharacter?.data == (Object)null || (Object)(object)_zombieCharacter?.data == (Object)null)
			{
				return;
			}
			try
			{
				_playerCharacter.data.currentStamina = _zombieCharacter.data.currentStamina;
			}
			catch (Exception ex)
			{
				LogError("SyncPlayerStamina", ex);
			}
		}

		private bool IsCharacterClimbing()
		{
			if ((Object)(object)_zombieCharacter?.data != (Object)null)
			{
				return _zombieCharacter.data.isClimbing;
			}
			return false;
		}

		private bool IsInClimbReleaseFall()
		{
			return Time.time < _climbReleaseFallUntil;
		}

		private bool IsClimbInputHeld()
		{
			try
			{
				return Input.GetKey((KeyCode)323);
			}
			catch
			{
				return false;
			}
		}

		private void ForwardClimbInput()
		{
			if ((Object)(object)_zombieCharacter?.input == (Object)null || (Object)(object)_zombieCharacter.data == (Object)null || (Object)(object)_zombieCharacter.refs?.climbing == (Object)null)
			{
				return;
			}
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			try
			{
				flag = Input.GetKeyDown((KeyCode)323);
				flag2 = Input.GetKey((KeyCode)323);
				flag3 = Input.GetKeyUp((KeyCode)323);
			}
			catch
			{
			}
			_zombieCharacter.input.usePrimaryWasPressed = flag;
			_zombieCharacter.input.usePrimaryIsPressed = flag2 || flag;
			if (flag2 || flag)
			{
				try
				{
					if ((Object)(object)_zombieCharacter.data.currentItem == (Object)null)
					{
						_zombieCharacter.data.sincePressClimb = 0f;
					}
				}
				catch
				{
				}
				if (!IsCharacterClimbing() && (flag || Time.time >= _nextClimbAttemptTime))
				{
					_nextClimbAttemptTime = Time.time + 0.08f;
					TryStartLocalClimb();
				}
			}
			if (flag3)
			{
				_zombieCharacter.input.usePrimaryIsPressed = false;
				_zombieCharacter.input.usePrimaryWasReleased = true;
				_hasLastClimbStart = false;
				if (IsCharacterClimbing())
				{
					StopControlledZombieClimb(1.25f);
				}
			}
			else
			{
				_zombieCharacter.input.usePrimaryWasReleased = false;
			}
		}

		private bool TryStartLocalClimb()
		{
			//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_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_00d4: 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_00e9: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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)
			if ((Object)(object)_zombieCharacter == (Object)null || (Object)(object)_zombieCharacter.data == (Object)null || (Object)(object)_zombieCharacter.refs?.climbing == (Object)null)
			{
				return false;
			}
			if (_zombieCharacter.data.isClimbing || _zombieCharacter.data.isRopeClimbing || _zombieCharacter.data.isVineClimbing)
			{
				return true;
			}
			if ((Object)(object)_zombieCharacter.data.currentItem != (Object)null)
			{
				return false;
			}
			CharacterClimbing climbing = _zombieCharacter.refs.climbing;
			if (!CanControlledZombieClimb(climbing))
			{
				return false;
			}
			Vector3 center = _zombieCharacter.Center;
			Vector3 climbForward = GetClimbForward();
			if (((Vector3)(ref climbForward)).sqrMagnitude < 0.0001f)
			{
				return false;
			}
			if (!TryFindLocalClimbHit(center, climbForward, 1.65f, out var climbHit))
			{
				return false;
			}
			if (IsRepeatedClimbStart(((RaycastHit)(ref climbHit)).point, ((RaycastHit)(ref climbHit)).normal))
			{
				return false;
			}
			bool num = TryStartControlledZombieClimb(climbing, _zombieCharacter, ((RaycastHit)(ref climbHit)).point, ((RaycastHit)(ref climbHit)).normal);
			if (num)
			{
				RecordClimbStart(((RaycastHit)(ref climbHit)).point, ((RaycastHit)(ref climbHit)).normal);
				if ((Object)(object)_zombieCharacter.input != (Object)null)
				{
					_zombieCharacter.input.jumpWasPressed = false;
					_zombieCharacter.input.jumpIsPressed = false;
				}
			}
			return num;
		}

		private Vector3 GetClimbForward()
		{
			//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)
			//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_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_00d7: 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_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_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)
			Vector3 val = Vector3.zero;
			Camera climbCamera = GetClimbCamera();
			if ((Object)(object)climbCamera != (Object)null)
			{
				val = ((Component)climbCamera).transform.forward;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && (Object)(object)_zombieCharacter != (Object)null)
			{
				val = ((Component)_zombieCharacter).transform.forward;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && (Object)(object)_zombieCharacter?.data != (Object)null)
			{
				val = _zombieCharacter.data.lookDirection;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && (Object)(object)_zombieCharacter?.data != (Object)null)
			{
				val = _zombieCharacter.data.lookDirection_Flat;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				val = Vector3.forward;
			}
			return ((Vector3)(ref val)).normalized;
		}

		private Camera GetClimbCamera()
		{
			try
			{
				if ((Object)(object)Camera.main != (Object)null)
				{
					return Camera.main;
				}
			}
			catch
			{
			}
			return null;
		}

		private bool CanControlledZombieClimb(CharacterClimbing climbing)
		{
			if ((Object)(object)climbing == (Object)null)
			{
				return false;
			}
			try
			{
				if (ClimbCanClimbMethod != null)
				{
					object obj = ClimbCanClimbMethod.Invoke(climbing, null);
					if (obj is bool)
					{
						return (bool)obj;
					}
				}
			}
			catch
			{
			}
			return true;
		}

		private bool TryStartControlledZombieClimb(CharacterClimbing climbing, Character character, Vector3 climbPos, Vector3 climbNormal)
		{
			//IL_0031: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0121: 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_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: 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)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)climbing == (Object)null)
			{
				return false;
			}
			try
			{
				PhotonView val = ((character != null) ? ((MonoBehaviourPun)character).photonView : null);
				if ((Object)(object)val != (Object)null)
				{
					val.RPC("StartClimbRpc", (RpcTarget)0, new object[2] { climbPos, climbNormal });
				}
				else
				{
					if (ClimbStartClimbRpcMethod == null)
					{
						LogInfo("Climb: StartClimbRpc unavailable.");
						return false;
					}
					object[] array = BuildClimbRpcArguments(ClimbStartClimbRpcMethod, climbPos, climbNormal);
					if (array == null)
					{
						return false;
					}
					ClimbStartClimbRpcMethod.Invoke(climbing, array);
				}
				ClimbClimbToggledOnField?.SetValue(climbing, false);
				ClimbPlayerSlideField?.SetValue(climbing, Vector2.zero);
				ClimbSinceLastClimbStartedField?.SetValue(climbing, 0f);
				if ((Object)(object)character?.data != (Object)null)
				{
					_nextClimbAttemptTime = Time.time + 0.08f;
					character.data.climbPos = climbPos;
					character.data.climbNormal = ((((Vector3)(ref climbNormal)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref climbNormal)).normalized : Vector3.zero);
					character.data.sincePressClimb = 0f;
					character.data.sinceCanClimb = 0f;
					character.data.sinceGrounded = 0f;
					character.data.fallSeconds = 0f;
					character.data.passedOut = false;
					character.data.fullyPassedOut = false;
					character.data.avarageVelocity = Vector3.zero;
					character.data.avarageLastFrameVelocity = Vector3.zero;
					character.data.worldMovementInput_Grounded = Vector3.zero;
				}
				return true;
			}
			catch (Exception ex)
			{
				LogError("TryStartControlledZombieClimb", ex);
				return false;
			}
		}

		private void StopControlledZombieClimb(float setFall)
		{
			//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_0185: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_zombieCharacter?.data == (Object)null)
			{
				return;
			}
			try
			{
				PhotonView photonView = ((MonoBehaviourPun)_zombieCharacter).photonView;
				if ((Object)(object)photonView != (Object)null)
				{
					photonView.RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { setFall });
				}
			}
			catch
			{
			}
			_zombieCharacter.data.isClimbing = false;
			_zombieCharacter.data.isRopeClimbing = false;
			_zombieCharacter.data.isVineClimbing = false;
			_zombieCharacter.data.isJumping = false;
			_zombieCharacter.data.sinceGrounded = setFall;
			_zombieCharacter.data.sinceClimb = 999f;
			_zombieCharacter.data.sinceCanClimb = 0f;
			_zombieCharacter.data.sincePressClimb = 1f;
			_zombieCharacter.data.climbNormal = Vector3.zero;
			_climbReleaseFallUntil = Time.time + 0.7f;
			_nextClimbAttemptTime = Time.time + 0.08f;
			if ((Object)(object)_zombieCharacter.input != (Object)null)
			{
				_zombieCharacter.input.usePrimaryIsPressed = false;
				_zombieCharacter.input.usePrimaryWasPressed = false;
				_zombieCharacter.input.usePrimaryWasReleased = true;
			}
			try
			{
				ClimbPlayerSlideField?.SetValue(_zombieCharacter.refs?.climbing, Vector2.zero);
				ClimbClimbToggledOnField?.SetValue(_zombieCharacter.refs?.climbing, false);
				ClimbSinceLastClimbStartedField?.SetValue(_zombieCharacter.refs?.climbing, 999f);
			}
			catch
			{
			}
		}

		private void StabilizeControlledClimb()
		{
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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_0148: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_zombieCharacter?.data == (Object)null)
			{
				return;
			}
			try
			{
				_zombieCharacter.data.currentRagdollControll = 0.95f;
				_zombieCharacter.data.fallSeconds = 0f;
				_zombieCharacter.data.passedOut = false;
				_zombieCharacter.data.fullyPassedOut = false;
				_zombieCharacter.data.isGrounded = false;
				_zombieCharacter.data.sinceGrounded = 0f;
				_zombieCharacter.data.sinceCanClimb = 0f;
				_zombieCharacter.data.sincePressClimb = 0f;
			}
			catch
			{
			}
			if (_zombieCharacter.refs?.ragdoll?.partList == null)
			{
				return;
			}
			try
			{
				foreach (Bodypart part in _zombieCharacter.refs.ragdoll.partList)
				{
					Rigidbody val = ((part != null) ? part.Rig : null);
					if (!((Object)(object)val == (Object)null) && !val.isKinematic)
					{
						val.linearVelocity = Vector3.ClampMagnitude(val.linearVelocity, 9f);
						val.angularVelocity = Vector3.ClampMagnitude(val.angularVelocity, 8f);
					}
				}
			}
			catch
			{
			}
		}

		private void EnsureClimbSurfaceStillValid()
		{
			//IL_006e: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00ba: 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_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_00e2: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			if (!IsCharacterClimbing() || (Object)(object)_zombieCharacter?.refs?.climbing == (Object)null || _zombieCharacter.data.isRopeClimbing || _zombieCharacter.data.isVineClimbing)
			{
				return;
			}
			if (!IsClimbInputHeld())
			{
				StopControlledZombieClimb(1.25f);
				return;
			}
			Vector3 center = _zombieCharacter.Center;
			Vector3[] array = (Vector3[])(object)new Vector3[4]
			{
				-_zombieCharacter.data.climbNormal,
				_zombieCharacter.data.lookDirection,
				_zombieCharacter.data.lookDirection_Flat,
				((Component)_zombieCharacter).transform.forward
			};
			for (int i = 0; i < array.Length; i++)
			{
				Vector3 val = array[i];
				if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f) && TryFindLocalClimbHit(center, ((Vector3)(ref val)).normalized, 2.25f, out var _))
				{
					_zombieCharacter.data.sinceCanClimb = 0f;
					return;
				}
			}
			StopControlledZombieClimb(1.25f);
		}

		private bool TryFindLocalClimbHit(Vector3 origin, Vector3 direction, float distance, out RaycastHit climbHit)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_00af: 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)
			climbHit = default