Decompiled source of PEAK Transform v0.9.10

plugins/Thanks.Transform.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using ImCritter;
using ImGhost;
using ImScoutmaster;
using ImTornado;
using ImTumbleweed;
using ImZombie;
using Microsoft.CodeAnalysis;
using Peak;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using Transform.Core;
using Transform.Statue;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Thanks.Transform")]
[assembly: AssemblyDescription("Unified transformation mod for PEAK: mushroom zombie, scoutmaster, ghost, tumbleweed, tornado and petrified scout statue forms with an in-game menu.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Thanks")]
[assembly: AssemblyProduct("Thanks.Transform")]
[assembly: AssemblyCopyright("Copyright © Thanks 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyFileVersion("0.9.10")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.9.10.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;
		}
	}
}
internal static class TransformState
{
	internal static bool MenuOpen;

	internal static bool AnyFormActive;
}
namespace ImCritter
{
	internal static class CritterPlugin
	{
		public const string Id = "com.github.Thanks.Transform.Critter";

		public const string Name = "Critter Forms";

		public const string Version = "0.9.10";

		private const float OldFrogJumpPowerDefault = 1.6f;

		private const float PreviousFrogJumpPowerDefault = 0.85f;

		private const float NewFrogJumpPowerDefault = 1.2f;

		internal const string ModPlayerProperty = "ImCritter.Mod";

		internal static ManualLogSource Log;

		private static Harmony _harmony;

		private static CritterController _controller;

		private static bool _switching;

		private static bool _initialized;

		private static bool _advertised;

		internal static ConfigEntry<bool> UnmoddedRoomSupport;

		internal static ConfigEntry<KeyCode> JumpKey;

		internal static ConfigEntry<KeyCode> AttackKey;

		private static ConfigEntry<float>[] _movementForce = new ConfigEntry<float>[6];

		private static ConfigEntry<float>[] _sprintMultiplier = new ConfigEntry<float>[6];

		private static ConfigEntry<float>[] _maxSpeed = new ConfigEntry<float>[6];

		private static ConfigEntry<float>[] _jumpSpeed = new ConfigEntry<float>[6];

		private static ConfigEntry<float>[] _jumpPower = new ConfigEntry<float>[6];

		private static ConfigEntry<float>[] _attackCooldown = new ConfigEntry<float>[6];

		private static ConfigEntry<float>[] _cameraDistance = new ConfigEntry<float>[6];

		private static ConfigEntry<float>[] _cameraHeight = new ConfigEntry<float>[6];

		private static ConfigEntry<float>[] _cameraFov = new ConfigEntry<float>[6];

		internal static bool IsActive
		{
			get
			{
				if ((Object)(object)_controller != (Object)null)
				{
					return _controller.Active;
				}
				return false;
			}
		}

		internal static CritterKind ActiveKind
		{
			get
			{
				if (!((Object)(object)_controller != (Object)null) || !_controller.Active)
				{
					return (CritterKind)(-1);
				}
				return _controller.Kind;
			}
		}

		internal static ConfigEntry<float> MovementForce(CritterKind kind)
		{
			return _movementForce[(int)kind];
		}

		internal static ConfigEntry<float> SprintMultiplier(CritterKind kind)
		{
			return _sprintMultiplier[(int)kind];
		}

		internal static ConfigEntry<float> MaxSpeed(CritterKind kind)
		{
			return _maxSpeed[(int)kind];
		}

		internal static ConfigEntry<float> JumpSpeed(CritterKind kind)
		{
			return _jumpSpeed[(int)kind];
		}

		internal static ConfigEntry<float> JumpPower(CritterKind kind)
		{
			return _jumpPower[(int)kind];
		}

		internal static ConfigEntry<float> AttackCooldown(CritterKind kind)
		{
			return _attackCooldown[(int)kind];
		}

		internal static ConfigEntry<float> CameraDistance(CritterKind kind)
		{
			return _cameraDistance[(int)kind];
		}

		internal static ConfigEntry<float> CameraHeight(CritterKind kind)
		{
			return _cameraHeight[(int)kind];
		}

		internal static ConfigEntry<float> CameraFov(CritterKind kind)
		{
			return _cameraFov[(int)kind];
		}

		private static string Section(CritterKind kind)
		{
			return kind switch
			{
				CritterKind.Frog => "Frog", 
				CritterKind.Beetle => "Beetle", 
				CritterKind.Scorpion => "Scorpion", 
				CritterKind.Coconut => "Coconut", 
				CritterKind.Bomb => "Bomb", 
				CritterKind.Cactus => "Cactus", 
				_ => "Critter", 
			};
		}

		internal static void Initialize(ConfigFile config, ManualLogSource log)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if (!_initialized)
			{
				_initialized = true;
				Log = log;
				_harmony = new Harmony("com.github.Thanks.Transform.Critter");
				_harmony.PatchAll(typeof(CritterHarmonyPatches));
				TryPatchFrogActionGuard();
				TryPatchBombFlareGuard();
				ConfigureOptionalEndgamePatches();
				BindConfig(config);
				SceneManager.sceneLoaded += OnSceneLoaded;
				Log.LogInfo((object)"[Critter] Module loaded (frog, beetle, scorpion, coconut and bomb forms).");
			}
		}

		private static void TryPatchFrogActionGuard()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(FrogTongue), "RPCA_FrogAction", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"[Critter] RPCA_FrogAction not found; frog AI guard skipped.");
					}
					return;
				}
				bool flag = methodInfo.GetParameters().Any((ParameterInfo p) => p.ParameterType == typeof(PhotonMessageInfo));
				string text = (flag ? "FrogActionGuardWithInfo" : "FrogActionGuard");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(CritterHarmonyPatches), text, (Type[])null, (Type[])null);
				if (methodInfo2 == null)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("[Critter] Prefix " + text + " not found; frog AI guard skipped."));
					}
					return;
				}
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogInfo((object)("[Critter] FrogActionGuard installed (" + text + ", PhotonMessageInfo=" + flag + ")."));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = Log;
				if (log4 != null)
				{
					log4.LogWarning((object)("[Critter] FrogActionGuard patch failed: " + ex.Message));
				}
			}
		}

		private static void TryPatchBombFlareGuard()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Dynamite), "SetFlareLitRPC", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"[Critter] Dynamite.SetFlareLitRPC not found; bomb fuse guard skipped.");
					}
					return;
				}
				bool flag = methodInfo.GetParameters().Any((ParameterInfo p) => p.ParameterType == typeof(PhotonMessageInfo));
				string text = (flag ? "BombFlareLitGuardWithInfo" : "BombFlareLitGuard");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(CritterHarmonyPatches), text, (Type[])null, (Type[])null);
				if (methodInfo2 == null)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("[Critter] Prefix " + text + " not found; bomb fuse guard skipped."));
					}
					return;
				}
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogInfo((object)("[Critter] Bomb flare guard installed (" + text + ", PhotonMessageInfo=" + flag + ")."));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = Log;
				if (log4 != null)
				{
					log4.LogWarning((object)("[Critter] Bomb flare guard patch failed: " + ex.Message));
				}
			}
		}

		private static void ConfigureOptionalEndgamePatches()
		{
			PatchUtility.TryPatchOptionalMethod(_harmony, Log, "Critter", typeof(Character), "RPCEndGame", Type.EmptyTypes, typeof(CritterHarmonyPatches), "CharacterRPCEndGamePrefix", "Character.RPCEndGame()");
			PatchUtility.TryPatchOptionalMethod(_harmony, Log, "Critter", typeof(GameOverHandler), "BeginAirportLoadRPC", Type.EmptyTypes, typeof(CritterHarmonyPatches), "GameOverHandlerBeginAirportLoadRPCPrefix", "GameOverHandler.BeginAirportLoadRPC()");
			PatchUtility.TryPatchOptionalMethod(_harmony, Log, "Critter", typeof(EndScreen), "ReturnToAirport", Type.EmptyTypes, typeof(CritterHarmonyPatches), "EndScreenReturnToAirportPrefix", "EndScreen.ReturnToAirport()");
		}

		private static void BindConfig(ConfigFile config)
		{
			BindKind(config, CritterKind.Frog, 14f, 14f, 12f, 9f, 6f, 1.2f);
			BindKind(config, CritterKind.Beetle, 18f, 4.5f, 7f, 6f, 7f, 1f, 1.35f);
			BindKind(config, CritterKind.Scorpion, 7.5f, 4.2f, 5f, 6f, 7f, 1f, 1.1f);
			BindKind(config, CritterKind.Coconut, 10f, 8f, 8f, 6f, 5f, 1f, 1.7f);
			BindKind(config, CritterKind.Bomb, 22f, 18f, 15.65f, 6f, 4f);
			BindKind(config, CritterKind.Cactus, 18f, 14f, 12f, 6f, 4.5f, 1f, 1.8f);
			MigrateCritterDefaults();
			UnmoddedRoomSupport = config.Bind<bool>("Critter", "UnmoddedRoomSupport", true, "In rooms with unmodded players: pin the critter to the rider's real position on every remote client (vanilla Item.SetKinematicAndResetSyncData RPC) and broadcast the vanilla mob state (Mob.RPC_SyncMobState) so their copies stay controllable and never run the wildlife AI. The owner's local physics feel is unchanged. An unmodded MASTER client's own copy can still fire one AI tongue action — that cannot be patched remotely; the owner's client ignores it, and the pin pulls the visual back within a tick.");
			JumpKey = config.Bind<KeyCode>("Critter Controls", "JumpKey", (KeyCode)32, "Press to hop/jump while in a critter form (frog leap, beetle/scorpion hop). Bind to a controller button (JoystickButtonN) for gamepad play.");
			AttackKey = config.Bind<KeyCode>("Critter Controls", "AttackKey", (KeyCode)324, "Press to attack/charge while in a critter form (beetle ram, scorpion sting, coconut slam). Defaults to right mouse; bind to a controller button (JoystickButtonN) for gamepad.");
		}

		private static void MigrateCritterDefaults()
		{
			ConfigEntry<float> val = _jumpPower[0];
			if (val != null && (Mathf.Abs(val.Value - 1.6f) <= 0.001f || Mathf.Abs(val.Value - 0.85f) <= 0.001f))
			{
				val.Value = 1.2f;
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)"[Critter] Migrated frog JumpPower to 1.2 for direct launch-speed frog jumping.");
				}
			}
			MigrateIfDefault(_jumpSpeed[0], 6f, 12f, "Frog JumpSpeed");
			MigrateIfDefault(_sprintMultiplier[1], 2f, 1.5f, "Beetle SprintMultiplier");
			MigrateIfDefault(_movementForce[2], 14f, 10f, "Scorpion MovementForce");
			MigrateIfDefault(_maxSpeed[2], 13f, 5.5f, "Scorpion MaxSpeed");
			MigrateIfDefault(_jumpSpeed[2], 6f, 5f, "Scorpion JumpSpeed");
			MigrateIfDefault(_sprintMultiplier[2], 2f, 1.15f, "Scorpion SprintMultiplier");
			MigrateIfDefault(_movementForce[2], 10f, 7.5f, "Scorpion MovementForce");
			MigrateIfDefault(_maxSpeed[2], 5.5f, 4.2f, "Scorpion MaxSpeed");
			MigrateIfDefault(_sprintMultiplier[2], 1.15f, 1.1f, "Scorpion SprintMultiplier");
			MigrateIfDefault(_maxSpeed[1], 5f, 4.5f, "Beetle MaxSpeed");
			MigrateIfDefault(_sprintMultiplier[1], 1.5f, 1.35f, "Beetle SprintMultiplier");
			MigrateIfDefault(_movementForce[4], 10f, 22f, "Bomb MovementForce");
			MigrateIfDefault(_maxSpeed[4], 7f, 18f, "Bomb MaxSpeed");
			MigrateIfDefault(_jumpSpeed[4], 7f, 15.65f, "Bomb JumpSpeed");
			MigrateIfDefault(_sprintMultiplier[4], 1.7f, 2f, "Bomb SprintMultiplier");
		}

		private static void MigrateIfDefault(ConfigEntry<float> entry, float oldDefault, float newDefault, string label)
		{
			if (entry != null && !(Mathf.Abs(entry.Value - oldDefault) > 0.001f))
			{
				entry.Value = newDefault;
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)("[Critter] Migrated " + label + " to " + newDefault.ToString("0.##") + "."));
				}
			}
		}

		private static void BindKind(ConfigFile config, CritterKind kind, float movementForce, float maxSpeed, float jumpSpeed, float cameraDistance, float cameraHeight, float jumpPower = 1f, float sprintMultiplier = 2f)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Expected O, but got Unknown
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Expected O, but got Unknown
			string text = Section(kind);
			_movementForce[(int)kind] = config.Bind<float>(text, "MovementForce", movementForce, new ConfigDescription("How strongly WASD pushes the critter (acceleration, mass-independent). Not used by the frog (hop-only movement); beetle/scorpion use MaxSpeed for direct player control.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			_sprintMultiplier[(int)kind] = config.Bind<float>(text, "SprintMultiplier", sprintMultiplier, new ConfigDescription("Force/speed multiplier while holding the sprint key (drains the stamina bar).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
			_maxSpeed[(int)kind] = config.Bind<float>(text, "MaxSpeed", maxSpeed, new ConfigDescription("Horizontal speed cap for WASD movement. For the frog this is the horizontal leap distance/speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>()));
			_jumpSpeed[(int)kind] = config.Bind<float>(text, "JumpSpeed", jumpSpeed, new ConfigDescription("Upward hop speed for Space. For the frog this is the direct vertical launch speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			_jumpPower[(int)kind] = config.Bind<float>(text, "JumpPower", jumpPower, new ConfigDescription("Multiplier on frog direct launch speeds or hop speed for beetle/scorpion.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
			_attackCooldown[(int)kind] = config.Bind<float>(text, "AttackCooldown", 1.5f, new ConfigDescription("Seconds between attacks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			_cameraDistance[(int)kind] = config.Bind<float>(text + " Camera", "Distance", cameraDistance, new ConfigDescription("Third-person critter camera distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 20f), Array.Empty<object>()));
			_cameraHeight[(int)kind] = config.Bind<float>(text + " Camera", "Height", cameraHeight, new ConfigDescription("Third-person critter camera height above the critter.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 10f), Array.Empty<object>()));
			_cameraFov[(int)kind] = config.Bind<float>(text + " Camera", "Fov", 78f, new ConfigDescription("Field of view while in this critter form.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(60f, 110f), Array.Empty<object>()));
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			try
			{
				if (IsActive)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogInfo((object)"[Critter] Scene loaded while transformed; exiting critter form.");
					}
					ForceExit();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Critter] Exit during scene load failed: " + ex.Message));
				}
			}
		}

		internal static void Tick()
		{
			try
			{
				AdvertiseModPresence();
				if ((Object)(object)_controller != (Object)null && _controller.Active && !_controller.IsValid())
				{
					ForceExit();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("[Critter] Module.Tick: " + ex));
				}
			}
		}

		private static void AdvertiseModPresence()
		{
			ModPresence.Advertise("ImCritter.Mod", "0.9.10", ref _advertised);
		}

		internal static bool PlayerHasMod(Player player)
		{
			return ModPresence.PlayerHasMod(player, "ImCritter.Mod");
		}

		internal static bool RoomHasUnmoddedPlayers()
		{
			return ModPresence.RoomHasUnmoddedPlayers("ImCritter.Mod");
		}

		internal static IEnumerable<Player> UnmoddedRemotePlayers()
		{
			return ModPresence.UnmoddedRemotePlayers("ImCritter.Mod");
		}

		internal static bool MasterHasMod()
		{
			return ModPresence.MasterHasMod("ImCritter.Mod");
		}

		internal static void Shutdown()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			try
			{
				ForceExit();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[Critter] Exit during cleanup failed: " + ex.Message));
				}
			}
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Critter] Harmony unpatch failed: " + ex2.Message));
				}
			}
		}

		internal static bool CanEnter(Character character)
		{
			return CanTransform(character);
		}

		private static bool CanTransform(Character character)
		{
			if (IsActive)
			{
				return false;
			}
			if (!FormValidation.IsValid(Log, "Critter", FormValidation.ValidateTransformable(character)))
			{
				return false;
			}
			if (!PhotonNetwork.IsConnected && !PhotonNetwork.OfflineMode)
			{
				FormValidation.ReportFailure(Log, "Critter", "[Critter] Critter forms require a Photon room or offline mode.");
				return false;
			}
			return true;
		}

		internal static bool Enter(Character character, CritterKind kind)
		{
			if (kind == CritterKind.Cactus)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)"[Critter] Cactus form is disabled.");
				}
				return false;
			}
			if (_switching)
			{
				return false;
			}
			if (!CanTransform(character))
			{
				return false;
			}
			_switching = true;
			try
			{
				_controller = ((Component)character).gameObject.GetComponent<CritterController>();
				if ((Object)(object)_controller == (Object)null)
				{
					_controller = ((Component)character).gameObject.AddComponent<CritterController>();
				}
				return _controller.EnterCritter(character, kind);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogError((object)("[Critter] Failed to enter " + kind.ToString() + " form:\n" + ex));
				}
				_controller = null;
				return false;
			}
			finally
			{
				_switching = false;
			}
		}

		internal static void Exit()
		{
			_switching = true;
			try
			{
				_controller?.ExitCritter();
				_controller = null;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("[Critter] Failed to exit critter form: " + ex));
				}
			}
			finally
			{
				_switching = false;
			}
		}

		internal static void ForceExit()
		{
			if ((Object)(object)_controller == (Object)null)
			{
				return;
			}
			try
			{
				_controller.ExitCritter();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[Critter] ForceExit failed: " + ex.Message));
				}
			}
			_controller = null;
		}
	}
	internal enum CritterKind
	{
		Frog,
		Beetle,
		Scorpion,
		Coconut,
		Bomb,
		Cactus
	}
	[DefaultExecutionOrder(600)]
	public sealed class CritterController : MonoBehaviour
	{
		private const float CameraLookAhead = 2.5f;

		private const float CameraSmoothTime = 0.08f;

		private const float CameraRotationSharpness = 12f;

		private const float DefaultCameraDistance = 6f;

		private const float DefaultCameraHeight = 2f;

		private const float DefaultCameraFov = 78f;

		private const float JumpCooldown = 0.3f;

		private const float GroundCheckExtra = 0.4f;

		private const float VoidExitHeight = -80f;

		private const float JumpStaminaCost = 0.08f;

		private const float MinSprintStamina = 0.02f;

		private const float AttackRange = 4f;

		private const float FrogTongueMinRange = 14f;

		private const float FrogTongueAimRadius = 3.4f;

		private const float FrogGroundedVelocityEpsilon = 0.08f;

		private const float AttackInputBufferSeconds = 0.2f;

		private const float FrogTongueReadyLength = 0.08f;

		private const float FrogEmptyLickSeconds = 0.35f;

		private const float BeetleMoveAcceleration = 18f;

		private const float ScorpionMoveAcceleration = 12f;

		private const float ItemRollTorque = 16f;

		private const float CoconutMaxChargeSeconds = 1.25f;

		private const float CoconutMinSlamSpeed = 10f;

		private const float CoconutMaxSlamSpeed = 28f;

		private const float CoconutSlamRange = 45f;

		private const float CoconutSlamUpBias = 0.16f;

		private const float FrogPullStopDistance = 2.6f;

		private const float BreakRestoreItemRestoreDelaySeconds = 1f;

		private const float RestoreHeightOffset = 0.6f;

		private const float ControlledLinearDamping = 0.05f;

		private const float ControlledAngularDamping = 8f;

		private const float MovementInputDeadzone = 0.01f;

		private const float FrogNormalHorizontalLaunchScale = 0.55f;

		private const float GroundedJumpBufferSeconds = 0.3f;

		private const float FrogJumpInputBufferSeconds = 0.25f;

		private static readonly FieldInfo FrogTargetCharacterField = AccessTools.Field(typeof(FrogTongue), "_targetCharacter");

		private static readonly FieldInfo FrogTongueLengthField = AccessTools.Field(typeof(FrogTongue), "_tongueLength");

		private static readonly FieldInfo FrogIsPullingField = AccessTools.Field(typeof(FrogTongue), "_isPulling");

		private static readonly FieldInfo BreakableAlreadyBrokeField = AccessTools.Field(typeof(Breakable), "alreadyBroke");

		private static readonly FieldInfo ItemLastThrownCharacterField = AccessTools.Field(typeof(Item), "lastThrownCharacter");

		private static readonly FieldInfo ItemLastThrownTimeField = AccessTools.Field(typeof(Item), "lastThrownTime");

		private static readonly MethodInfo ItemForceSyncForFramesMethod = AccessTools.Method(typeof(Item), "ForceSyncForFrames", (Type[])null, (Type[])null);

		private static readonly Dictionary<Type, bool> HasSetKinematicRpcByComponentType = new Dictionary<Type, bool>();

		private const float UnmoddedSyncInterval = 0.1f;

		private const float IntegrityCheckInterval = 0.5f;

		private const float RespawnThrottleSeconds = 3f;

		private Character _character;

		private CritterKind _kind;

		private GameObject _critterRoot;

		private Rigidbody _critterRigidbody;

		private Mob _mob;

		private FrogTongue _frog;

		private Beetle _beetle;

		private Scorpion _scorpion;

		private Dynamite _dynamite;

		private Breakable _breakable;

		private Item _item;

		private PhotonView _critterView;

		private Vector3 _prevCenter;

		private Vector3 _cameraVelocity;

		private Vector3 _cameraSmoothedPosition;

		private Quaternion _cameraSmoothedRotation;

		private bool _cameraHasSmoothedPosition;

		private float _nextJumpAllowedTime;

		private float _nextAttackAllowedTime;

		private float _nextUnmoddedSyncTime;

		private float _nextIntegrityCheckTime;

		private float _nextRespawnTime;

		private float _lastGroundedTime = -10f;

		private float _frogJumpPressedTime = -10f;

		private float _attackPressedTime = -10f;

		private float _frogLocalLickBusyUntil;

		private float _coconutChargeStartTime = -1f;

		private float _itemRestoreAt = -1f;

		private Vector3 _lastKnownCritterPosition;

		private Vector3 _transformEntryRestorePosition;

		private Vector3 _lastSafeExitAnchor;

		private bool _coconutSlamQueued;

		private bool _bombIgnited;

		private bool _restoreAtTransformEntryOnExit;

		private bool _loggedControlledPhysics;

		private Vector3 _controlledFlatVelocity;

		private Renderer[] _localRenderers;

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

		private readonly List<KeyValuePair<Rigidbody, RigidbodyInterpolation>> _savedInterpolations = new List<KeyValuePair<Rigidbody, RigidbodyInterpolation>>();

		private static readonly Dictionary<int, CritterKind> KindByViewId = new Dictionary<int, CritterKind>();

		internal const string NetworkVisualMarker = "ImCritter.Visual";

		private static object _walkingMobState;

		public bool Active { get; private set; }

		internal CritterKind Kind => _kind;

		public static Character ActiveCritterCharacter { get; private set; }

		internal static bool IsCritterView(PhotonView view)
		{
			if ((Object)(object)view == (Object)null)
			{
				return false;
			}
			if (KindByViewId.ContainsKey(view.ViewID))
			{
				return true;
			}
			object[] instantiationData = view.InstantiationData;
			if (instantiationData != null && instantiationData.Length != 0 && instantiationData[0] is string text)
			{
				return text == "ImCritter.Visual";
			}
			return false;
		}

		internal static bool TryGetKind(PhotonView view, out CritterKind kind)
		{
			kind = CritterKind.Frog;
			if ((Object)(object)view == (Object)null)
			{
				return false;
			}
			if (KindByViewId.TryGetValue(view.ViewID, out kind))
			{
				return true;
			}
			object[] instantiationData = view.InstantiationData;
			if (instantiationData != null && instantiationData.Length > 1 && instantiationData[0] is string text && text == "ImCritter.Visual" && instantiationData[1] is int num && Enum.IsDefined(typeof(CritterKind), num))
			{
				kind = (CritterKind)num;
				return true;
			}
			return false;
		}

		internal static bool IsManualBombIgnitionInProgress(PhotonView view)
		{
			try
			{
				if ((Object)(object)view == (Object)null || (Object)(object)ActiveCritterCharacter == (Object)null)
				{
					return false;
				}
				CritterController component = ((Component)ActiveCritterCharacter).GetComponent<CritterController>();
				return (Object)(object)component != (Object)null && component.Active && component._kind == CritterKind.Bomb && component._bombIgnited && (Object)(object)component._critterView == (Object)(object)view;
			}
			catch
			{
				return false;
			}
		}

		internal static bool IsLocalCritterCharacter(Character character)
		{
			if ((Object)(object)character != (Object)null && character.IsLocal)
			{
				return (Object)(object)ActiveCritterCharacter == (Object)(object)character;
			}
			return false;
		}

		private static void LogInfo(string message)
		{
			ManualLogSource log = CritterPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("[Critter] " + message));
			}
		}

		private static void LogError(string entryPoint, Exception ex)
		{
			ManualLogSource log = CritterPlugin.Log;
			if (log != null)
			{
				log.LogError((object)("[Critter] " + entryPoint + ": " + ex));
			}
		}

		public bool IsValid()
		{
			if (!Active || (Object)(object)_character == (Object)null)
			{
				return false;
			}
			if (ShouldRestoreOnPickupHijack())
			{
				return true;
			}
			if (IsBreakRestoreItemForm(_kind))
			{
				return true;
			}
			if ((Object)(object)_critterRoot == (Object)null || (Object)(object)_critterRigidbody == (Object)null)
			{
				return false;
			}
			if (RequiresMob(_kind) && (Object)(object)_mob == (Object)null)
			{
				return false;
			}
			return true;
		}

		private static bool RequiresMob(CritterKind kind)
		{
			return !IsBreakRestoreItemForm(kind);
		}

		private static bool IsBreakRestoreItemForm(CritterKind kind)
		{
			if (kind != CritterKind.Coconut && kind != CritterKind.Bomb)
			{
				return kind == CritterKind.Cactus;
			}
			return true;
		}

		private static bool IsTransformEntryRestoreForm(CritterKind kind)
		{
			if (kind != CritterKind.Coconut)
			{
				return kind == CritterKind.Bomb;
			}
			return true;
		}

		private static bool IsPickupRestoreWhenMasterUnmoddedForm(CritterKind kind)
		{
			if (kind != CritterKind.Frog && kind != CritterKind.Scorpion && kind != CritterKind.Coconut && kind != CritterKind.Bomb)
			{
				return kind == CritterKind.Cactus;
			}
			return true;
		}

		private bool ShouldRestoreOnPickupHijack()
		{
			if (IsPickupRestoreWhenMasterUnmoddedForm(_kind))
			{
				return !CritterPlugin.MasterHasMod();
			}
			return false;
		}

		private bool ShouldUseLastKnownRestorePosition()
		{
			if (_itemRestoreAt > 0f && ((Vector3)(ref _lastKnownCritterPosition)).sqrMagnitude > 0.0001f)
			{
				if (!IsBreakRestoreItemForm(_kind))
				{
					return ShouldRestoreOnPickupHijack();
				}
				return true;
			}
			return false;
		}

		private bool ShouldRestoreAtTransformEntryPosition()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (_itemRestoreAt > 0f && _restoreAtTransformEntryOnExit && IsTransformEntryRestoreForm(_kind) && IsFiniteVector(_transformEntryRestorePosition))
			{
				return ((Vector3)(ref _transformEntryRestorePosition)).sqrMagnitude > 0.0001f;
			}
			return false;
		}

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

		internal static object GetWalkingMobState()
		{
			if (_walkingMobState == null)
			{
				Type type = AccessTools.Inner(typeof(Mob), "MobState");
				if (type != null && type.IsEnum)
				{
					_walkingMobState = Enum.Parse(type, "Walking");
				}
			}
			return _walkingMobState;
		}

		internal bool EnterCritter(Character character, CritterKind kind)
		{
			//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_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_00d4: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			if (Active)
			{
				return false;
			}
			try
			{
				GameObject val = SpawnCritter(character, kind, useLastKnownPosition: false);
				if ((Object)(object)val == (Object)null)
				{
					LogInfo("Failed to spawn critter prefab for " + kind.ToString() + ".");
					return false;
				}
				_character = character;
				_kind = kind;
				_prevCenter = character.Center;
				_cameraVelocity = Vector3.zero;
				_cameraHasSmoothedPosition = false;
				_nextJumpAllowedTime = 0f;
				_nextAttackAllowedTime = 0f;
				_frogJumpPressedTime = -10f;
				_attackPressedTime = -10f;
				_frogLocalLickBusyUntil = 0f;
				_coconutChargeStartTime = -1f;
				_itemRestoreAt = -1f;
				_coconutSlamQueued = false;
				_bombIgnited = false;
				_lastKnownCritterPosition = val.transform.position;
				_transformEntryRestorePosition = character.Center;
				_lastSafeExitAnchor = character.Center;
				_restoreAtTransformEntryOnExit = false;
				Active = true;
				ActiveCritterCharacter = character;
				((Behaviour)this).enabled = true;
				SetCritterNoClip(enable: true);
				HideLocalRenderers();
				HideHud();
				LogInfo("Entered " + kind.ToString() + " form.");
				return true;
			}
			catch (Exception ex)
			{
				LogError("EnterCritter(" + kind.ToString() + ")", ex);
				TearDownCritter();
				return false;
			}
		}

		private GameObject SpawnCritter(Character character, CritterKind kind, bool useLastKnownPosition)
		{
			//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_0037: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((useLastKnownPosition && ((Vector3)(ref _lastKnownCritterPosition)).sqrMagnitude > 0.0001f) ? _lastKnownCritterPosition : (character.Center + Vector3.up * 0.5f));
			string[] prefabNameCandidates = GetPrefabNameCandidates(kind);
			GameObject val2 = null;
			string text = ((prefabNameCandidates.Length != 0) ? prefabNameCandidates[0] : kind.ToString());
			for (int i = 0; i < prefabNameCandidates.Length; i++)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					break;
				}
				text = prefabNameCandidates[i];
				try
				{
					if (PhotonNetwork.InRoom)
					{
						val2 = PhotonNetwork.Instantiate("0_Items/" + text, val, Quaternion.identity, (byte)0, new object[2]
						{
							"ImCritter.Visual",
							(int)kind
						});
						continue;
					}
					GameObject val3 = Resources.Load<GameObject>("0_Items/" + text);
					if ((Object)(object)val3 == (Object)null)
					{
						val3 = Resources.Load<GameObject>(text);
					}
					if ((Object)(object)val3 != (Object)null)
					{
						val2 = Object.Instantiate<GameObject>(val3, val, Quaternion.identity);
						((Object)val2).name = "CritterLocal_" + text;
					}
				}
				catch (Exception ex)
				{
					LogInfo("Spawn candidate 0_Items/" + text + " failed: " + ex.Message);
					val2 = null;
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				LogInfo("SpawnCritter returned null for " + kind.ToString() + ".");
				return null;
			}
			_critterRoot = val2;
			_critterView = val2.GetComponent<PhotonView>();
			_item = val2.GetComponent<Item>();
			_critterRigidbody = val2.GetComponent<Rigidbody>();
			if ((Object)(object)_critterRigidbody == (Object)null && (Object)(object)_item != (Object)null)
			{
				_critterRigidbody = _item.rig;
			}
			_mob = val2.GetComponent<Mob>();
			_frog = val2.GetComponent<FrogTongue>();
			_beetle = val2.GetComponent<Beetle>();
			_scorpion = val2.GetComponent<Scorpion>();
			_dynamite = val2.GetComponent<Dynamite>();
			_breakable = val2.GetComponent<Breakable>();
			if ((Object)(object)_critterRigidbody == (Object)null || ((Object)(object)_mob == (Object)null && !IsBreakRestoreItemForm(kind)))
			{
				LogInfo("Prefab 0_Items/" + text + " has no required Rigidbody/Mob for " + kind.ToString() + ".");
				return null;
			}
			_critterRigidbody.freezeRotation = !IsBreakRestoreItemForm(kind);
			if (kind == CritterKind.Bomb && (Object)(object)_dynamite != (Object)null)
			{
				_dynamite.lightFuseRadius = 0f;
			}
			if (kind == CritterKind.Frog)
			{
				ConfigureControlledFrogTongue();
			}
			if ((Object)(object)_critterView != (Object)null)
			{
				KindByViewId[_critterView.ViewID] = kind;
			}
			if ((Object)(object)_mob != (Object)null)
			{
				_mob.hasBrain = false;
				TrySetMobField("forceNoMovement", true);
				TrySetMobStateWalking();
			}
			_controlledFlatVelocity = Vector3.zero;
			ApplyControlledRigidbodySettings(logOnce: true);
			if ((Object)(object)_mob != (Object)null && (Object)(object)_mob.anim != (Object)null)
			{
				TrySetMobField("sleeping", false);
			}
			if ((Object)(object)_item != (Object)null)
			{
				_item.blockInteraction = true;
			}
			return val2;
		}

		private void ConfigureControlledFrogTongue()
		{
			if (!((Object)(object)_frog == (Object)null))
			{
				_frog.extraDragLetGo = 0f;
				_frog.launchForce = 0f;
				_frog.liftForce = 0f;
				_frog.liftDragForce = 0f;
				_frog.extraDragOther = 0f;
				_frog.stopPullFriendDistance = Mathf.Max(_frog.stopPullFriendDistance, 2.6f);
			}
		}

		private static string[] GetPrefabNameCandidates(CritterKind kind)
		{
			return kind switch
			{
				CritterKind.Frog => new string[1] { "Frog" }, 
				CritterKind.Beetle => new string[1] { "Beetle" }, 
				CritterKind.Scorpion => new string[1] { "Scorpion" }, 
				CritterKind.Coconut => new string[5] { "item_coconut", "Item_Coconut", "Coconut", "CocoNut", "CoconutItem" }, 
				CritterKind.Bomb => new string[2] { "Dynamite", "Bomb" }, 
				CritterKind.Cactus => new string[2] { "cactusball", "CactusBall" }, 
				_ => throw new ArgumentOutOfRangeException("kind"), 
			};
		}

		public void ExitCritter()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (!Active && (Object)(object)_critterRoot == (Object)null)
			{
				return;
			}
			try
			{
				Active = false;
				ActiveCritterCharacter = null;
				((Behaviour)this).enabled = false;
				PositionCharacterForExit();
				SetCritterNoClip(enable: false);
				DestroyCritter();
				ForceShowLocalRenderers();
				_localRenderers = null;
				RestoreHud();
				_lastKnownCritterPosition = Vector3.zero;
				_transformEntryRestorePosition = Vector3.zero;
				_lastSafeExitAnchor = Vector3.zero;
				_restoreAtTransformEntryOnExit = false;
				LogInfo("Exited " + _kind.ToString() + " form.");
			}
			catch (Exception ex)
			{
				LogError("ExitCritter", ex);
				TearDownCritter();
			}
		}

		private void TearDownCritter()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Active = false;
			ActiveCritterCharacter = null;
			((Behaviour)this).enabled = false;
			SetCritterNoClip(enable: false);
			DestroyCritter();
			_lastKnownCritterPosition = Vector3.zero;
			_transformEntryRestorePosition = Vector3.zero;
			_lastSafeExitAnchor = Vector3.zero;
			_restoreAtTransformEntryOnExit = false;
		}

		private void DestroyCritter()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_critterView != (Object)null)
			{
				KindByViewId.Remove(_critterView.ViewID);
			}
			if ((Object)(object)_critterRoot != (Object)null)
			{
				try
				{
					if (PhotonNetwork.InRoom && (Object)(object)_critterView != (Object)null && _critterView.IsMine)
					{
						PhotonNetwork.Destroy(_critterRoot);
					}
					else
					{
						Object.Destroy((Object)(object)_critterRoot);
					}
				}
				catch (Exception ex)
				{
					LogError("DestroyCritter", ex);
				}
			}
			_critterRoot = null;
			_critterView = null;
			_critterRigidbody = null;
			_mob = null;
			_item = null;
			_frog = null;
			_beetle = null;
			_breakable = null;
			_dynamite = null;
			_controlledFlatVelocity = Vector3.zero;
			_scorpion = null;
			_coconutChargeStartTime = -1f;
			_itemRestoreAt = -1f;
			_coconutSlamQueued = false;
			_bombIgnited = false;
			_loggedControlledPhysics = false;
		}

		private void Update()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)_character == (Object)null)
			{
				return;
			}
			try
			{
				ClearNonMovementInput();
				KeepPlayerAlive();
				UpdatePickupOrBreakRestoreRecovery();
				KeepCritterControlled();
				UpdateUnmoddedSync();
				KeepLocalRenderersHidden();
				HideHud();
				HandleStamina();
				if (!ThirdPartyCameras.ShouldPauseFormControl)
				{
					BufferFrogJumpInput();
					BufferAttackInput();
				}
				else
				{
					ClearBufferedControlInput();
				}
				CheckCritterIntegrity();
				if ((Object)(object)_critterRoot != (Object)null && _critterRoot.transform.position.y < -80f)
				{
					LogInfo("Critter fell out of the world; exiting form.");
					ExitCritter();
				}
			}
			catch (Exception ex)
			{
				LogError("CritterController.Update", ex);
			}
		}

		private void CheckCritterIntegrity()
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < _nextIntegrityCheckTime)
			{
				return;
			}
			_nextIntegrityCheckTime = Time.unscaledTime + 0.5f;
			if (IsBreakRestoreItemForm(_kind) || ShouldRestoreOnPickupHijack())
			{
				bool flag = (Object)(object)_critterRoot == (Object)null || (Object)(object)_critterRigidbody == (Object)null || (Object)(object)_critterView == (Object)null || (!IsBreakRestoreItemForm(_kind) && (Object)(object)_mob == (Object)null) || (IsBreakRestoreItemForm(_kind) && IsBreakableAlreadyBroke());
				if (flag || ((Object)(object)_item != (Object)null && (int)_item.itemState != 0) || ((Object)(object)_critterView != (Object)null && _critterView.Owner != null && _critterView.Owner != PhotonNetwork.LocalPlayer))
				{
					SchedulePickupOrBreakRestore(IsTransformEntryRestoreForm(_kind) && flag);
				}
			}
			else if ((Object)(object)_critterRoot == (Object)null || (Object)(object)_mob == (Object)null || (Object)(object)_critterView == (Object)null)
			{
				LogInfo("Critter object was destroyed (likely picked up by another player); respawning.");
				RespawnCritter();
			}
			else if (_critterView.Owner != null && _critterView.Owner != PhotonNetwork.LocalPlayer)
			{
				LogInfo("Critter ownership was taken; respawning.");
				RespawnCritter();
			}
			else if ((Object)(object)_item != (Object)null && (int)_item.itemState != 0)
			{
				LogInfo("Critter was put in a backpack; respawning.");
				RespawnCritter();
			}
		}

		private void RespawnCritter()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)_character == (Object)null)
			{
				return;
			}
			if (IsBreakRestoreItemForm(_kind) || ShouldRestoreOnPickupHijack())
			{
				RestorePlayerAfterPickupOrBreak();
			}
			else if (!PhotonNetwork.InRoom)
			{
				ExitCritter();
			}
			else
			{
				if (Time.unscaledTime < _nextRespawnTime)
				{
					return;
				}
				_nextRespawnTime = Time.unscaledTime + 3f;
				try
				{
					CritterKind kind = _kind;
					DestroyCritter();
					if ((Object)(object)SpawnCritter(_character, kind, useLastKnownPosition: true) == (Object)null)
					{
						LogInfo("Respawn failed; exiting critter form.");
						ExitCritter();
						return;
					}
					_prevCenter = _character.Center;
					_nextJumpAllowedTime = Time.time + 0.3f;
					_nextAttackAllowedTime = Time.time + 0.5f;
					_nextUnmoddedSyncTime = 0f;
					_frogJumpPressedTime = -10f;
					_attackPressedTime = -10f;
					_frogLocalLickBusyUntil = 0f;
					_coconutChargeStartTime = -1f;
					_itemRestoreAt = -1f;
					_coconutSlamQueued = false;
					_bombIgnited = false;
					LogInfo("Respawned critter form: " + kind);
				}
				catch (Exception ex)
				{
					LogError("RespawnCritter", ex);
				}
			}
		}

		private void FixedUpdate()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)_character == (Object)null)
			{
				return;
			}
			try
			{
				FollowCritterWithCharacterRoot();
				if (!ThirdPartyCameras.ShouldPauseFormControl)
				{
					DriveCritterPhysics();
					return;
				}
				ClearBufferedControlInput();
				_controlledFlatVelocity = Vector3.zero;
			}
			catch (Exception ex)
			{
				LogError("CritterController.FixedUpdate", ex);
			}
		}

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

		private void OnDestroy()
		{
			if (Active)
			{
				Active = false;
				ActiveCritterCharacter = null;
				SetCritterNoClip(enable: false);
				DestroyCritter();
				ForceShowLocalRenderers();
				RestoreHud();
			}
		}

		private void KeepCritterControlled()
		{
			try
			{
				if ((Object)(object)_item != (Object)null && !_item.blockInteraction)
				{
					_item.blockInteraction = true;
				}
				if ((Object)(object)_critterRigidbody != (Object)null)
				{
					ApplyControlledRigidbodySettings(logOnce: false);
				}
				if (_kind == CritterKind.Bomb && (Object)(object)_dynamite != (Object)null && _dynamite.lightFuseRadius != 0f)
				{
					_dynamite.lightFuseRadius = 0f;
				}
				if (!((Object)(object)_mob == (Object)null))
				{
					if (_mob.hasBrain)
					{
						_mob.hasBrain = false;
					}
					TrySetMobField("forceNoMovement", true);
					TrySetMobField("sleeping", false);
					_mob.UpdateAnimation();
				}
			}
			catch (Exception ex)
			{
				LogError("KeepCritterControlled", ex);
			}
		}

		private void ApplyControlledRigidbodySettings(bool logOnce)
		{
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_critterRigidbody == (Object)null)
			{
				return;
			}
			try
			{
				_critterRigidbody.isKinematic = false;
				_critterRigidbody.useGravity = true;
				_critterRigidbody.detectCollisions = true;
				_critterRigidbody.constraints = (RigidbodyConstraints)((!IsBreakRestoreItemForm(_kind)) ? 112 : 0);
				_critterRigidbody.linearDamping = 0.05f;
				_critterRigidbody.angularDamping = 8f;
				_critterRigidbody.interpolation = (RigidbodyInterpolation)1;
				_critterRigidbody.sleepThreshold = 0f;
				_critterRigidbody.WakeUp();
				if (logOnce && !_loggedControlledPhysics)
				{
					_loggedControlledPhysics = true;
					LogInfo("Controlled physics for " + _kind.ToString() + ": linearDamping=" + _critterRigidbody.linearDamping.ToString("0.###") + " angularDamping=" + _critterRigidbody.angularDamping.ToString("0.###") + " constraints=" + ((object)_critterRigidbody.constraints/*cast due to .constrained prefix*/).ToString() + " kinematic=" + _critterRigidbody.isKinematic);
				}
			}
			catch (Exception ex)
			{
				LogError("ApplyControlledRigidbodySettings", ex);
			}
		}

		private void TrySetMobField(string fieldName, object value)
		{
			try
			{
				AccessTools.Field(typeof(Mob), fieldName)?.SetValue(_mob, value);
			}
			catch (Exception ex)
			{
				LogError("TrySetMobField(" + fieldName + ")", ex);
			}
		}

		private void UpdateUnmoddedSync()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_critterView == (Object)null || (Object)(object)_critterRoot == (Object)null || (Object)(object)_critterRigidbody == (Object)null || !PhotonNetwork.InRoom || CritterPlugin.UnmoddedRoomSupport == null || !CritterPlugin.UnmoddedRoomSupport.Value || !CritterPlugin.RoomHasUnmoddedPlayers() || Time.unscaledTime < _nextUnmoddedSyncTime)
			{
				return;
			}
			_nextUnmoddedSyncTime = Time.unscaledTime + 0.1f;
			try
			{
				Vector3 position = _critterRigidbody.position;
				Quaternion rotation = _critterRigidbody.rotation;
				if (!IsFiniteVector(position))
				{
					return;
				}
				PhotonView val = (((Object)(object)_item != (Object)null) ? ((MonoBehaviourPun)_item).photonView : _critterView);
				bool flag = PhotonViewHasRpcMethod(val, "SetKinematicRPC");
				foreach (Player item in CritterPlugin.UnmoddedRemotePlayers())
				{
					if (flag)
					{
						val.RPC("SetKinematicRPC", item, new object[3] { true, position, rotation });
					}
					if ((Object)(object)_mob != (Object)null)
					{
						_critterView.RPC("RPC_SyncMobState", item, new object[1] { 0 });
					}
				}
			}
			catch (Exception ex)
			{
				LogError("UpdateUnmoddedSync", ex);
			}
		}

		private void ForceCritterPhysicsSync(int frames)
		{
			if ((Object)(object)_item == (Object)null || !PhotonNetwork.InRoom || (Object)(object)_critterView == (Object)null || !_critterView.IsMine)
			{
				return;
			}
			try
			{
				ItemForceSyncForFramesMethod?.Invoke(_item, new object[1] { Mathf.Max(1, frames) });
			}
			catch
			{
			}
		}

		private static bool IsFiniteVector(Vector3 v)
		{
			//IL_0000: 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_001a: 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_0034: 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)
			if (!float.IsNaN(v.x) && !float.IsNaN(v.y) && !float.IsNaN(v.z) && !float.IsInfinity(v.x) && !float.IsInfinity(v.y))
			{
				return !float.IsInfinity(v.z);
			}
			return false;
		}

		private static bool IsFiniteQuaternion(Quaternion q)
		{
			//IL_0000: 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_001a: 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_0034: 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_004e: 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)
			if (!float.IsNaN(q.x) && !float.IsNaN(q.y) && !float.IsNaN(q.z) && !float.IsNaN(q.w) && !float.IsInfinity(q.x) && !float.IsInfinity(q.y) && !float.IsInfinity(q.z))
			{
				return !float.IsInfinity(q.w);
			}
			return false;
		}

		private void TrySetMobStateWalking()
		{
			try
			{
				object walkingMobState = GetWalkingMobState();
				if (walkingMobState != null)
				{
					AccessTools.PropertySetter(typeof(Mob), "mobState")?.Invoke(_mob, new object[1] { walkingMobState });
				}
			}
			catch (Exception ex)
			{
				LogError("TrySetMobStateWalking", ex);
			}
		}

		private void DriveCritterPhysics()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: 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_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: 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_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0666: Unknown result type (might be due to invalid IL or missing references)
			//IL_0663: Unknown result type (might be due to invalid IL or missing references)
			//IL_092d: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0667: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0806: Unknown result type (might be due to invalid IL or missing references)
			//IL_082d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0832: Unknown result type (might be due to invalid IL or missing references)
			//IL_0839: Unknown result type (might be due to invalid IL or missing references)
			//IL_083e: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_052a: Unknown result type (might be due to invalid IL or missing references)
			//IL_052f: Unknown result type (might be due to invalid IL or missing references)
			//IL_072d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0731: Unknown result type (might be due to invalid IL or missing references)
			//IL_0736: Unknown result type (might be due to invalid IL or missing references)
			//IL_073d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0742: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0573: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_critterRigidbody == (Object)null || TransformState.MenuOpen || ThirdPartyCameras.ShouldPauseFormControl)
			{
				return;
			}
			ApplyControlledRigidbodySettings(logOnce: false);
			Vector3 flatLookDirection = GetFlatLookDirection();
			Vector2 movementInput = GetMovementInput();
			Vector3 val = Vector3.Cross(Vector3.up, flatLookDirection);
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			Vector3 val2 = flatLookDirection * movementInput.y + normalized * movementInput.x;
			if (((Vector3)(ref val2)).sqrMagnitude > 1f)
			{
				((Vector3)(ref val2)).Normalize();
			}
			bool flag = IsSprintHeld() && CanSprint();
			float num = (flag ? Mathf.Max(1f, CritterPlugin.SprintMultiplier(_kind).Value) : 1f);
			float num2 = CritterPlugin.MaxSpeed(_kind).Value * num;
			bool flag2 = _kind == CritterKind.Frog && (Object)(object)_frog != (Object)null;
			bool flag3 = _kind == CritterKind.Beetle;
			bool flag4 = IsBreakRestoreItemForm(_kind);
			bool flag5 = _kind == CritterKind.Coconut;
			bool flag6 = _kind == CritterKind.Bomb;
			bool flag7 = _kind == CritterKind.Cactus;
			if (flag7 && _critterRigidbody.isKinematic)
			{
				return;
			}
			if (!flag2)
			{
				if (flag5 || flag6 || flag7)
				{
					if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f)
					{
						Vector3 linearVelocity = _critterRigidbody.linearVelocity;
						Vector3 val3 = default(Vector3);
						((Vector3)(ref val3))..ctor(linearVelocity.x, 0f, linearVelocity.z);
						if (((Vector3)(ref val3)).magnitude < num2)
						{
							_critterRigidbody.AddForce(val2 * CritterPlugin.MovementForce(_kind).Value * num, (ForceMode)5);
						}
						val = Vector3.Cross(Vector3.up, val2);
						Vector3 normalized2 = ((Vector3)(ref val)).normalized;
						_critterRigidbody.AddTorque(normalized2 * 16f * num, (ForceMode)5);
						ForceCritterPhysicsSync(2);
					}
					if (flag && ((Vector3)(ref val2)).sqrMagnitude > 0.0001f)
					{
						UseStamina(Time.fixedDeltaTime * 0.035f);
					}
				}
				else
				{
					Vector3 linearVelocity2 = _critterRigidbody.linearVelocity;
					Vector3 val4 = ((((Vector3)(ref val2)).sqrMagnitude > 0.0001f) ? (val2 * num2) : Vector3.zero);
					Vector3 controlledFlatVelocity = _controlledFlatVelocity;
					float num3 = ((_kind == CritterKind.Beetle) ? 18f : 12f);
					Vector3 val5 = (_controlledFlatVelocity = Vector3.MoveTowards(controlledFlatVelocity, val4, num3 * Time.fixedDeltaTime));
					_critterRigidbody.linearVelocity = new Vector3(0f, linearVelocity2.y, 0f);
					if (((Vector3)(ref val5)).sqrMagnitude > 1E-06f)
					{
						_critterRigidbody.MovePosition(_critterRigidbody.position + val5 * Time.fixedDeltaTime);
						ForceCritterPhysicsSync(2);
					}
					if ((_kind == CritterKind.Beetle || flag4) && flag && ((Vector3)(ref val2)).sqrMagnitude > 0.0001f)
					{
						UseStamina(Time.fixedDeltaTime * 0.035f);
					}
				}
			}
			if (flag3 && IsCritterGrounded() && Vector3.Dot(_critterRoot.transform.up, Vector3.up) < 0.5f)
			{
				Vector3 val6 = _critterRoot.transform.forward;
				val6.y = 0f;
				if (((Vector3)(ref val6)).sqrMagnitude < 0.0001f)
				{
					val6 = flatLookDirection;
				}
				Quaternion val7 = Quaternion.LookRotation(((Vector3)(ref val6)).normalized, Vector3.up);
				_critterRigidbody.MoveRotation(Quaternion.Slerp(_critterRigidbody.rotation, val7, Time.deltaTime * 6f));
				Rigidbody critterRigidbody = _critterRigidbody;
				critterRigidbody.angularVelocity *= 0.5f;
			}
			if (!flag4 && ((Vector3)(ref val2)).sqrMagnitude > 0.0001f)
			{
				Quaternion val8 = Quaternion.LookRotation(val2, Vector3.up);
				float num4 = ((_kind == CritterKind.Scorpion) ? 4.5f : 6.5f);
				_critterRigidbody.MoveRotation(Quaternion.Slerp(_critterRigidbody.rotation, val8, Time.fixedDeltaTime * num4));
			}
			if (flag2 && IsCritterGrounded())
			{
				_lastGroundedTime = Time.time;
			}
			if (flag2 && HasBufferedFrogJump())
			{
				if (!(Time.time < _nextJumpAllowedTime))
				{
					if (!CanFrogJumpNow())
					{
						string[] obj = new string[13]
						{
							"Frog jump blocked: grounded=",
							IsCritterGrounded().ToString(),
							" char.isGrounded=",
							(_character?.data?.isGrounded == true).ToString(),
							" rb.kinematic=",
							(!((Object)(object)_critterRigidbody != (Object)null) || _critterRigidbody.isKinematic).ToString(),
							" rb.velY=",
							null,
							null,
							null,
							null,
							null,
							null
						};
						object obj2;
						if (!((Object)(object)_critterRigidbody != (Object)null))
						{
							obj2 = "n/a";
						}
						else
						{
							val = _critterRigidbody.linearVelocity;
							obj2 = val.y.ToString("0.00");
						}
						obj[7] = (string)obj2;
						obj[8] = " y=";
						object obj3;
						if (!((Object)(object)_critterRoot != (Object)null))
						{
							obj3 = "n/a";
						}
						else
						{
							val = _critterRoot.transform.position;
							obj3 = val.y.ToString("0.00");
						}
						obj[9] = (string)obj3;
						obj[10] = " sinceGround=";
						obj[11] = (Time.time - _lastGroundedTime).ToString("0.00");
						obj[12] = "s";
						LogInfo(string.Concat(obj));
						ConsumeFrogJumpInput();
					}
					else if (!UseStamina(0.08f))
					{
						Character character = _character;
						float? obj4;
						if (character == null)
						{
							obj4 = null;
						}
						else
						{
							CharacterData data = character.data;
							obj4 = ((data != null) ? new float?(data.currentStamina) : ((float?)null));
						}
						LogInfo("Frog jump blocked: stamina=" + (obj4 ?? (-1f)).ToString("0.00"));
						ConsumeFrogJumpInput();
					}
					else
					{
						ConsumeFrogJumpInput();
						_lastGroundedTime = Time.time;
						Vector3 val9 = ((((Vector3)(ref val2)).sqrMagnitude > 0.0001f) ? val2 : flatLookDirection);
						float value = CritterPlugin.JumpPower(_kind).Value;
						if ((Object)(object)_mob.anim != (Object)null)
						{
							_mob.anim.SetTrigger("Jump");
						}
						val9 = ((Vector3)(ref val9)).normalized;
						float num5 = (IsSprintHeld() ? Mathf.Max(1f, CritterPlugin.SprintMultiplier(_kind).Value) : 1f);
						float num6 = Mathf.Clamp(CritterPlugin.MaxSpeed(_kind).Value * value * 0.55f * num5, 2f, 40f);
						float num7 = Mathf.Clamp(CritterPlugin.JumpSpeed(_kind).Value * value, 4f, 30f);
						_critterRigidbody.linearVelocity = val9 * num6 + Vector3.up * num7;
						ForceCritterPhysicsSync(8);
						_nextJumpAllowedTime = Time.time + 0.3f;
					}
				}
			}
			else if (flag4 && HasBufferedFrogJump())
			{
				if (Time.time >= _nextJumpAllowedTime && IsCritterGrounded() && UseStamina(0.08f))
				{
					ConsumeFrogJumpInput();
					Vector3 val10 = ((((Vector3)(ref val2)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val2)).normalized : Vector3.zero);
					float value2 = CritterPlugin.JumpPower(_kind).Value;
					float num8 = Mathf.Clamp(CritterPlugin.JumpSpeed(_kind).Value * value2, 3f, 20f);
					_critterRigidbody.linearVelocity = val10 * Mathf.Clamp(CritterPlugin.MaxSpeed(_kind).Value * 0.35f, 0f, 10f) + Vector3.up * num8;
					ForceCritterPhysicsSync(6);
					_nextJumpAllowedTime = Time.time + 0.3f;
				}
				else if (Time.time >= _nextJumpAllowedTime)
				{
					ConsumeFrogJumpInput();
				}
			}
			if (flag5 && _coconutSlamQueued && Time.time >= _nextAttackAllowedTime)
			{
				_coconutSlamQueued = false;
				if (TryCoconutSlam())
				{
					_nextAttackAllowedTime = Time.time + CritterPlugin.AttackCooldown(_kind).Value;
				}
			}
			else if (flag6 && HasBufferedAttack() && Time.time >= _nextAttackAllowedTime)
			{
				ConsumeAttackInput();
				if (TryIgniteBomb())
				{
					_nextAttackAllowedTime = Time.time + CritterPlugin.AttackCooldown(_kind).Value;
				}
			}
			else if (HasBufferedAttack() && Time.time >= _nextAttackAllowedTime && (!flag2 || IsFrogTongueReady()))
			{
				ConsumeAttackInput();
				if (TryAttack(flatLookDirection))
				{
					_nextAttackAllowedTime = Time.time + ((_kind == CritterKind.Frog) ? Mathf.Min(0.1f, CritterPlugin.AttackCooldown(_kind).Value) : CritterPlugin.AttackCooldown(_kind).Value);
				}
			}
		}

		private bool CanFrogJumpNow()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (IsCritterGrounded() || Time.time - _lastGroundedTime <= 0.3f)
			{
				return true;
			}
			if ((Object)(object)_critterRigidbody == (Object)null)
			{
				return false;
			}
			return Mathf.Abs(_critterRigidbody.linearVelocity.y) <= 0.08f;
		}

		private bool TryAttack(Vector3 forward)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			return _kind switch
			{
				CritterKind.Frog => TryFrogTongue(), 
				CritterKind.Beetle => TryBeetleBonk(forward), 
				CritterKind.Scorpion => TryScorpionSting(forward), 
				CritterKind.Coconut => TryCoconutSlam(), 
				CritterKind.Bomb => TryIgniteBomb(), 
				CritterKind.Cactus => TryCactusLaunch(), 
				_ => false, 
			};
		}

		private static bool PhotonViewHasRpcMethod(PhotonView view, string methodName)
		{
			if ((Object)(object)view == (Object)null)
			{
				return false;
			}
			try
			{
				MonoBehaviour[] components = ((Component)view).GetComponents<MonoBehaviour>();
				if (components == null)
				{
					return false;
				}
				foreach (MonoBehaviour val in components)
				{
					if (!((Object)(object)val == (Object)null))
					{
						Type type = ((object)val).GetType();
						if (!HasSetKinematicRpcByComponentType.TryGetValue(type, out var value))
						{
							value = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null;
							HasSetKinematicRpcByComponentType[type] = value;
						}
						if (value)
						{
							return true;
						}
					}
				}
			}
			catch
			{
				return false;
			}
			return false;
		}

		private void UpdatePickupOrBreakRestoreRecovery()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			bool flag = ShouldRestoreOnPickupHijack();
			if (IsBreakRestoreItemForm(_kind) || flag)
			{
				if ((Object)(object)_critterRoot != (Object)null)
				{
					_lastKnownCritterPosition = _critterRoot.transform.position;
				}
				if (_itemRestoreAt > 0f && Time.unscaledTime >= _itemRestoreAt)
				{
					RestorePlayerAfterPickupOrBreak();
				}
				else if ((Object)(object)_critterRoot == (Object)null || (Object)(object)_critterRigidbody == (Object)null || (Object)(object)_critterView == (Object)null || (!IsBreakRestoreItemForm(_kind) && (Object)(object)_mob == (Object)null) || (IsBreakRestoreItemForm(_kind) && IsBreakableAlreadyBroke()))
				{
					SchedulePickupOrBreakRestore(IsTransformEntryRestoreForm(_kind));
				}
			}
		}

		private void SchedulePickupOrBreakRestore(bool restoreAtTransformEntry)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return;
			}
			bool flag = ShouldRestoreOnPickupHijack();
			if (IsBreakRestoreItemForm(_kind) || flag)
			{
				if ((Object)(object)_critterRoot != (Object)null)
				{
					_lastKnownCritterPosition = _critterRoot.transform.position;
				}
				if (restoreAtTransformEntry && IsTransformEntryRestoreForm(_kind))
				{
					_restoreAtTransformEntryOnExit = true;
				}
				if (!(_itemRestoreAt > 0f))
				{
					_itemRestoreAt = Time.unscaledTime + 1f;
					_coconutChargeStartTime = -1f;
					_coconutSlamQueued = false;
					string text = ((flag && !CritterPlugin.MasterHasMod()) ? "was picked up while the master has no mod" : "broke, exploded, or was removed");
					LogInfo(_kind.ToString() + " " + text + "; restoring player in 1 second.");
				}
			}
		}

		private bool IsBreakableAlreadyBroke()
		{
			if ((Object)(object)_breakable == (Object)null || BreakableAlreadyBrokeField == null)
			{
				return false;
			}
			try
			{
				return (bool)BreakableAlreadyBrokeField.GetValue(_breakable);
			}
			catch
			{
				return false;
			}
		}

		private void RestorePlayerAfterPickupOrBreak()
		{
			if (!Active || (!IsBreakRestoreItemForm(_kind) && !ShouldRestoreOnPickupHijack()))
			{
				return;
			}
			try
			{
				string text = (ShouldRestoreAtTransformEntryPosition() ? "transform entry position" : "pickup/destroyed position");
				LogInfo("Restoring player at " + _kind.ToString() + " " + text + ".");
				ExitCritter();
			}
			catch (Exception ex)
			{
				LogError("RestorePlayerAfterPickupOrBreak", ex);
			}
		}

		private bool TryCoconutSlam()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_critterRigidbody == (Object)null || (Object)(object)_critterRoot == (Object)null)
			{
				return false;
			}
			try
			{
				float num = Mathf.Clamp01(((_coconutChargeStartTime > 0f) ? Mathf.Clamp(Time.time - _coconutChargeStartTime, 0f, 1.25f) : 0.4375f) / 1.25f);
				Vector3 crosshairLaunchDirection = GetCrosshairLaunchDirection(45f);
				float num2 = Mathf.Lerp(10f, 28f, num);
				_critterRigidbody.linearVelocity = crosshairLaunchDirection * num2;
				Vector3 val = Vector3.ProjectOnPlane(crosshairLaunchDirection, Vector3.up);
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
				{
					val = GetFlatLookDirection();
				}
				Rigidbody critterRigidbody = _critterRigidbody;
				critterRigidbody.angularVelocity += Vector3.Cross(Vector3.up, ((Vector3)(ref val)).normalized) * Mathf.Lerp(4f, 16f, num);
				ForceCritterPhysicsSync(10);
				_coconutChargeStartTime = -1f;
				LogInfo("Coconut slam charged " + num.ToString("0.00") + ".");
				return true;
			}
			catch (Exception ex)
			{
				LogError("TryCoconutSlam", ex);
				return false;
			}
		}

		private bool TryIgniteBomb()
		{
			if (_kind != CritterKind.Bomb || _bombIgnited || (Object)(object)_dynamite == (Object)null)
			{
				return false;
			}
			try
			{
				_bombIgnited = true;
				_dynamite.LightFlare();
				ForceCritterPhysicsSync(4);
				LogInfo("Bomb fuse lit through vanilla Dynamite.LightFlare.");
				return true;
			}
			catch (Exception ex)
			{
				_bombIgnited = false;
				LogError("TryIgniteBomb", ex);
				return false;
			}
		}

		private bool TryCactusLaunch()
		{
			return false;
		}

		private Vector3 GetCrosshairLaunchDirection(float range)
		{
			//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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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_007c: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Camera main = Camera.main;
				if ((Object)(object)main == (Object)null)
				{
					Vector3 val = GetFlatLookDirection() + Vector3.up * 0.16f;
					return ((Vector3)(ref val)).normalized;
				}
				Ray val2 = default(Ray);
				((Ray)(ref val2))..ctor(((Component)main).transform.position, ((Component)main).transform.forward);
				Vector3 val3 = ((Ray)(ref val2)).direction;
				RaycastHit val4 = default(RaycastHit);
				if (Physics.Raycast(val2, ref val4, range, -5, (QueryTriggerInteraction)1) && (Object)(object)_critterRigidbody != (Object)null)
				{
					Vector3 val5 = ((RaycastHit)(ref val4)).point - _critterRigidbody.position;
					if (((Vector3)(ref val5)).sqrMagnitude > 1f)
					{
						val3 = Vector3.Slerp(val3, ((Vector3)(ref val5)).normalized, 0.25f);
					}
				}
				val3 += Vector3.up * 0.16f;
				return ((Vector3)(ref val3)).normalized;
			}
			catch
			{
				Vector3 val6 = GetFlatLookDirection() + Vector3.up * 0.16f;
				return ((Vector3)(ref val6)).normalized;
			}
		}

		private bool TryFrogTongue()
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_frog == (Object)null)
			{
				return false;
			}
			try
			{
				ResetFrogTongueIfIdle();
				Character val = FindCrosshairTarget(Mathf.Max(_frog.maxDistance, 14f), 3.4f);
				if ((Object)(object)val == (Object)null)
				{
					if ((Object)(object)_mob != (Object)null && (Object)(object)_mob.anim != (Object)null)
					{
						_mob.anim.SetTrigger("Lick");
					}
					TryPlayFrogLickSfx();
					_frogLocalLickBusyUntil = Time.time + 0.35f;
					LogInfo("Frog tongue lashed (no target).");
					return true;
				}
				((MonoBehaviourPun)_frog).photonView.RPC("RPCA_FrogAction", (RpcTarget)0, new object[3]
				{
					((MonoBehaviourPun)val).photonView,
					(object)(FrogActionType)1,
					Vector3.zero
				});
				LogInfo("Frog tongue fired.");
				return true;
			}
			catch (Exception ex)
			{
				LogError("TryFrogTongue", ex);
				return false;
			}
		}

		private bool IsFrogTongueReady()
		{
			if ((Object)(object)_frog == (Object)null)
			{
				return true;
			}
			if (Time.time < _frogLocalLickBusyUntil)
			{
				return false;
			}
			try
			{
				object? obj = FrogTargetCharacterField?.GetValue(_frog);
				object? obj2 = ((obj is Character) ? obj : null);
				bool flag = FrogIsPullingField != null && (bool)FrogIsPullingField.GetValue(_frog);
				float num = ((FrogTongueLengthField != null) ? ((float)FrogTongueLengthField.GetValue(_frog)) : 0f);
				return (Object)obj2 == (Object)null && !flag && num <= 0.08f;
			}
			catch
			{
				return Time.time >= _nextAttackAllowedTime;
			}
		}

		private void TryPlayFrogLickSfx()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_frog == (Object)null) && _frog.lickSFX != null && _frog.lickSFX.Length != 0 && !((Object)(object)_critterRoot == (Object)null))
			{
				SFX_Instance val = _frog.lickSFX[0];
				if ((Object)(object)val != (Object)null)
				{
					val.Play(_critterRoot.transform.position);
				}
			}
		}

		private bool TryBeetleBonk(Vector3 forward)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Character val = FindCrosshairTarget(4f);
				if ((Object)(object)val == (Object)null)
				{
					PlayAttackAnimationNetworked();
					Rigidbody critterRigidbody = _critterRigidbody;
					if (critterRigidbody != null)
					{
						critterRigidbody.AddForce(forward * 3f + Vector3.up * 1.5f, (ForceMode)2);
					}
					return true;
				}
				PlayAttackAnimationNetworked();
				float ragdollTime = (((Object)(object)_beetle != (Object)null) ? _beetle.ragdollTime : 2f);
				float num = (((Object)(object)_beetle != (Object)null) ? _beetle.bonkForce : 8f);
				float num2 = (((Object)(object)_beetle != (Object)null) ? _beetle.bonkForceUp : 6f) * 1.6f;
				Vector3 force = forward * num + Vector3.up * num2;
				ApplyKnockback(val, force, ragdollTime);
				LogInfo("Beetle bonk!");
				return true;
			}
			catch (Exception ex)
			{
				LogError("TryBeetleBonk", ex);
				return false;
			}
		}

		private bool TryScorpionSting(Vector3 forward)
		{
			//IL_0026: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Character val = FindCrosshairTarget(4f);
				if ((Object)(object)val == (Object)null)
				{
					PlayAttackAnimationNetworked();
					return true;
				}
				PlayAttackAnimationNetworked();
				ApplyKnockback(val, forward * 3f + Vector3.up * 2f, 1.5f);
				ApplyPoison(val);
				LogInfo("Scorpion sting!");
				return true;
			}
			catch (Exception ex)
			{
				LogError("TryScorpionSting", ex);
				return false;
			}
		}

		private void PlayAttackAnimation()
		{
			if ((Object)(object)_mob != (Object)null && (Object)(object)_mob.anim != (Object)null)
			{
				_mob.anim.SetTrigger("Attack");
			}
		}

		private void PlayAttackAnimationNetworked()
		{
			PlayAttackAnimation();
			try
			{
				if (PhotonNetwork.InRoom && (Object)(object)_critterView != (Object)null && _critterView.IsMine)
				{
					_critterView.RPC("RPC_StartAttack", (RpcTarget)1, Array.Empty<object>());
				}
			}
			catch (Exception ex)
			{
				LogInfo("Attack animation RPC failed: " + ex.Message);
			}
		}

		private static void ApplyKnockback(Character target, Vector3 force, float ragdollTime)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			try
			{
				PhotonView photonView = ((MonoBehaviourPun)target).photonView;
				if (photonView != null)
				{
					photonView.RPC("RPCA_Fall", (RpcTarget)0, new object[2] { ragdollTime, 0f });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = CritterPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Critter] RPCA_Fall failed: " + ex.Message));
				}
			}
			try
			{
				if ((Object)(object)((MonoBehaviourPun)target).photonView != (Object)null)
				{
					((MonoBehaviourPun)target).photonView.RPC("RPCA_AddForceToBodyPart", (RpcTarget)0, new object[3]
					{
						(object)(BodypartType)2,
						Vector3.zero,
						force
					});
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = CritterPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Critter] Knockback broadcast failed: " + ex2.Message));
				}
			}
		}

		private static void ApplyPoison(Character target)
		{
			try
			{
				CharacterAfflictions val = ((target.refs != null) ? target.refs.afflictions : null);
				if (!((Object)(object)val == (Object)null))
				{
					AccessTools.Method(typeof(CharacterAfflictions), "AddStatus", (Type[])null, (Type[])null)?.Invoke(val, new object[6] { 3, 0.15f, false, true, true, false });
					Type type = AccessTools.TypeByName("Peak.Afflictions.Affliction_PoisonOverTime");
					object obj = ((!(type != null)) ? null : AccessTools.Constructor(type, new Type[3]
					{
						typeof(float),
						typeof(float),
						typeof(float)
					}, false)?.Invoke(new object[3] { 10f, 0f, 0.1f }));
					if (obj != null)
					{
						AccessTools.Method(typeof(CharacterAfflictions), "AddAffliction", (Type[])null, (Type[])null)?.Invoke(val, new object[2] { obj, false });
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = CritterPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Critter] Poison affliction failed: " + ex.Message));
				}
			}
		}

		private Character FindCrosshairTarget(float range)
		{
			return FindCrosshairTarget(range, 2.5f);
		}

		private Character FindCrosshairTarget(float range, float aimRadius)
		{
			//IL_001f: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Camera main = Camera.main;
				if ((Object)(object)main == (Object)null)
				{
					return null;
				}
				Ray val = default(Ray);
				((Ray)(ref val))..ctor(((Component)main).transform.position, ((Component)main).transform.forward);
				Character result = null;
				float num = float.MaxValue;
				List<Character> allCharacters = Character.AllCharacters;
				for (int i = 0; i < allCharacters.Count; i++)
				{
					Character val2 = allCharacters[i];
					if ((Object)(object)val2 == (Object)null || (Object)(object)val2 == (Object)(object)_character || (Object)(object)val2.data == (Object)null || val2.data.dead)
					{
						continue;
					}
					Vector3 center = val2.Center;
					Vector3 val3 = center - _critterRoot.transform.position;
					if (((Vector3)(ref val3)).magnitude > range)
					{
						continue;
					}
					float num2 = Vector3.Dot(center - ((Ray)(ref val)).origin, ((Ray)(ref val)).direction);
					if (num2 <= 0f)
					{
						continue;
					}
					float num3 = Vector3.Distance(((Ray)(ref val)).origin + ((Ray)(ref val)).direction * num2, center);
					float num4 = Mathf.Max(0.65f, GetCharacterAimRadius(val2));
					float num5 = Mathf.Max(aimRadius, num4);
					if (!(num3 > num5))
					{
						float num6 = Mathf.Max(0f, num3 - num4) + ((Vector3)(ref val3)).magnitude * 0.08f;
						if (num6 < num)
						{
							num = num6;
							result = val2;
						}
					}
				}
				return result;
			}
			catch (Exception ex)
			{
				LogError("FindCrosshairTarget", ex);
				return null;
			}
		}

		private static float GetCharacterAimRadius(Character character)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Collider[] componentsInChildren = ((Component)character).GetComponentsInChildren<Collider>(true);
				float num = 0.65f;
				foreach (Collider val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null) && !val.isTrigger)
					{
						Bounds bounds = val.bounds;
						Vector3 extents = ((Bounds)(ref bounds)).extents;
						num = Mathf.Max(num, Mathf.Min(1.8f, Mathf.Max(extents.x, extents.z)));
					}
				}
				return num;
			}
			catch
			{
				return 0.65f;
			}
		}

		private void ResetFrogTongueIfIdle()
		{
			if ((Object)(object)_frog == (Object)null)
			{
				return;
			}
			try
			{
				object? obj = FrogTargetCharacterField?.GetValue(_frog);
				object? obj2 = ((obj is Character) ? obj : null);
				bool flag = FrogIsPullingField != null && (bool)FrogIsPullingField.GetValue(_frog);
				float num = ((FrogTongueLengthField != null) ? ((float)FrogTongueLengthField.GetValue(_frog)) : 0f);
				if ((Object)obj2 == (Object)null && !flag && num <= 0.16f && FrogTongueLengthField != null)
				{
					FrogTongueLengthField.SetValue(_frog, 0f);
				}
			}
			catch (Exception ex)
			{
				LogError("ResetFrogTongueIfIdle", ex);
			}
		}

		private bool IsCritterGrounded()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_character != (Object)null && (Object)(object)_character.data != (Object)null && _character.data.isGrounded)
			{
				return true;
			}
			if ((Object)(object)_critterRoot == (Object)null)
			{
				return false;
			}
			float critterRadius = GetCritterRadius();
			return Physics.CheckSphere(_critterRoot.transform.position - Vector3.up * (critterRadius * 0.8f) + Vector3.down * 0.25f, Mathf.Max(0.08f, critterRadius * 0.5f), -5, (QueryTriggerInteraction)1);
		}

		private float GetCritterRadius()
		{
			//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_0023: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Collider componentInChildren = _critterRoot.GetComponentInChildren<Collider>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					Bounds bounds = componentInChildren.bounds;
					return Mathf.Max(0.1f, ((Bounds)(ref bounds)).extents.y);
				}
			}
			catch
			{
			}
			return 0.3f;
		}

		private void HandleStamina()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_character == (Object)null || (Object)(object)_character.data == (Object)null)
			{
				return;
			}
			CharacterData data = _character.data;
			if (IsSprintHeld())
			{
				Vector2 movementInput = GetMovementInput();
				if (!(((Vector2)(ref movementInput)).sqrMagnitude < 0.0001f))
				{
					return;
				}
			}
			data.currentStamina = Mathf.Min(1f, data.currentStamina + GetStaminaRegen() * Time.deltaTime);
		}

		private static bool IsSprintHeld()
		{
			if (TransformState.MenuOpen)
			{
				return false;
			}
			return GameInput.SprintHeld((KeyCode)304);
		}

		private bool CanSprint()
		{
			if ((Object)(object)_character != (Object)null && (Object)(object)_character.data != (Object)null)
			{
				return _character.data.currentStamina > 0.02f;
			}
			return false;
		}

		private bool UseStamina(float cost)
		{
			if ((Object)(object)_character == (Object)null || (Object)(object)_character.data == (Object)null)
			{
				return true;
			}
			CharacterData data = _character.data;
			if (data.currentStamina < cost)
			{
				return false;
			}
			data.currentStamina = Mathf.Max(0f, data.currentStamina - cost);
			return true;
		}

		private static float GetStaminaRegen()
		{
			return Mathf.Clamp(0.18f, 0.01f, 1f);
		}

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

		private void BufferFrogJumpInput()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((_kind == CritterKind.Frog || IsBreakRestoreItemForm(_kind)) && !TransformState.MenuOpen && GameInput.JumpPressed(CritterPlugin.JumpKey.Value))
			{
				_frogJumpPressedTime = Time.time;
			}
		}

		private bool HasBufferedFrogJump()
		{
			return Time.time - _frogJumpPressedTime <= 0.25f;
		}

		private void ConsumeFrogJumpInput()
		{
			_frogJumpPressedTime = -10f;
		}

		private static bool AttackPressed()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return GameInput.UseSecondaryPressed(CritterPlugin.AttackKey.Value);
		}

		private static bool AttackReleased()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return GameInput.UseSecondaryReleased(CritterPlugin.AttackKey.Value);
		}

		private void BufferAttackInput()
		{
			if (TransformState.MenuOpen || (_kind == CritterKind.Bomb && _bombIgnited))
			{
				return;
			}
			if (_kind == CritterKind.Coconut)
			{
				if (AttackPressed())
				{
					_coconutChargeStartTime = Time.time;
					_coconutSlamQueued = false;
				}
				if (_coconutChargeStartTime > 0f && (AttackReleased() || Time.time - _coconutChargeStartTime >= 1.25f))
				{
					_coconutSlamQueued = true;
				}
			}
			else if (AttackPressed())
			{
				_attackPressedTime = Time.time;
			}
		}

		private bool HasBufferedAttack()
		{
			return Time.time - _attackPressedTime <= 0.2f;
		}

		private void ConsumeAttackInput()
		{
			_attackPressedTime = -10f;
		}

		private void ClearBufferedControlInput()
		{
			_frogJumpPressedTime = -10f;
			_attackPressedTime = -10f;
			_coconutChargeStartTime = -1f;
			_coconutSlamQueued = false;
		}

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

		private Vector2 GetMovementInput()
		{
			//IL_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_0007: 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 r