Decompiled source of SourceBhop v0.3.9

BepInEx/plugins/SourceBhop.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace SourceBhop;

internal enum SpeedometerCorner
{
	TopLeft,
	TopRight,
	BottomLeft,
	BottomRight
}
[BepInPlugin("Tim.SourceBhop", "Source Bhop", "0.3.9")]
public sealed class Plugin : BaseUnityPlugin
{
	internal const string Guid = "Tim.SourceBhop";

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> AutoHop;

	internal static ConfigEntry<bool> ShowSpeedometer;

	internal static ConfigEntry<SpeedometerCorner> Corner;

	internal static ConfigEntry<float> GroundAcceleration;

	internal static ConfigEntry<float> AirAcceleration;

	internal static ConfigEntry<float> GroundFriction;

	internal static ConfigEntry<float> StopSpeed;

	internal static ConfigEntry<float> AirWishSpeedFraction;

	internal static ConfigEntry<float> AirTurnAssistRate;

	internal static ConfigEntry<float> JumpTakeoffDelaySeconds;

	internal static ConfigEntry<float> JumpStaminaMultiplier;

	internal static ConfigEntry<bool> DebugOverlay;

	internal static ConfigEntry<bool> DebugFallDamage;

	internal static ConfigEntry<bool> DebugAirStrafe;

	internal static ManualLogSource Log;

	internal static bool NetworkRequirementReady;

	private Harmony _harmony;

	private GUIStyle _speedometerStyle;

	private GUIStyle _statusStyle;

	private bool _loggedGui;

	private float _nextStatusLog;

	private void Awake()
	{
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b6: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Source-style bunnyhopping for the local player.");
		AutoHop = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoHop", true, "Hold Jump to jump again on landing.");
		ShowSpeedometer = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowSpeedometer", true, "Show current horizontal movement speed in a screen corner.");
		Corner = ((BaseUnityPlugin)this).Config.Bind<SpeedometerCorner>("HUD", "Corner", SpeedometerCorner.TopRight, "Speedometer location: TopLeft, TopRight, BottomLeft, or BottomRight.");
		GroundAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "GroundAcceleration", 10f, "Acceleration toward the desired direction while grounded.");
		AirAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "AirAcceleration", 10f, "Acceleration toward the desired direction in the air.");
		GroundFriction = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "GroundFriction", 6f, "Horizontal friction while grounded and not jumping.");
		StopSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "StopSpeed", 2f, "Minimum speed used in the ground friction calculation, in game units per second.");
		AirWishSpeedFraction = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "AirWishSpeedFraction", 0.3f, "Directional air speed limit as a fraction of normal movement speed. This does not cap total speed.");
		AirTurnAssistRate = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "AirTurnAssistDegreesPerSecond", 720f, "Maximum extra rotation of existing airborne momentum per second during a matching fast look turn and side strafe. Set to 0 to disable.");
		JumpTakeoffDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Jump", "TakeoffDelaySeconds", 0.02f, "Time between jump input and upward movement. Vanilla is 0.15 seconds.");
		JumpStaminaMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Jump", "StaminaCostMultiplier", 0.5f, "Multiplier on the normal jump stamina cost of 0.08. Default 0.5 costs 0.04.");
		DebugOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ShowStatus", false, "Show local-player and input status for troubleshooting.");
		DebugFallDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogFallDamage", false, "Log local-player landing and fall-damage events for troubleshooting.");
		DebugAirStrafe = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogAirStrafe", false, "Log local airborne side-strafing directions and velocities for troubleshooting.");
		Log.LogInfo((object)("Configuration: enabled=" + Enabled.Value + " speedometer=" + ShowSpeedometer.Value + " showStatus=" + DebugOverlay.Value + " logFallDamage=" + DebugFallDamage.Value + " logAirStrafe=" + DebugAirStrafe.Value));
		_harmony = new Harmony("Tim.SourceBhop");
		_harmony.PatchAll(typeof(Plugin).Assembly);
		RequiredNetworkPrefabPatch.Register(NetworkManager.Singleton);
		PatchJumpMethods();
		Log.LogInfo((object)"Source Bhop loaded");
	}

	private void OnEnable()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Source Bhop component enabled");
	}

	private void Start()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Source Bhop component started");
	}

	private void PatchJumpMethods()
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Expected O, but got Unknown
		//IL_00b3: Expected O, but got Unknown
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Expected O, but got Unknown
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayerControllerB), "Jump_performed", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(JumpCostPatch), "Prefix", (Type[])null, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(JumpCostPatch), "Postfix", (Type[])null, (Type[])null);
			if (methodInfo != null && methodInfo2 != null && methodInfo3 != null && AccessTools.Field(typeof(PlayerControllerB), "sprintMeter") != null && AccessTools.Field(typeof(PlayerControllerB), "isJumping") != null)
			{
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)"Jump stamina patch installed");
			}
			else
			{
				Log.LogError((object)"Could not find the jump stamina hook; vanilla jump cost remains active.");
			}
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Jump stamina patch failed: " + ex));
		}
		try
		{
			Type type = null;
			Type[] nestedTypes = typeof(PlayerControllerB).GetNestedTypes(BindingFlags.NonPublic);
			foreach (Type type2 in nestedTypes)
			{
				if (type2.Name.StartsWith("<PlayerJump>d__", StringComparison.Ordinal))
				{
					type = type2;
					break;
				}
			}
			MethodInfo methodInfo4 = ((type == null) ? null : AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null));
			MethodInfo methodInfo5 = AccessTools.Method(typeof(JumpTakeoffPatch), "Transpiler", (Type[])null, (Type[])null);
			if (methodInfo4 != null && methodInfo5 != null)
			{
				_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo5), (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)"Jump takeoff patch installed");
			}
			else
			{
				Log.LogError((object)"Could not find the jump takeoff hook; vanilla delay remains active.");
			}
		}
		catch (Exception ex2)
		{
			Log.LogError((object)("Jump takeoff patch failed: " + ex2));
		}
	}

	private void OnGUI()
	{
		//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)
		//IL_00d6: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Expected O, but got Unknown
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Expected O, but got Unknown
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_026d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0272: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_0292: Unknown result type (might be due to invalid IL or missing references)
		//IL_029e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
		if (DebugOverlay.Value && !_loggedGui)
		{
			_loggedGui = true;
			Log.LogInfo((object)"Debug display is running");
		}
		if (DebugOverlay.Value)
		{
			if (_statusStyle == null)
			{
				_statusStyle = new GUIStyle(GUI.skin.label);
				_statusStyle.fontSize = 14;
				_statusStyle.fontStyle = (FontStyle)1;
				_statusStyle.alignment = (TextAnchor)3;
				_statusStyle.normal.textColor = Color.white;
			}
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(12f, 12f, Mathf.Max(100f, (float)Screen.width - 24f), 32f);
			Color color = GUI.color;
			GUI.color = new Color(0f, 0f, 0f, 0.8f);
			GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture);
			GUI.color = Color.white;
			GUI.Label(new Rect(((Rect)(ref val)).x + 8f, ((Rect)(ref val)).y, ((Rect)(ref val)).width - 16f, ((Rect)(ref val)).height), "SOURCE BHOP 0.3.9  " + Movement.DebugStatus(), _statusStyle);
			GUI.color = color;
		}
		if (ShowSpeedometer.Value && Movement.TryGetCurrentSpeed(out var speed))
		{
			if (_speedometerStyle == null)
			{
				_speedometerStyle = new GUIStyle(GUI.skin.label);
				_speedometerStyle.alignment = (TextAnchor)4;
				_speedometerStyle.fontSize = 18;
				_speedometerStyle.fontStyle = (FontStyle)1;
				_speedometerStyle.normal.textColor = Color.white;
			}
			float num = ((Corner.Value == SpeedometerCorner.TopRight || Corner.Value == SpeedometerCorner.BottomRight) ? ((float)Screen.width - 180f - 16f) : 16f);
			float num2 = ((Corner.Value == SpeedometerCorner.BottomLeft || Corner.Value == SpeedometerCorner.BottomRight) ? ((float)Screen.height - 36f - 16f) : 16f);
			if (DebugOverlay.Value && (Corner.Value == SpeedometerCorner.TopLeft || Corner.Value == SpeedometerCorner.TopRight))
			{
				num2 = 52f;
			}
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(Mathf.Max(0f, num), Mathf.Max(0f, num2), 180f, 36f);
			Color color2 = GUI.color;
			GUI.color = new Color(0f, 0f, 0f, 0.65f);
			GUI.DrawTexture(val2, (Texture)(object)Texture2D.whiteTexture);
			GUI.color = Color.white;
			GUI.Label(val2, "SPEED  " + speed.ToString("0.0", CultureInfo.InvariantCulture) + " u/s", _speedometerStyle);
			GUI.color = color2;
		}
	}

	private void Update()
	{
		if (DebugOverlay.Value && !(Time.unscaledTime < _nextStatusLog))
		{
			_nextStatusLog = Time.unscaledTime + 10f;
			Log.LogInfo((object)("Runtime status: " + Movement.DebugStatus()));
		}
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
[HarmonyPatch(typeof(NetworkManager), "SetSingleton")]
internal static class RequiredNetworkPrefabPatch
{
	private static readonly FieldInfo GlobalObjectIdHash = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.NonPublic);

	private static NetworkManager _registeredManager;

	private static GameObject _prefab;

	private static void Postfix(NetworkManager __instance)
	{
		Register(__instance);
	}

	internal static void Register(NetworkManager __instance)
	{
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)NetworkManager.Singleton || (Object)(object)_registeredManager == (Object)(object)__instance)
		{
			return;
		}
		Plugin.NetworkRequirementReady = false;
		if (GlobalObjectIdHash == null || GlobalObjectIdHash.FieldType != typeof(uint) || __instance.NetworkConfig == null)
		{
			Plugin.Log.LogError((object)"Cannot require Source Bhop for the lobby: Netcode prefab registration is unavailable.");
			return;
		}
		try
		{
			if ((Object)(object)_prefab == (Object)null)
			{
				_prefab = new GameObject("Tim.SourceBhop Required Prefab");
				GameObject prefab = _prefab;
				((Object)prefab).hideFlags = (HideFlags)(((Object)prefab).hideFlags | 0x3D);
				Object.DontDestroyOnLoad((Object)(object)_prefab);
				NetworkObject obj = _prefab.AddComponent<NetworkObject>();
				GlobalObjectIdHash.SetValue(obj, GetHash("Tim.SourceBhop"));
			}
			__instance.NetworkConfig.ForceSamePrefabs = true;
			__instance.PrefabHandler.AddNetworkPrefab(_prefab);
			if (!__instance.NetworkConfig.Prefabs.Contains(_prefab))
			{
				throw new InvalidOperationException("Netcode did not add the required prefab.");
			}
			_registeredManager = __instance;
			Plugin.NetworkRequirementReady = true;
			Plugin.Log.LogInfo((object)("Source Bhop network requirement registered (hash=" + GetHash("Tim.SourceBhop") + ")."));
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Cannot require Source Bhop for the lobby: " + ex));
		}
	}

	private static uint GetHash(string value)
	{
		uint num = 17u;
		foreach (char c in value)
		{
			num = (num * 31) ^ c;
		}
		return num;
	}
}
internal static class Movement
{
	private static readonly FieldInfo SprintMultiplier = AccessTools.Field(typeof(PlayerControllerB), "sprintMultiplier");

	private static readonly FieldInfo IsJumping = AccessTools.Field(typeof(PlayerControllerB), "isJumping");

	private static readonly FieldInfo IsFallingFromJump = AccessTools.Field(typeof(PlayerControllerB), "isFallingFromJump");

	private static readonly FieldInfo IsFallingNoJump = AccessTools.Field(typeof(PlayerControllerB), "isFallingNoJump");

	private static readonly MethodInfo JumpPerformed = AccessTools.Method(typeof(PlayerControllerB), "Jump_performed", (Type[])null, (Type[])null);

	private static PlayerControllerB _player;

	private static Vector3 _velocity;

	private static bool _hasVelocity;

	private static InputAction _jumpAction;

	private static int _walkingHookCalls;

	private static int _lateHookCalls;

	private static float _nextAirTraceTime;

	private static int _pendingAirTraceFrame = -1;

	private static string _pendingAirTrace;

	private static float _lastBodyYaw;

	private static bool _hasBodyYaw;

	internal static bool TryGetCurrentSpeed(out float speed)
	{
		//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_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		speed = 0f;
		GameNetworkManager instance = GameNetworkManager.Instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)instance.localPlayerController == (Object)null)
		{
			return false;
		}
		PlayerControllerB localPlayerController = instance.localPlayerController;
		if (!localPlayerController.isPlayerControlled || localPlayerController.isPlayerDead || localPlayerController.isFreeCamera || (Object)(object)localPlayerController.thisController == (Object)null || (Object)(object)localPlayerController.quickMenuManager == (Object)null || localPlayerController.quickMenuManager.isMenuOpen)
		{
			return false;
		}
		Vector3 velocity = localPlayerController.thisController.velocity;
		Vector2 val = new Vector2(velocity.x, velocity.z);
		speed = ((Vector2)(ref val)).magnitude;
		return true;
	}

	internal static bool Eligible(PlayerControllerB player)
	{
		GameNetworkManager instance = GameNetworkManager.Instance;
		if (Plugin.Enabled.Value && Plugin.NetworkRequirementReady && (Object)(object)instance != (Object)null && (Object)(object)instance.localPlayerController == (Object)(object)player && player.isPlayerControlled && !player.isPlayerDead && !player.disableMoveInput && !player.inSpecialInteractAnimation && !player.isClimbingLadder && !player.isFreeCamera && !player.jetpackControls && !player.isUnderwater && !player.isPlayerSliding && !player.teleportedLastFrame && !player.isTypingChat && player.isMovementHindered == 0 && (Object)(object)player.quickMenuManager != (Object)null && !player.quickMenuManager.isMenuOpen)
		{
			return (Object)(object)player.thisController != (Object)null;
		}
		return false;
	}

	internal static string DebugStatus()
	{
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		GameNetworkManager instance = GameNetworkManager.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return "waiting for game manager";
		}
		PlayerControllerB localPlayerController = instance.localPlayerController;
		if ((Object)(object)localPlayerController == (Object)null)
		{
			return "waiting for local player";
		}
		if (_jumpAction == null && (Object)(object)InputSystem.actions != (Object)null)
		{
			_jumpAction = InputSystem.actions.FindAction("Jump", false);
		}
		object[] array = new object[16]
		{
			"eligible=",
			Eligible(localPlayerController),
			" controlled=",
			localPlayerController.isPlayerControlled,
			" dead=",
			localPlayerController.isPlayerDead,
			" grounded=",
			(Object)(object)localPlayerController.thisController != (Object)null && localPlayerController.thisController.isGrounded,
			" jumpAction=",
			_jumpAction != null,
			" walkHook=",
			_walkingHookCalls,
			" lateHook=",
			_lateHookCalls,
			" speed=",
			null
		};
		object obj;
		if (!((Object)(object)localPlayerController.thisController == (Object)null))
		{
			Vector3 velocity = localPlayerController.thisController.velocity;
			obj = ((Vector3)(ref velocity)).magnitude.ToString("0.0", CultureInfo.InvariantCulture);
		}
		else
		{
			obj = "n/a";
		}
		array[15] = obj;
		return string.Concat(array);
	}

	internal static void TryAutoHopAfterLanding(PlayerControllerB player)
	{
		//IL_00ce: 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)
		GameNetworkManager instance = GameNetworkManager.Instance;
		if ((Object)(object)instance != (Object)null && (Object)(object)instance.localPlayerController == (Object)(object)player)
		{
			_lateHookCalls++;
		}
		if (Eligible(player) && Plugin.AutoHop.Value && !(JumpPerformed == null) && !(IsJumping == null) && !(IsFallingFromJump == null) && !(IsFallingNoJump == null) && IsJumpHeld() && player.thisController.isGrounded && !(bool)IsJumping.GetValue(player) && !(bool)IsFallingFromJump.GetValue(player) && !(bool)IsFallingNoJump.GetValue(player))
		{
			JumpPerformed.Invoke(player, new object[1] { (object)default(CallbackContext) });
		}
	}

	internal static Vector3 AdjustBaseVelocity(Vector3 vanilla, PlayerControllerB player)
	{
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0266: Unknown result type (might be due to invalid IL or missing references)
		//IL_0270: Unknown result type (might be due to invalid IL or missing references)
		//IL_0275: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0289: Unknown result type (might be due to invalid IL or missing references)
		//IL_0294: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0372: Unknown result type (might be due to invalid IL or missing references)
		//IL_0377: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0428: Unknown result type (might be due to invalid IL or missing references)
		//IL_045d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0462: Unknown result type (might be due to invalid IL or missing references)
		//IL_0404: Unknown result type (might be due to invalid IL or missing references)
		//IL_0686: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_060a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0654: Unknown result type (might be due to invalid IL or missing references)
		//IL_0580: Unknown result type (might be due to invalid IL or missing references)
		//IL_0585: Unknown result type (might be due to invalid IL or missing references)
		//IL_058a: Unknown result type (might be due to invalid IL or missing references)
		//IL_058f: Unknown result type (might be due to invalid IL or missing references)
		GameNetworkManager instance = GameNetworkManager.Instance;
		bool flag = (Object)(object)instance != (Object)null && (Object)(object)instance.localPlayerController == (Object)(object)player;
		if (flag)
		{
			_walkingHookCalls++;
		}
		bool flag2 = flag && Plugin.DebugAirStrafe.Value && (Object)(object)player.thisController != (Object)null && !player.thisController.isGrounded && Mathf.Abs(player.moveInputVector.x) > 0.2f && Time.unscaledTime >= _nextAirTraceTime;
		if (flag2)
		{
			_nextAirTraceTime = Time.unscaledTime + 0.05f;
		}
		if (!Eligible(player) || SprintMultiplier == null || IsJumping == null)
		{
			if (flag2)
			{
				Plugin.Log.LogInfo((object)("AirTrace frame=" + Time.frameCount + " inactive eligible=" + Eligible(player) + " sprintField=" + (SprintMultiplier != null) + " jumpingField=" + (IsJumping != null) + " input=" + FormatInput(player.moveInputVector)));
			}
			Reset();
			return vanilla;
		}
		if ((Object)(object)_player != (Object)(object)player || !_hasVelocity)
		{
			_player = player;
			_velocity = player.thisController.velocity;
			_velocity.y = 0f;
			_hasVelocity = true;
			_hasBodyYaw = false;
		}
		float y = ((Component)player).transform.eulerAngles.y;
		float num = (_hasBodyYaw ? Mathf.DeltaAngle(_lastBodyYaw, y) : 0f);
		_lastBodyYaw = y;
		_hasBodyYaw = true;
		float deltaTime = Time.deltaTime;
		if (deltaTime <= 0f)
		{
			return vanilla;
		}
		Vector3 velocity = (flag2 ? player.thisController.velocity : Vector3.zero);
		Vector3 velocity2 = (flag2 ? _velocity : Vector3.zero);
		float num2 = (flag2 ? ((Component)player).transform.eulerAngles.y : 0f);
		float num3 = ((flag2 && (Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform.eulerAngles.y : 0f);
		Vector2 input = Vector2.ClampMagnitude(player.moveInputVector, 1f);
		Vector3 val = ((Component)player).transform.right * input.x + ((Component)player).transform.forward * input.y;
		val.y = 0f;
		float num4 = Mathf.Min(1f, ((Vector3)(ref val)).magnitude);
		if (num4 > 0.0001f)
		{
			val /= ((Vector3)(ref val)).magnitude;
		}
		float num5 = Mathf.Max(0f, (float)SprintMultiplier.GetValue(player));
		float num6 = Mathf.Max(0f, player.movementSpeed) / Mathf.Max(0.1f, player.carryWeight) * num5 * num4;
		bool flag3 = (bool)IsJumping.GetValue(player);
		bool isGrounded = player.thisController.isGrounded;
		bool flag4 = Plugin.AutoHop.Value && IsJumpHeld();
		Vector2 val2 = new Vector2(_velocity.x, _velocity.z);
		float magnitude = ((Vector2)(ref val2)).magnitude;
		bool flag5 = isGrounded && (flag3 || flag4) && magnitude > num6;
		float num7 = num6 * Mathf.Clamp01(Plugin.AirWishSpeedFraction.Value);
		float num8 = (flag2 ? Vector3.Dot(_velocity, val) : 0f);
		float num9 = Mathf.Atan2(_velocity.x, _velocity.z) * 57.29578f;
		float num10 = 0f;
		if (isGrounded && !flag5)
		{
			if (!flag3 && !flag4)
			{
				ApplyFriction(deltaTime);
			}
			Accelerate(val, num6, Mathf.Max(0f, Plugin.GroundAcceleration.Value), deltaTime);
		}
		else
		{
			Accelerate(val, num7, Mathf.Max(0f, Plugin.AirAcceleration.Value), deltaTime, num6);
			Vector2 val3 = new Vector2(_velocity.x, _velocity.z);
			float magnitude2 = ((Vector2)(ref val3)).magnitude;
			if (Mathf.Abs(input.x) > 0.1f && magnitude > 0.001f && magnitude2 > 0.001f && magnitude2 < magnitude)
			{
				float num11 = magnitude / magnitude2;
				_velocity.x *= num11;
				_velocity.z *= num11;
			}
			if (!isGrounded && Mathf.Abs(input.x) > 0.2f && magnitude > 0.001f && num * input.x > 0f)
			{
				float num12 = Mathf.Atan2(_velocity.x, _velocity.z) * 57.29578f;
				float num13 = Mathf.DeltaAngle(num9, num12) * Mathf.Sign(num);
				float num14 = Mathf.Max(0f, Mathf.Abs(num) - num13);
				num10 = Mathf.Min(num14, Mathf.Max(0f, Plugin.AirTurnAssistRate.Value) * deltaTime);
				_velocity = Quaternion.Euler(0f, Mathf.Sign(num) * num10, 0f) * _velocity;
			}
		}
		if (flag2)
		{
			_pendingAirTraceFrame = Time.frameCount;
			_pendingAirTrace = string.Format(CultureInfo.InvariantCulture, "AirTrace frame={0} input={1} dt={2:0.000} bodyYawBefore={3:0.0} cameraYawBefore={4:0.0} wish={5} actualBefore={6} storedBefore={7} cap={8:0.00} projected={9:0.00} room={10:0.00} lookTurn={11:0.00} assist={12:0.00} storedAfter={13}", Time.frameCount, FormatInput(input), deltaTime, num2, num3, FormatHorizontal(val), FormatHorizontal(velocity), FormatHorizontal(velocity2), num7, num8, num7 - num8, num, num10, FormatHorizontal(_velocity));
		}
		return new Vector3(_velocity.x, vanilla.y, _velocity.z);
	}

	internal static void LogAirStrafeAfterLook(PlayerControllerB player)
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		if (_pendingAirTraceFrame == Time.frameCount && _pendingAirTrace != null && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)(object)player))
		{
			Plugin.Log.LogInfo((object)(_pendingAirTrace + string.Format(CultureInfo.InvariantCulture, " bodyYawAfter={0:0.0} cameraYawAfter={1:0.0} actualAfter={2}", ((Component)player).transform.eulerAngles.y, ((Object)(object)player.gameplayCamera == (Object)null) ? 0f : ((Component)player.gameplayCamera).transform.eulerAngles.y, FormatHorizontal(player.thisController.velocity))));
			_pendingAirTrace = null;
			_pendingAirTraceFrame = -1;
		}
	}

	private static string FormatInput(Vector2 input)
	{
		return string.Format(CultureInfo.InvariantCulture, "({0:0.00},{1:0.00})", input.x, input.y);
	}

	private static string FormatHorizontal(Vector3 velocity)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		CultureInfo invariantCulture = CultureInfo.InvariantCulture;
		Vector2 val = new Vector2(velocity.x, velocity.z);
		return string.Format(invariantCulture, "{0:0.00}@{1:0.0}", ((Vector2)(ref val)).magnitude, Mathf.Atan2(velocity.x, velocity.z) * 57.29578f);
	}

	private static bool IsJumpHeld()
	{
		if (_jumpAction == null && (Object)(object)InputSystem.actions != (Object)null)
		{
			_jumpAction = InputSystem.actions.FindAction("Jump", false);
		}
		if (_jumpAction != null)
		{
			return _jumpAction.IsPressed();
		}
		return false;
	}

	private static void ApplyFriction(float dt)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		Vector2 val = new Vector2(_velocity.x, _velocity.z);
		float magnitude = ((Vector2)(ref val)).magnitude;
		if (!(magnitude < 0.0001f))
		{
			float num = Mathf.Max(magnitude, Mathf.Max(0f, Plugin.StopSpeed.Value));
			float num2 = Mathf.Max(0f, magnitude - num * Mathf.Max(0f, Plugin.GroundFriction.Value) * dt);
			float num3 = num2 / magnitude;
			_velocity.x *= num3;
			_velocity.z *= num3;
		}
	}

	private static void Accelerate(Vector3 direction, float directionalLimit, float acceleration, float dt)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		Accelerate(direction, directionalLimit, acceleration, dt, directionalLimit);
	}

	private static void Accelerate(Vector3 direction, float directionalLimit, float acceleration, float dt, float uncappedWishSpeed)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		if (!(directionalLimit <= 0f) && !(acceleration <= 0f))
		{
			float num = Vector3.Dot(_velocity, direction);
			float num2 = directionalLimit - num;
			if (!(num2 <= 0f))
			{
				float num3 = Mathf.Min(num2, acceleration * uncappedWishSpeed * dt);
				_velocity += direction * num3;
			}
		}
	}

	internal static void Reset()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		_player = null;
		_velocity = Vector3.zero;
		_hasVelocity = false;
		_hasBodyYaw = false;
	}
}
[HarmonyPatch(typeof(PlayerControllerB), "Update")]
internal static class PlayerUpdatePatch
{
	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
	{
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Expected O, but got Unknown
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(source);
		MethodInfo methodInfo = AccessTools.Method(typeof(Movement), "AdjustBaseVelocity", (Type[])null, (Type[])null);
		int num = 0;
		for (int i = 3; i < list.Count; i++)
		{
			FieldInfo fieldInfo = list[i - 2].operand as FieldInfo;
			MethodInfo methodInfo2 = list[i - 1].operand as MethodInfo;
			if (!(fieldInfo == null) && !(fieldInfo.Name != "sprintMultiplier") && !(methodInfo2 == null) && !(methodInfo2.DeclaringType != typeof(Vector3)) && !(methodInfo2.Name != "op_Multiply") && IsStoreLocal(list[i].opcode))
			{
				list.Insert(i, new CodeInstruction(OpCodes.Ldarg_0, (object)null));
				list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo));
				num++;
				break;
			}
		}
		if (num != 1)
		{
			Plugin.Log.LogError((object)"Could not find the walking velocity hook; vanilla movement remains active.");
		}
		return list;
	}

	private static bool IsStoreLocal(OpCode opcode)
	{
		if (!(opcode == OpCodes.Stloc) && !(opcode == OpCodes.Stloc_S) && !(opcode == OpCodes.Stloc_0) && !(opcode == OpCodes.Stloc_1) && !(opcode == OpCodes.Stloc_2))
		{
			return opcode == OpCodes.Stloc_3;
		}
		return true;
	}
}
[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
internal static class PlayerLateUpdatePatch
{
	private static void Postfix(PlayerControllerB __instance)
	{
		Movement.TryAutoHopAfterLanding(__instance);
		Movement.LogAirStrafeAfterLook(__instance);
	}
}
internal static class JumpCostPatch
{
	private struct JumpState
	{
		internal bool Active;

		internal bool WasJumping;

		internal float StaminaBefore;
	}

	private static readonly FieldInfo SprintMeter = AccessTools.Field(typeof(PlayerControllerB), "sprintMeter");

	private static readonly FieldInfo IsJumping = AccessTools.Field(typeof(PlayerControllerB), "isJumping");

	private static void Prefix(PlayerControllerB __instance, out JumpState __state)
	{
		__state = default(JumpState);
		GameNetworkManager instance = GameNetworkManager.Instance;
		if (Plugin.Enabled.Value && Plugin.NetworkRequirementReady && (Object)(object)instance != (Object)null && (Object)(object)instance.localPlayerController == (Object)(object)__instance)
		{
			__state.Active = true;
			__state.WasJumping = (bool)IsJumping.GetValue(__instance);
			__state.StaminaBefore = (float)SprintMeter.GetValue(__instance);
		}
	}

	private static void Postfix(PlayerControllerB __instance, JumpState __state)
	{
		if (__state.Active && !__state.WasJumping && (bool)IsJumping.GetValue(__instance))
		{
			float num = 0.08f * Mathf.Clamp01(Plugin.JumpStaminaMultiplier.Value);
			SprintMeter.SetValue(__instance, Mathf.Clamp01(__state.StaminaBefore - num));
		}
	}
}
internal static class JumpTakeoffPatch
{
	private static float ResolveDelay(float vanillaDelay)
	{
		if (!Plugin.Enabled.Value || !Plugin.NetworkRequirementReady)
		{
			return vanillaDelay;
		}
		return Mathf.Clamp(Plugin.JumpTakeoffDelaySeconds.Value, 0f, vanillaDelay);
	}

	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
	{
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(source);
		MethodInfo methodInfo = AccessTools.Method(typeof(JumpTakeoffPatch), "ResolveDelay", (Type[])null, (Type[])null);
		int num = 0;
		for (int i = 0; i < list.Count - 1; i++)
		{
			ConstructorInfo constructorInfo = list[i + 1].operand as ConstructorInfo;
			if (!(list[i].opcode != OpCodes.Ldc_R4) && list[i].operand is float && (float)list[i].operand == 0.15f && !(constructorInfo == null) && !(constructorInfo.DeclaringType != typeof(WaitForSeconds)))
			{
				list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo));
				num++;
				break;
			}
		}
		if (num != 1)
		{
			Plugin.Log.LogError((object)"Could not find the jump takeoff delay; vanilla delay remains active.");
		}
		return list;
	}
}
[HarmonyPatch(typeof(PlayerControllerB), "PlayerHitGroundEffects")]
internal static class FallLandingDebugPatch
{
	private static readonly FieldInfo FallValue = AccessTools.Field(typeof(PlayerControllerB), "fallValue");

	private static readonly FieldInfo FallValueUncapped = AccessTools.Field(typeof(PlayerControllerB), "fallValueUncapped");

	private static readonly FieldInfo TakingFallDamage = AccessTools.Field(typeof(PlayerControllerB), "takingFallDamage");

	private static readonly FieldInfo IsSpeedCheating = AccessTools.Field(typeof(PlayerControllerB), "isSpeedCheating");

	private static void Prefix(PlayerControllerB __instance)
	{
		if (Plugin.DebugFallDamage.Value && IsLocal(__instance))
		{
			float num = (float)FallValueUncapped.GetValue(__instance);
			bool flag = (bool)TakingFallDamage.GetValue(__instance);
			if (!(num > -30f) || flag)
			{
				Plugin.Log.LogInfo((object)string.Concat("Landing: fall=", ((float)FallValue.GetValue(__instance)).ToString("0.0", CultureInfo.InvariantCulture), " uncapped=", num.ToString("0.0", CultureInfo.InvariantCulture), " taking=", flag, " speedCheat=", IsSpeedCheating.GetValue(__instance), " health=", __instance.health));
			}
		}
	}

	internal static bool IsLocal(PlayerControllerB player)
	{
		GameNetworkManager instance = GameNetworkManager.Instance;
		if ((Object)(object)instance != (Object)null)
		{
			return (Object)(object)instance.localPlayerController == (Object)(object)player;
		}
		return false;
	}
}
[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")]
internal static class FallDamageDebugPatch
{
	private static void Prefix(PlayerControllerB __instance, int damageNumber, bool fallDamage, out int __state)
	{
		__state = __instance.health;
		if (Plugin.DebugFallDamage.Value && fallDamage && FallLandingDebugPatch.IsLocal(__instance))
		{
			Plugin.Log.LogInfo((object)("Fall damage requested: " + damageNumber + " healthBefore=" + __state));
		}
	}

	private static void Postfix(PlayerControllerB __instance, bool fallDamage, int __state)
	{
		if (Plugin.DebugFallDamage.Value && fallDamage && FallLandingDebugPatch.IsLocal(__instance))
		{
			Plugin.Log.LogInfo((object)("Fall damage result: healthBefore=" + __state + " healthAfter=" + __instance.health + " dead=" + __instance.isPlayerDead));
		}
	}
}