Decompiled source of ArcadeMovement v1.0.1

Mods/ArcadeMovement.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using ArcadeMovement;
using ArcadeMovement.Integration;
using ArcadeMovement.Logging;
using ArcadeMovement.Patches;
using Fusion;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(ModMain), "Arcade Movement", "1.0.0", "Generic", null)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ArcadeMovement")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+852064e45704d7481eb1c862897c77a4e247cc87")]
[assembly: AssemblyProduct("Arcade Movement")]
[assembly: AssemblyTitle("Arcade Movement")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ArcadeMovement
{
	public sealed class ModMain : MelonMod
	{
		public override void OnInitializeMelon()
		{
			AmLog.Msg("initialized.");
			SprintPatch.SetupPreferences();
			ADVRIntegration.HookIntoModLoader();
			ADVRIntegration.EvaluateAndApply();
		}
	}
}
namespace ArcadeMovement.Patches
{
	internal static class SprintPatch
	{
		private class SprintState
		{
			public bool IsSprinting;

			public float CooldownEndTime;

			public bool CooldownNotified;

			public float Meter = -1f;

			public float LastUpdateAt = -1f;

			public bool RechargeBeganLogged;

			public bool IsDashing;

			public float DashEndTime;

			public int DashCharges = -1;

			public float NextDashRechargeAt = -1f;
		}

		internal static class HarmonyHooks
		{
			[HarmonyPatch(typeof(PlayerLiving), "Update")]
			internal static class PlayerLiving_Update_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix(PlayerLiving __instance)
				{
					PlayerLiving_Update_Postfix_Impl(__instance);
				}
			}

			[HarmonyPatch(typeof(GameHandler), "ChangePlayerMoveSpeed")]
			internal static class GameHandler_ChangePlayerMoveSpeed_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix(float val)
				{
					GameHandler_ChangePlayerMoveSpeed_Postfix_Impl(val);
				}
			}

			[HarmonyPatch(typeof(PlayerLiving), "MoveSpeed_ValueChanged")]
			internal static class PlayerLiving_MoveSpeed_ValueChanged_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix(PlayerLiving __instance)
				{
					PlayerLiving_MoveSpeed_ValueChanged_Postfix_Impl(__instance);
				}
			}

			[HarmonyPatch(typeof(SettingsMod), "OnApplyClick")]
			internal static class SettingsMod_OnApplyClick_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix()
				{
					try
					{
						ApplyDominantHandSelection(GetMovementControllerSettingText());
					}
					catch
					{
					}
				}
			}
		}

		private const string MultKey = "arcade_movement_sprint";

		private const string UnlimitedSprintItemId = "am_unlimited_sprint";

		private const string UpgradedDashItemId = "am_upgraded_dash";

		private const int UpgradedDashExtraCharges = 1;

		private const float UpgradedDashRechargeMultiplier = 0.8f;

		private static float SprintMultiplier = 1.8f;

		private static float SprintDuration = 3f;

		private static float SprintCooldown = 5f;

		private static float SprintDrainPerSecond = 1f;

		private static float SprintRechargePerSecond = 1f;

		private static bool DashEnabled = true;

		private static float DashSpeedMultiplier = 3f;

		private static float DashDurationSeconds = 0.2f;

		private static float DashRechargeSeconds = 5f;

		private static int DashMaxCharges = 1;

		private static float DashDoubleClickWindow = 0.25f;

		private static bool DebugLogs = false;

		private static float SmoothCheckInterval = 0.5f;

		private static float _lastSmoothCheckAt = -1f;

		private static bool _lastSmoothSelected = true;

		private static float _lastStatusLogAt = -1f;

		private static float _statusLogMinInterval = 1f;

		private static Harmony? _harmony;

		private static InputAction? _leftClick;

		private static InputAction? _rightClick;

		private static int _clickHeldCount;

		private static string? _lastMovementControllerText;

		private static float _lastHandCheckAt = -1f;

		private static float _lastDashClickReleasedAt = -1f;

		private static float _dashRequestAt = -1f;

		private static bool _sprintOnLeft = false;

		private static bool _dashOnLeft = false;

		private static string? _lastMovementTypeText;

		private static string? _lastControllerMoveTypeText;

		private static readonly ConditionalWeakTable<PlayerLiving, SprintState> _states = new ConditionalWeakTable<PlayerLiving, SprintState>();

		private static MelonPreferences_Category? _prefCat;

		private static MelonPreferences_Entry<float>? _prefSprintMult;

		private static MelonPreferences_Entry<float>? _prefSprintDur;

		private static MelonPreferences_Entry<float>? _prefSprintCd;

		private static MelonPreferences_Entry<float>? _prefDrainRate;

		private static MelonPreferences_Entry<float>? _prefRechargeRate;

		private static MelonPreferences_Entry<bool>? _prefDashEnabled;

		private static MelonPreferences_Entry<float>? _prefDashSpeedMult;

		private static MelonPreferences_Entry<float>? _prefDashDuration;

		private static MelonPreferences_Entry<float>? _prefDashRecharge;

		private static MelonPreferences_Entry<int>? _prefDashMaxCharges;

		private static MelonPreferences_Entry<float>? _prefDashDoubleClick;

		private static MelonPreferences_Entry<bool>? _prefDebugLogs;

		private static MelonPreferences_Entry<float>? _prefSmoothCheckInterval;

		private static MelonPreferences_Entry<float>? _prefStatusLogMinInterval;

		public static bool IsApplied { get; private set; }

		public static void SetupPreferences()
		{
			try
			{
				_prefCat = MelonPreferences.CreateCategory("ArcadeMovement", "Arcade Movement");
				_prefSprintMult = _prefCat.CreateEntry<float>("SprintMultiplier", SprintMultiplier, "Sprint speed multiplier", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefSprintDur = _prefCat.CreateEntry<float>("SprintDurationSeconds", SprintDuration, "Sprint meter capacity (seconds)", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefSprintCd = _prefCat.CreateEntry<float>("SprintCooldownSeconds", SprintCooldown, "Recharge delay after sprint ends (seconds)", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefDrainRate = _prefCat.CreateEntry<float>("SprintDrainPerSecond", SprintDrainPerSecond, "Drain rate while sprinting (sec/sec)", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefRechargeRate = _prefCat.CreateEntry<float>("SprintRechargePerSecond", SprintRechargePerSecond, "Recharge rate after delay (sec/sec)", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefDashEnabled = _prefCat.CreateEntry<bool>("DashEnabled", DashEnabled, "Enable dash on double-click", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefDashSpeedMult = _prefCat.CreateEntry<float>("DashSpeedMultiplier", DashSpeedMultiplier, "Dash speed multiplier", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefDashDuration = _prefCat.CreateEntry<float>("DashDurationSeconds", DashDurationSeconds, "Dash duration (seconds)", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefDashRecharge = _prefCat.CreateEntry<float>("DashRechargeSeconds", DashRechargeSeconds, "Seconds per dash recharge", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefDashMaxCharges = _prefCat.CreateEntry<int>("DashMaxCharges", DashMaxCharges, "Max dash charges", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefDashDoubleClick = _prefCat.CreateEntry<float>("DashDoubleClickWindowSeconds", DashDoubleClickWindow, "Double-click window (seconds)", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefDebugLogs = _prefCat.CreateEntry<bool>("EnableDebugLogs", false, "Verbose logging for troubleshooting", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefSmoothCheckInterval = _prefCat.CreateEntry<float>("SmoothCheckIntervalSeconds", SmoothCheckInterval, "How often to re-check movement settings", (string)null, false, false, (ValueValidator)null, (string)null);
				_prefStatusLogMinInterval = _prefCat.CreateEntry<float>("StatusLogIntervalSeconds", _statusLogMinInterval, "Minimum seconds between status logs", (string)null, false, false, (ValueValidator)null, (string)null);
				ApplyPreferences();
			}
			catch (Exception ex)
			{
				AmLog.Warn("[Sprint] Failed to setup preferences: " + ex.Message);
			}
		}

		public static void ApplyPreferences()
		{
			try
			{
				if (_prefSprintMult != null)
				{
					SprintMultiplier = Math.Max(1f, _prefSprintMult.Value);
				}
				if (_prefSprintDur != null)
				{
					SprintDuration = Math.Max(0.1f, _prefSprintDur.Value);
				}
				if (_prefSprintCd != null)
				{
					SprintCooldown = Math.Max(0f, _prefSprintCd.Value);
				}
				if (_prefDebugLogs != null)
				{
					DebugLogs = _prefDebugLogs.Value;
				}
				AmLog.SetEnabled(DebugLogs);
				if (_prefSmoothCheckInterval != null)
				{
					SmoothCheckInterval = Math.Max(0.1f, _prefSmoothCheckInterval.Value);
				}
				if (_prefStatusLogMinInterval != null)
				{
					_statusLogMinInterval = Math.Max(0.25f, _prefStatusLogMinInterval.Value);
				}
				if (_prefDrainRate != null)
				{
					SprintDrainPerSecond = Math.Max(0.01f, _prefDrainRate.Value);
				}
				if (_prefRechargeRate != null)
				{
					SprintRechargePerSecond = Math.Max(0.01f, _prefRechargeRate.Value);
				}
				if (_prefDashEnabled != null)
				{
					DashEnabled = _prefDashEnabled.Value;
				}
				if (_prefDashSpeedMult != null)
				{
					DashSpeedMultiplier = Math.Max(1f, _prefDashSpeedMult.Value);
				}
				if (_prefDashDuration != null)
				{
					DashDurationSeconds = Math.Max(0.05f, _prefDashDuration.Value);
				}
				if (_prefDashRecharge != null)
				{
					DashRechargeSeconds = Math.Max(0.1f, _prefDashRecharge.Value);
				}
				if (_prefDashMaxCharges != null)
				{
					DashMaxCharges = Math.Max(1, _prefDashMaxCharges.Value);
				}
				if (_prefDashDoubleClick != null)
				{
					DashDoubleClickWindow = Math.Max(0.05f, Math.Min(0.75f, _prefDashDoubleClick.Value));
				}
			}
			catch (Exception ex)
			{
				AmLog.Warn("[Sprint] Failed to apply preferences: " + ex.Message);
			}
		}

		public static void Apply()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			try
			{
				if (!IsApplied)
				{
					_harmony = new Harmony("ArcadeMovement.Sprint");
					_harmony.CreateClassProcessor(typeof(SprintPatch)).Patch();
					SetupInput();
					IsApplied = true;
					AmLog.Msg("[Sprint] Enabled (hold stick/trackpad click to sprint)");
				}
			}
			catch (Exception arg)
			{
				AmLog.Error($"Failed to apply SprintPatch: {arg}");
			}
		}

		public static void Remove()
		{
			try
			{
				if (!IsApplied)
				{
					return;
				}
				try
				{
					InputAction? leftClick = _leftClick;
					if (leftClick != null)
					{
						leftClick.Disable();
					}
					InputAction? rightClick = _rightClick;
					if (rightClick != null)
					{
						rightClick.Disable();
					}
				}
				catch
				{
				}
				_leftClick = null;
				_rightClick = null;
				ClearForCurrentPlayer();
				try
				{
					Harmony? harmony = _harmony;
					if (harmony != null)
					{
						harmony.UnpatchAll((string)null);
					}
				}
				catch
				{
				}
				_harmony = null;
				IsApplied = false;
				AmLog.Msg("[Sprint] Disabled by Mod Manager");
			}
			catch (Exception ex)
			{
				AmLog.Warn("Failed to remove SprintPatch: " + ex.Message);
			}
		}

		private static void SetupInput()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			try
			{
				_leftClick = new InputAction("AM_SprintLeft", (InputActionType)1, (string)null, (string)null, (string)null, (string)null);
				_rightClick = new InputAction("AM_SprintRight", (InputActionType)1, (string)null, (string)null, (string)null, (string)null);
				AddClickBindings(_leftClick, "{LeftHand}");
				AddClickBindings(_rightClick, "{RightHand}");
				_leftClick.started += OnClickStarted;
				_rightClick.started += OnClickStarted;
				_leftClick.canceled += OnClickCanceled;
				_rightClick.canceled += OnClickCanceled;
				ApplyDominantHandSelection(GetMovementControllerSettingText());
				_leftClick.Enable();
				_rightClick.Enable();
				AmLog.Msg("[Sprint] Input wired: dominant=SPRINT, opposite=DASH");
			}
			catch (Exception arg)
			{
				AmLog.Error($"Sprint input setup error: {arg}");
			}
			static void AddClickBindings(InputAction action, string handTag)
			{
				InputAction action2 = action;
				Add("*/" + handTag + "/Primary2DAxisClick");
				Add("<XRController>" + handTag + "/Primary2DAxisClick");
				Add("*/" + handTag + "/thumbstickClicked");
				Add("<XRController>" + handTag + "/thumbstickClicked");
				Add("<ValveIndexController>" + handTag + "/thumbstickClicked");
				Add("*/" + handTag + "/joystickClicked");
				Add("<XRController>" + handTag + "/joystickClicked");
				Add("*/" + handTag + "/trackpadClicked");
				Add("<XRController>" + handTag + "/trackpadClicked");
				Add("<ValveIndexController>" + handTag + "/trackpadClicked");
				Add("*/" + handTag + "/touchpadClicked");
				Add("<XRController>" + handTag + "/touchpadClicked");
				void Add(string path)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					if (!string.IsNullOrEmpty(path))
					{
						InputActionSetupExtensions.AddBinding(action2, path, (string)null, (string)null, (string)null);
					}
				}
			}
		}

		private static void OnClickStarted(CallbackContext ctx)
		{
			if (IsSprintAction(((CallbackContext)(ref ctx)).action))
			{
				_clickHeldCount++;
			}
			try
			{
				string text = ((((CallbackContext)(ref ctx)).action == _leftClick) ? "Left" : ((((CallbackContext)(ref ctx)).action == _rightClick) ? "Right" : "?"));
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				PlayerLiving val = (((Object)(object)iNSTANCE != (Object)null) ? iNSTANCE.playerLiving : null);
				bool flag = IsInitialized();
				if ((Object)(object)val == (Object)null)
				{
					AmLog.Msg($"[Sprint] Press: {text} held={_clickHeldCount} init={flag} player=null (not spawned yet)");
					return;
				}
				if (IsDashAction(((CallbackContext)(ref ctx)).action))
				{
					float unscaledTime = Time.unscaledTime;
					if (DashEnabled && _lastDashClickReleasedAt > 0f && unscaledTime - _lastDashClickReleasedAt <= DashDoubleClickWindow)
					{
						_dashRequestAt = Time.time;
						AmLog.Msg("[Dash] Double-click detected; scheduling dash (hand=" + text + ")");
					}
				}
				bool flag2 = false;
				bool flag3 = false;
				bool flag4 = false;
				string text2 = "?";
				try
				{
					flag2 = ((NetworkBehaviour)val).HasStateAuthority;
				}
				catch
				{
				}
				try
				{
					flag3 = IsWalking(val);
				}
				catch
				{
				}
				try
				{
					flag4 = ((LivingBase)val).isDead;
				}
				catch
				{
				}
				try
				{
					text2 = GetControllerMovementTypeText(val);
				}
				catch
				{
				}
				bool flag5 = false;
				try
				{
					flag5 = IsSmoothMovementSelected();
				}
				catch
				{
				}
				SprintState orCreateValue = _states.GetOrCreateValue(val);
				if (orCreateValue.Meter < 0f)
				{
					orCreateValue.Meter = SprintDuration;
				}
				float time = Time.time;
				float num = Mathf.Max(0f, orCreateValue.CooldownEndTime - time);
				bool flag6 = num > 0f;
				bool isSprinting = orCreateValue.IsSprinting;
				string settingsMovementTypeText = GetSettingsMovementTypeText();
				AmLog.Msg(string.Format("[Sprint] Press: {0} auth={1} init={2} smooth={3} settings='{4}' ctrl='{5}' walking={6} dead={7} sprinting={8} cooldown={9} meter={10:0.00}/{11:0.00}", text, flag2, flag, flag5, settingsMovementTypeText, text2, flag3, flag4, isSprinting, flag6 ? (num.ToString("0.00") + "s") : "no", orCreateValue.Meter, SprintDuration));
			}
			catch
			{
			}
		}

		private static void OnClickCanceled(CallbackContext ctx)
		{
			if (IsSprintAction(((CallbackContext)(ref ctx)).action))
			{
				_clickHeldCount = Math.Max(0, _clickHeldCount - 1);
			}
			try
			{
				string arg = ((((CallbackContext)(ref ctx)).action == _leftClick) ? "Left" : ((((CallbackContext)(ref ctx)).action == _rightClick) ? "Right" : "?"));
				AmLog.Msg($"[Sprint] Click released: {arg} (held={_clickHeldCount})");
			}
			catch
			{
			}
			if (IsDashAction(((CallbackContext)(ref ctx)).action))
			{
				_lastDashClickReleasedAt = Time.unscaledTime;
			}
		}

		private static void PlayerLiving_Update_Postfix_Impl(PlayerLiving __instance)
		{
			//IL_0718: Unknown result type (might be due to invalid IL or missing references)
			//IL_0613: Unknown result type (might be due to invalid IL or missing references)
			//IL_0637: Unknown result type (might be due to invalid IL or missing references)
			//IL_062d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((NetworkBehaviour)__instance).HasStateAuthority || !IsInitialized())
				{
					return;
				}
				LogMovementModeIfChanged(__instance);
				float unscaledTime = Time.unscaledTime;
				if (_lastHandCheckAt < 0f || unscaledTime >= _lastHandCheckAt + SmoothCheckInterval)
				{
					_lastHandCheckAt = unscaledTime;
					string movementControllerSettingText = GetMovementControllerSettingText();
					if (!string.Equals(_lastMovementControllerText, movementControllerSettingText, StringComparison.Ordinal))
					{
						ApplyDominantHandSelection(movementControllerSettingText);
					}
				}
				if (!IsSmoothMovementSelected())
				{
					EnsureSprintCleared(__instance);
					return;
				}
				if (!IsWalking(__instance) || ((LivingBase)__instance).isDead)
				{
					EnsureSprintCleared(__instance);
					return;
				}
				SprintState orCreateValue = _states.GetOrCreateValue(__instance);
				if (orCreateValue.Meter < 0f)
				{
					orCreateValue.Meter = SprintDuration;
				}
				float time = Time.time;
				float num = ((!(orCreateValue.LastUpdateAt < 0f)) ? Mathf.Max(0f, time - orCreateValue.LastUpdateAt) : Time.deltaTime);
				orCreateValue.LastUpdateAt = time;
				bool flag = _clickHeldCount > 0;
				bool flag2 = HasUnlimitedSprintLocal();
				bool flag3 = HasUpgradedDashLocal();
				bool num2 = flag && !orCreateValue.IsSprinting && IsWalking(__instance) && (flag2 || orCreateValue.Meter > 0f);
				if (flag && !orCreateValue.IsSprinting)
				{
					Mathf.Max(0f, orCreateValue.CooldownEndTime - time);
					AmLog.Msg("[Sprint] Update: held=1");
				}
				if (num2)
				{
					orCreateValue.IsSprinting = true;
					orCreateValue.CooldownNotified = false;
					orCreateValue.RechargeBeganLogged = false;
					ApplyMoveSpeedMultiplier(__instance, SprintMultiplier);
					TryHapticPulse(0.1f, 0.2f);
					AmLog.Msg($"[Sprint] START '{GetPlayerObjectName(__instance)}' mult={SprintMultiplier} meter={orCreateValue.Meter:0.00}/{SprintDuration:0.00}");
				}
				if (orCreateValue.IsSprinting)
				{
					if (!flag || !IsWalking(__instance) || ((LivingBase)__instance).isDead)
					{
						orCreateValue.IsSprinting = false;
						orCreateValue.CooldownEndTime = (flag2 ? time : (time + SprintCooldown));
						orCreateValue.CooldownNotified = false;
						ClearMoveSpeedMultiplier(__instance);
						AmLog.Msg(string.Format("[Sprint] END '{0}' reason={1} cooldown={2:0.0}s meter={3:0.00}/{4:0.00}", GetPlayerObjectName(__instance), (!flag) ? "release" : (IsWalking(__instance) ? ("dead=" + ((LivingBase)__instance).isDead) : "mode"), SprintCooldown, orCreateValue.Meter, SprintDuration));
					}
					else if (flag2)
					{
						orCreateValue.Meter = SprintDuration;
						orCreateValue.CooldownEndTime = time;
					}
					else
					{
						float num3 = SprintDrainPerSecond * num;
						if (num3 > 0f)
						{
							float meter = orCreateValue.Meter;
							orCreateValue.Meter = Mathf.Max(0f, orCreateValue.Meter - num3);
							if (meter > 0f && orCreateValue.Meter <= 0f)
							{
								orCreateValue.IsSprinting = false;
								orCreateValue.CooldownEndTime = time + SprintCooldown;
								orCreateValue.CooldownNotified = false;
								ClearMoveSpeedMultiplier(__instance);
								AmLog.Msg($"[Sprint] DEPLETED -> cooldown {SprintCooldown:0.0}s");
							}
						}
					}
				}
				if (!orCreateValue.IsSprinting)
				{
					if (flag2)
					{
						orCreateValue.Meter = SprintDuration;
						orCreateValue.CooldownEndTime = time;
						orCreateValue.RechargeBeganLogged = false;
					}
					else if (time < orCreateValue.CooldownEndTime)
					{
						float num4 = Mathf.Max(0f, orCreateValue.CooldownEndTime - time);
						if (flag && !orCreateValue.CooldownNotified)
						{
							AmLog.Msg($"[Sprint] On cooldown remain={num4:0.0}s meter={orCreateValue.Meter:0.00}/{SprintDuration:0.00}");
							orCreateValue.CooldownNotified = true;
						}
					}
					else if (orCreateValue.Meter < SprintDuration)
					{
						float meter2 = orCreateValue.Meter;
						orCreateValue.Meter = Mathf.Min(SprintDuration, orCreateValue.Meter + SprintRechargePerSecond * num);
						if (!orCreateValue.RechargeBeganLogged)
						{
							AmLog.Msg($"[Sprint] Recharge start meter={meter2:0.00}->{orCreateValue.Meter:0.00}/{SprintDuration:0.00}");
							orCreateValue.RechargeBeganLogged = true;
						}
					}
					else
					{
						orCreateValue.RechargeBeganLogged = false;
					}
				}
				if (!DashEnabled)
				{
					return;
				}
				int num5 = DashMaxCharges + (flag3 ? 1 : 0);
				float num6 = DashRechargeSeconds * (flag3 ? 0.8f : 1f);
				if (orCreateValue.DashCharges < 0)
				{
					orCreateValue.DashCharges = num5;
					if (orCreateValue.DashCharges < num5)
					{
						orCreateValue.NextDashRechargeAt = time + num6;
					}
					else
					{
						orCreateValue.NextDashRechargeAt = -1f;
					}
				}
				if (orCreateValue.DashCharges >= 0)
				{
					if (orCreateValue.DashCharges < num5 && orCreateValue.NextDashRechargeAt <= 0f)
					{
						orCreateValue.NextDashRechargeAt = time + num6;
					}
					else if (orCreateValue.DashCharges >= num5)
					{
						orCreateValue.NextDashRechargeAt = -1f;
					}
				}
				if (orCreateValue.DashCharges < num5 && orCreateValue.NextDashRechargeAt > 0f)
				{
					while (orCreateValue.DashCharges < num5 && time >= orCreateValue.NextDashRechargeAt)
					{
						orCreateValue.DashCharges++;
						orCreateValue.NextDashRechargeAt += num6;
						AmLog.Msg($"[Dash] Recharged -> {orCreateValue.DashCharges}/{num5}");
					}
					if (orCreateValue.DashCharges >= num5)
					{
						orCreateValue.NextDashRechargeAt = -1f;
					}
				}
				if (orCreateValue.IsDashing)
				{
					if (!(time >= orCreateValue.DashEndTime))
					{
						return;
					}
					orCreateValue.IsDashing = false;
					try
					{
						GameHandler iNSTANCE = GameHandler.INSTANCE;
						if (iNSTANCE != null)
						{
							iNSTANCE.ChangePlayerMoveSpeed(__instance.MoveSpeed.GetValueFloat());
						}
					}
					catch
					{
					}
					AmLog.Msg("[Dash] End");
				}
				else
				{
					if (!(_dashRequestAt > 0f))
					{
						return;
					}
					_ = _dashRequestAt;
					_dashRequestAt = -1f;
					if (orCreateValue.DashCharges <= 0)
					{
						AmLog.Msg("[Dash] No charges");
						return;
					}
					if (IsWalking(__instance) && !((LivingBase)__instance).isDead)
					{
						PlayerController playerController = __instance.playerController;
						_ = Vector2.zero;
						try
						{
							if (string.Equals(GetMovementControllerSettingText(), "left", StringComparison.OrdinalIgnoreCase))
							{
								playerController.GetLeftJoystickValue();
							}
							else
							{
								playerController.GetRightJoystickValue();
							}
						}
						catch
						{
						}
						float num7 = 0f;
						try
						{
							num7 = __instance.MoveSpeed.GetValueFloat();
						}
						catch
						{
						}
						float num8 = Math.Max(num7, num7 * DashSpeedMultiplier);
						try
						{
							GameHandler iNSTANCE2 = GameHandler.INSTANCE;
							if (iNSTANCE2 != null)
							{
								PlayerController playerController2 = iNSTANCE2.playerController;
								if (playerController2 != null)
								{
									playerController2.SetSlidingMovementSpeed(num8);
								}
							}
						}
						catch
						{
						}
						orCreateValue.IsDashing = true;
						orCreateValue.DashEndTime = time + DashDurationSeconds;
						orCreateValue.DashCharges--;
						if (orCreateValue.DashCharges < num5 && orCreateValue.NextDashRechargeAt <= 0f)
						{
							orCreateValue.NextDashRechargeAt = time + num6;
						}
						AmLog.Msg($"[Dash] START speed={num8:0.00} charges={orCreateValue.DashCharges}/{num5}");
						try
						{
							GameHandler.INSTANCE.playerController.RpcMpQuickAction((byte)240, (NetworkObject)null, GameHandler.INSTANCE.networkHandler.GetNetworkRunner().LocalPlayer);
							return;
						}
						catch
						{
							return;
						}
					}
					AmLog.Msg($"[Dash] Blocked (walking={IsWalking(__instance)} dead={((LivingBase)__instance).isDead})");
				}
			}
			catch (Exception arg)
			{
				AmLog.Error($"Sprint Update error: {arg}");
			}
		}

		private static void EnsureSprintCleared(PlayerLiving playerLiving)
		{
			if (_states.TryGetValue(playerLiving, out SprintState value) && value.IsSprinting)
			{
				value.IsSprinting = false;
				ClearMoveSpeedMultiplier(playerLiving);
				AmLog.Msg("[Sprint] Cleared sprint for player '" + GetPlayerObjectName(playerLiving) + "'");
			}
		}

		private static void ClearForCurrentPlayer()
		{
			try
			{
				if ((Object)(object)GameHandler.INSTANCE?.playerLiving != (Object)null)
				{
					EnsureSprintCleared(GameHandler.INSTANCE.playerLiving);
				}
			}
			catch
			{
			}
		}

		private static bool IsWalking(PlayerLiving playerLiving)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			PlayerController playerController = playerLiving.playerController;
			if ((Object)(object)playerController == (Object)null)
			{
				return false;
			}
			return (int)playerController.CurrentMovementType == 0;
		}

		private static string GetControllerMovementTypeText(PlayerLiving playerLiving)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerController playerController = playerLiving.playerController;
				if ((Object)(object)playerController == (Object)null)
				{
					return "?";
				}
				MovementType currentMovementType = playerController.CurrentMovementType;
				return ((object)(MovementType)(ref currentMovementType)).ToString();
			}
			catch
			{
				return "?";
			}
		}

		private static bool IsInitialized()
		{
			if ((Object)(object)GameHandler.INSTANCE != (Object)null)
			{
				return GameHandler.INSTANCE.initialized;
			}
			return false;
		}

		private static void ApplyMoveSpeedMultiplier(PlayerLiving playerLiving, float multiplier)
		{
			try
			{
				PlayerStat moveSpeed = playerLiving.MoveSpeed;
				if (moveSpeed == null)
				{
					return;
				}
				float num = 0f;
				try
				{
					num = moveSpeed.GetValueFloat();
				}
				catch
				{
				}
				float num2 = 0f;
				try
				{
					GameHandler iNSTANCE = GameHandler.INSTANCE;
					float? obj2;
					if (iNSTANCE == null)
					{
						obj2 = null;
					}
					else
					{
						PlayerController playerController = iNSTANCE.playerController;
						obj2 = ((playerController != null) ? new float?(playerController.GetWalkingMovementSpeed()) : null);
					}
					float? num3 = obj2;
					num2 = num3.GetValueOrDefault();
				}
				catch
				{
				}
				moveSpeed.ChangeMultiplier("arcade_movement_sprint", multiplier);
				float num4 = num;
				try
				{
					num4 = moveSpeed.GetValueFloat();
				}
				catch
				{
				}
				try
				{
					GameHandler iNSTANCE2 = GameHandler.INSTANCE;
					if (iNSTANCE2 != null)
					{
						iNSTANCE2.ChangePlayerMoveSpeed(num4);
					}
				}
				catch
				{
				}
				float num5 = 0f;
				try
				{
					GameHandler iNSTANCE3 = GameHandler.INSTANCE;
					float? obj6;
					if (iNSTANCE3 == null)
					{
						obj6 = null;
					}
					else
					{
						PlayerController playerController2 = iNSTANCE3.playerController;
						obj6 = ((playerController2 != null) ? new float?(playerController2.GetWalkingMovementSpeed()) : null);
					}
					float? num3 = obj6;
					num5 = num3.GetValueOrDefault();
				}
				catch
				{
				}
				AmLog.Msg(string.Format("[Sprint] Applied speed mult key='{0}' x{1:0.00} stat {2:0.00}->{3:0.00} pc {4:0.00}->{5:0.00}", "arcade_movement_sprint", multiplier, num, num4, num2, num5));
			}
			catch (Exception arg)
			{
				AmLog.Error($"Failed to apply sprint multiplier: {arg}");
			}
		}

		private static void ClearMoveSpeedMultiplier(PlayerLiving playerLiving)
		{
			try
			{
				PlayerStat moveSpeed = playerLiving.MoveSpeed;
				if (moveSpeed == null)
				{
					return;
				}
				float num = 0f;
				try
				{
					num = moveSpeed.GetValueFloat();
				}
				catch
				{
				}
				float num2 = 0f;
				try
				{
					GameHandler iNSTANCE = GameHandler.INSTANCE;
					float? obj2;
					if (iNSTANCE == null)
					{
						obj2 = null;
					}
					else
					{
						PlayerController playerController = iNSTANCE.playerController;
						obj2 = ((playerController != null) ? new float?(playerController.GetWalkingMovementSpeed()) : null);
					}
					float? num3 = obj2;
					num2 = num3.GetValueOrDefault();
				}
				catch
				{
				}
				moveSpeed.ClearMultiplier("arcade_movement_sprint");
				float num4 = num;
				try
				{
					num4 = moveSpeed.GetValueFloat();
				}
				catch
				{
				}
				try
				{
					GameHandler iNSTANCE2 = GameHandler.INSTANCE;
					if (iNSTANCE2 != null)
					{
						iNSTANCE2.ChangePlayerMoveSpeed(num4);
					}
				}
				catch
				{
				}
				float num5 = 0f;
				try
				{
					GameHandler iNSTANCE3 = GameHandler.INSTANCE;
					float? obj6;
					if (iNSTANCE3 == null)
					{
						obj6 = null;
					}
					else
					{
						PlayerController playerController2 = iNSTANCE3.playerController;
						obj6 = ((playerController2 != null) ? new float?(playerController2.GetWalkingMovementSpeed()) : null);
					}
					float? num3 = obj6;
					num5 = num3.GetValueOrDefault();
				}
				catch
				{
				}
				AmLog.Msg(string.Format("[Sprint] Cleared speed mult key='{0}' stat {1:0.00}->{2:0.00} pc {3:0.00}->{4:0.00}", "arcade_movement_sprint", num, num4, num2, num5));
			}
			catch (Exception arg)
			{
				AmLog.Error($"Failed to clear sprint multiplier: {arg}");
			}
		}

		private static void TryHapticPulse(float amplitude, float duration)
		{
		}

		private static bool IsSmoothMovementSelected()
		{
			try
			{
				float unscaledTime = Time.unscaledTime;
				if (_lastSmoothCheckAt >= 0f && unscaledTime < _lastSmoothCheckAt + SmoothCheckInterval)
				{
					return _lastSmoothSelected;
				}
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.mainMenu == (Object)null || (Object)(object)iNSTANCE.mainMenu.settingsObject == (Object)null)
				{
					_lastSmoothSelected = false;
					_lastSmoothCheckAt = unscaledTime;
					return _lastSmoothSelected;
				}
				Settings settingsObject = iNSTANCE.mainMenu.settingsObject;
				if (settingsObject.IsUsingTeleportMovement() || settingsObject.IsUsingMonkeMovement())
				{
					_lastSmoothSelected = false;
					_lastSmoothCheckAt = unscaledTime;
					return _lastSmoothSelected;
				}
				Dictionary<string, string> settings = settingsObject.settings;
				if (settings != null && settings.ContainsKey("movement_type"))
				{
					_lastSmoothSelected = string.Equals(settings["movement_type"], "smooth", StringComparison.OrdinalIgnoreCase);
				}
				else
				{
					_lastSmoothSelected = true;
				}
				_lastSmoothCheckAt = unscaledTime;
				return _lastSmoothSelected;
			}
			catch
			{
				return _lastSmoothSelected;
			}
		}

		private static void LogMovementModeIfChanged(PlayerLiving playerLiving)
		{
			if (!DebugLogs)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (!(_lastStatusLogAt >= 0f) || !(unscaledTime < _lastStatusLogAt + _statusLogMinInterval))
			{
				string settingsMovementTypeText = GetSettingsMovementTypeText();
				string controllerMovementTypeText = GetControllerMovementTypeText(playerLiving);
				if (!string.Equals(_lastMovementTypeText, settingsMovementTypeText, StringComparison.Ordinal))
				{
					_lastMovementTypeText = settingsMovementTypeText;
					AmLog.Msg("[Sprint] Detected movement setting: " + settingsMovementTypeText);
				}
				if (!string.Equals(_lastControllerMoveTypeText, controllerMovementTypeText, StringComparison.Ordinal))
				{
					_lastControllerMoveTypeText = controllerMovementTypeText;
					AmLog.Msg("[Sprint] PlayerController movement: " + controllerMovementTypeText);
				}
				_lastStatusLogAt = unscaledTime;
			}
		}

		private static string GetSettingsMovementTypeText()
		{
			try
			{
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.mainMenu == (Object)null || (Object)(object)iNSTANCE.mainMenu.settingsObject == (Object)null)
				{
					return "?";
				}
				Dictionary<string, string> settings = iNSTANCE.mainMenu.settingsObject.settings;
				if (settings != null && settings.ContainsKey("movement_type"))
				{
					return settings["movement_type"] ?? "?";
				}
			}
			catch
			{
			}
			return "?";
		}

		private static string GetPlayerObjectName(PlayerLiving playerLiving)
		{
			if (!((Object)(object)playerLiving != (Object)null) || !((Object)(object)((Component)playerLiving).gameObject != (Object)null))
			{
				return "PlayerLiving";
			}
			return ((Object)((Component)playerLiving).gameObject).name;
		}

		private static string GetMovementControllerSettingText()
		{
			try
			{
				Dictionary<string, string> dictionary = (GameHandler.INSTANCE?.mainMenu?.settingsObject)?.settings;
				if (dictionary != null && dictionary.ContainsKey("movement_controller"))
				{
					string text = dictionary["movement_controller"];
					if (!string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
			}
			catch
			{
			}
			return "right";
		}

		private static bool HasUnlimitedSprintLocal()
		{
			try
			{
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.itemInterpreter == (Object)null)
				{
					return false;
				}
				return iNSTANCE.itemInterpreter.AmountPickupFoundByLocalPlayer("am_unlimited_sprint") > 0;
			}
			catch
			{
				return false;
			}
		}

		private static bool HasUpgradedDashLocal()
		{
			try
			{
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.itemInterpreter == (Object)null)
				{
					return false;
				}
				return iNSTANCE.itemInterpreter.AmountPickupFoundByLocalPlayer("am_upgraded_dash") > 0;
			}
			catch
			{
				return false;
			}
		}

		private static void ApplyDominantHandSelection(string controllerText)
		{
			_lastMovementControllerText = controllerText ?? "?";
			bool sprintOnLeft = string.Equals(_lastMovementControllerText, "left", StringComparison.OrdinalIgnoreCase);
			bool dashOnLeft = string.Equals(_lastMovementControllerText, "right", StringComparison.OrdinalIgnoreCase);
			_sprintOnLeft = sprintOnLeft;
			_dashOnLeft = dashOnLeft;
			try
			{
				_clickHeldCount = 0;
				AmLog.Msg("[Sprint] Mapping: sprint=" + (_sprintOnLeft ? "LEFT" : "RIGHT") + ", dash=" + (_dashOnLeft ? "LEFT" : "RIGHT"));
			}
			catch (Exception ex)
			{
				AmLog.Warn("[Sprint] Failed to apply dominant hand selection: " + ex.Message);
			}
		}

		private static bool IsSprintAction(InputAction? action)
		{
			if (action == null)
			{
				return false;
			}
			bool flag = action == _leftClick;
			bool flag2 = action == _rightClick;
			if (!(_sprintOnLeft && flag))
			{
				return !_sprintOnLeft && flag2;
			}
			return true;
		}

		private static bool IsDashAction(InputAction? action)
		{
			if (action == null)
			{
				return false;
			}
			bool flag = action == _leftClick;
			bool flag2 = action == _rightClick;
			if (!(_dashOnLeft && flag))
			{
				return !_dashOnLeft && flag2;
			}
			return true;
		}

		private static void GameHandler_ChangePlayerMoveSpeed_Postfix_Impl(float val)
		{
			try
			{
				float num = 0f;
				try
				{
					GameHandler iNSTANCE = GameHandler.INSTANCE;
					float? obj;
					if (iNSTANCE == null)
					{
						obj = null;
					}
					else
					{
						PlayerController playerController = iNSTANCE.playerController;
						obj = ((playerController != null) ? new float?(playerController.GetWalkingMovementSpeed()) : null);
					}
					float? num2 = obj;
					num = num2.GetValueOrDefault();
				}
				catch
				{
				}
				GameHandler iNSTANCE2 = GameHandler.INSTANCE;
				string arg = ((iNSTANCE2?.mainMenu?.settingsObject?.settings != null && iNSTANCE2.mainMenu.settingsObject.settings.ContainsKey("movement_type")) ? (iNSTANCE2.mainMenu.settingsObject.settings["movement_type"] ?? "?") : "?");
				AmLog.Msg($"[Sprint] GH.ChangePlayerMoveSpeed(val={val:0.00}) -> pc={num:0.00} settings='{arg}'");
			}
			catch
			{
			}
		}

		private static void PlayerLiving_MoveSpeed_ValueChanged_Postfix_Impl(PlayerLiving __instance)
		{
			try
			{
				float num = 0f;
				try
				{
					num = __instance.MoveSpeed.GetValueFloat();
				}
				catch
				{
				}
				float num2 = 0f;
				try
				{
					GameHandler iNSTANCE = GameHandler.INSTANCE;
					float? obj2;
					if (iNSTANCE == null)
					{
						obj2 = null;
					}
					else
					{
						PlayerController playerController = iNSTANCE.playerController;
						obj2 = ((playerController != null) ? new float?(playerController.GetWalkingMovementSpeed()) : null);
					}
					float? num3 = obj2;
					num2 = num3.GetValueOrDefault();
				}
				catch
				{
				}
				AmLog.Msg($"[Sprint] MoveSpeed_ValueChanged -> stat {num:0.00} pc {num2:0.00}");
			}
			catch
			{
			}
		}
	}
	internal static class TrackpadClickLogger
	{
		[HarmonyPatch(typeof(PlayerInputAction))]
		private static class PlayerInputAction__ctor_Patch
		{
			[HarmonyPatch(/*Could not decode attribute arguments.*/)]
			[HarmonyPostfix]
			private static void Postfix(PlayerInputAction __instance)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					AmLog.Msg("[TrackpadClickLogger] PlayerInputAction constructed; wiring maps...");
					RightHandActions rightHand = __instance.RightHand;
					InputActionMap val = ((RightHandActions)(ref rightHand)).Get();
					if (val != null)
					{
						AmLog.Msg("[TrackpadClickLogger] Found RightHand map");
						EnsureClickLogger(val, "{RightHand}", "Right");
						EnsurePrimary2DAxisBinding(val, "{RightHand}");
					}
					else
					{
						AmLog.Warn("[TrackpadClickLogger] RightHand map not found");
					}
					LeftHandActions leftHand = __instance.LeftHand;
					InputActionMap val2 = ((LeftHandActions)(ref leftHand)).Get();
					if (val2 != null)
					{
						AmLog.Msg("[TrackpadClickLogger] Found LeftHand map");
						EnsureClickLogger(val2, "{LeftHand}", "Left");
						EnsurePrimary2DAxisBinding(val2, "{LeftHand}");
					}
					else
					{
						AmLog.Warn("[TrackpadClickLogger] LeftHand map not found");
					}
				}
				catch (Exception arg)
				{
					AmLog.Error($"TrackpadClickLogger Postfix error: {arg}");
				}
				AmInputLog.DumpDevicesOnce();
			}

			private static void EnsureClickLogger(InputActionMap map, string handTag, string label)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				bool enabled = map.enabled;
				if (enabled)
				{
					map.Disable();
				}
				try
				{
					InputAction val = ((IEnumerable<InputAction>)(object)map.actions).FirstOrDefault((Func<InputAction, bool>)((InputAction a) => a.name == "Primary2DAxisClickLogger")) ?? InputActionSetupExtensions.AddAction(map, "Primary2DAxisClickLogger", (InputActionType)1, (string)null, (string)null, (string)null, (string)null, (string)null);
					val.expectedControlType = "Button";
					AddIfMissing(val, "*/" + handTag + "/Primary2DAxisClick");
					AddIfMissing(val, "<XRController>" + handTag + "/Primary2DAxisClick");
					AddIfMissing(val, "*/" + handTag + "/thumbstickClicked");
					AddIfMissing(val, "<XRController>" + handTag + "/thumbstickClicked");
					AddIfMissing(val, "<ValveIndexController>" + handTag + "/thumbstickClicked");
					AddIfMissing(val, "*/" + handTag + "/joystickClicked");
					AddIfMissing(val, "<XRController>" + handTag + "/joystickClicked");
					AddIfMissing(val, "*/" + handTag + "/trackpadClicked");
					AddIfMissing(val, "<XRController>" + handTag + "/trackpadClicked");
					AddIfMissing(val, "<ValveIndexController>" + handTag + "/trackpadClicked");
					AddIfMissing(val, "*/" + handTag + "/touchpadClicked");
					AddIfMissing(val, "<XRController>" + handTag + "/touchpadClicked");
					AmLog.Msg("[TrackpadClickLogger] Wired click logger for " + label + " hand");
					if (_wiredClickActions.Add(val))
					{
						_actionLabels[val] = label;
						val.started += OnPrimary2DAxisClickStarted;
					}
				}
				finally
				{
					if (enabled)
					{
						map.Enable();
					}
				}
				static void AddIfMissing(InputAction a, string path)
				{
					//IL_000e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0035: Unknown result type (might be due to invalid IL or missing references)
					string path2 = path;
					if (!((IEnumerable<InputBinding>)(object)a.bindings).Any((InputBinding b) => string.Equals(((InputBinding)(ref b)).path, path2, StringComparison.OrdinalIgnoreCase)))
					{
						InputActionSetupExtensions.AddBinding(a, path2, (string)null, (string)null, (string)null);
						AmLog.Msg("[TrackpadClickLogger] Added binding: " + path2);
					}
				}
			}

			private static void EnsurePrimary2DAxisBinding(InputActionMap map, string handTag)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				bool enabled = map.enabled;
				if (enabled)
				{
					map.Disable();
				}
				try
				{
					InputAction val = ((IEnumerable<InputAction>)(object)map.actions).FirstOrDefault((Func<InputAction, bool>)((InputAction a) => a.name == "JoystickAxis"));
					if (val != null)
					{
						AddIfMissing(val, "*/" + handTag + "/Primary2DAxis");
						AddIfMissing(val, "<XRController>" + handTag + "/Primary2DAxis");
						AddIfMissing(val, "*/" + handTag + "/thumbstick");
						AddIfMissing(val, "<XRController>" + handTag + "/thumbstick");
						AddIfMissing(val, "<ValveIndexController>" + handTag + "/thumbstick");
						AddIfMissing(val, "*/" + handTag + "/joystick");
						AddIfMissing(val, "<XRController>" + handTag + "/joystick");
						AddIfMissing(val, "*/" + handTag + "/trackpad");
						AddIfMissing(val, "<XRController>" + handTag + "/trackpad");
						AddIfMissing(val, "<ValveIndexController>" + handTag + "/trackpad");
						AddIfMissing(val, "*/" + handTag + "/touchpad");
						AddIfMissing(val, "<XRController>" + handTag + "/touchpad");
					}
				}
				finally
				{
					if (enabled)
					{
						map.Enable();
					}
				}
				static void AddIfMissing(InputAction a, string path)
				{
					//IL_000e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0035: Unknown result type (might be due to invalid IL or missing references)
					string path2 = path;
					if (!((IEnumerable<InputBinding>)(object)a.bindings).Any((InputBinding b) => string.Equals(((InputBinding)(ref b)).path, path2, StringComparison.OrdinalIgnoreCase)))
					{
						InputActionSetupExtensions.AddBinding(a, path2, (string)null, (string)null, (string)null);
						AmLog.Msg("[TrackpadClickLogger] Added vector2 binding: " + path2);
					}
				}
			}

			private static void OnPrimary2DAxisClickStarted(CallbackContext ctx)
			{
				try
				{
					if (((CallbackContext)(ref ctx)).action == null)
					{
						AmInputLog.Primary2DAxisClick("?");
					}
					else
					{
						AmInputLog.Primary2DAxisClick(_actionLabels.TryGetValue(((CallbackContext)(ref ctx)).action, out string value) ? value : "?");
					}
				}
				catch (Exception arg)
				{
					AmLog.Error($"Primary2DAxis click logger error: {arg}");
				}
			}
		}

		private static Harmony? _harmony;

		private static readonly HashSet<InputAction> _wiredClickActions = new HashSet<InputAction>();

		private static readonly Dictionary<InputAction, string> _actionLabels = new Dictionary<InputAction, string>();

		public static bool IsApplied { get; private set; }

		public static void Apply()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			try
			{
				if (!IsApplied)
				{
					_harmony = new Harmony("ArcadeMovement.TrackpadClickLogger");
					_harmony.CreateClassProcessor(typeof(TrackpadClickLogger)).Patch();
					IsApplied = true;
					AmLog.Msg("[TrackpadClickLogger] Applied (gated by mod enable)");
				}
			}
			catch (Exception arg)
			{
				AmLog.Error($"Failed to apply TrackpadClickLogger: {arg}");
			}
		}

		public static void Remove()
		{
			try
			{
				if (!IsApplied)
				{
					return;
				}
				try
				{
					Harmony? harmony = _harmony;
					if (harmony != null)
					{
						harmony.UnpatchAll((string)null);
					}
				}
				catch
				{
				}
				finally
				{
					_harmony = null;
					IsApplied = false;
				}
				AmLog.Msg("[TrackpadClickLogger] Removed");
			}
			catch (Exception ex)
			{
				AmLog.Warn("[TrackpadClickLogger] Remove failed: " + ex.Message);
			}
		}
	}
}
namespace ArcadeMovement.Logging
{
	internal static class AmInputLog
	{
		private static bool _dumpedDevices;

		public static void DumpDevicesOnce()
		{
			//IL_0020: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			if (!AmLog.Enabled || _dumpedDevices)
			{
				return;
			}
			_dumpedDevices = true;
			try
			{
				AmLog.Msg("[TrackpadClickLogger] Listing XR input devices and key controls...");
				foreach (InputDevice item in ((IEnumerable<InputDevice>)(object)InputSystem.devices).ToList())
				{
					if ((((InputControl)item).layout ?? string.Empty).IndexOf("XR", StringComparison.OrdinalIgnoreCase) < 0 && !((IEnumerable<InternedString>)(object)((InputControl)item).usages).Any((InternedString u) => string.Equals(((object)(InternedString)(ref u)).ToString(), "LeftHand", StringComparison.OrdinalIgnoreCase) || string.Equals(((object)(InternedString)(ref u)).ToString(), "RightHand", StringComparison.OrdinalIgnoreCase)))
					{
						continue;
					}
					AmLog.Msg("- Device: '" + ((InputControl)item).displayName + "' layout='" + ((InputControl)item).layout + "' usages=[" + string.Join(", ", ((IEnumerable<InternedString>)(object)((InputControl)item).usages).Select((InternedString u) => ((object)(InternedString)(ref u)).ToString())) + "]");
					string[] array = new string[12]
					{
						"primary2DAxis", "primary2DAxisClick", "thumbstick", "thumbstickClicked", "joystick", "joystickClicked", "touchpad", "touchpadClicked", "trackpad", "trackpadClicked",
						"secondary2DAxis", "secondary2DAxisClick"
					};
					foreach (string text in array)
					{
						InputControl val = ((InputControl)item).TryGetChildControl(text);
						if (val != null)
						{
							AmLog.Msg("    control: " + text + " type=" + val.valueType.Name);
						}
					}
				}
			}
			catch (Exception arg)
			{
				AmLog.Error($"[TrackpadClickLogger] DumpDevices error: {arg}");
			}
		}

		public static void Primary2DAxisClick(string label)
		{
			AmLog.Msg("[" + label + "] Primary2DAxis pressed down");
		}
	}
	internal static class AmLog
	{
		public static bool Enabled { get; private set; }

		public static void SetEnabled(bool enabled)
		{
			Enabled = enabled;
		}

		public static void Msg(string message)
		{
			if (Enabled)
			{
				MelonLogger.Msg("ArcadeMovement: " + message);
			}
		}

		public static void Warn(string message)
		{
			if (Enabled)
			{
				MelonLogger.Warning("ArcadeMovement: " + message);
			}
		}

		public static void Error(string message)
		{
			MelonLogger.Error("ArcadeMovement: " + message);
		}
	}
}
namespace ArcadeMovement.Integration
{
	internal static class ADVRIntegration
	{
		internal static class IntegrationPatches
		{
			[HarmonyPatch(typeof(ModLoader), "Initialize")]
			internal static class ModLoader_Initialize_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix(ModLoader __instance)
				{
					AppendPseudoMod(__instance);
				}
			}

			[HarmonyPatch(typeof(SettingsMod), "OnApplyClick")]
			internal static class SettingsMod_OnApplyClick_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix()
				{
					EvaluateAndApply();
				}
			}

			[HarmonyPatch(typeof(GameHandler), "Awake")]
			internal static class GameHandler_Awake_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix()
				{
					RelicInjector.EnsureRelicRepresentations();
					EvaluateAndApply();
				}
			}
		}

		private const string OurModId = "ArcadeMovement";

		public static void EvaluateAndApply()
		{
			try
			{
				if (GetManagerEnabledFlag("ArcadeMovement"))
				{
					if (!SprintPatch.IsApplied)
					{
						SprintPatch.Apply();
					}
					if (!TrackpadClickLogger.IsApplied)
					{
						TrackpadClickLogger.Apply();
					}
				}
				else
				{
					if (SprintPatch.IsApplied)
					{
						SprintPatch.Remove();
					}
					if (TrackpadClickLogger.IsApplied)
					{
						TrackpadClickLogger.Remove();
					}
				}
			}
			catch (Exception ex)
			{
				AmLog.Warn("[ADVRIntegration] Enablement evaluation failed: " + ex.Message);
			}
		}

		public static void HookIntoModLoader()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			try
			{
				Harmony val = new Harmony("ArcadeMovement.ADVRIntegration");
				val.CreateClassProcessor(typeof(IntegrationPatches.ModLoader_Initialize_PostfixPatch)).Patch();
				val.CreateClassProcessor(typeof(IntegrationPatches.SettingsMod_OnApplyClick_PostfixPatch)).Patch();
				val.CreateClassProcessor(typeof(IntegrationPatches.GameHandler_Awake_PostfixPatch)).Patch();
				val.CreateClassProcessor(typeof(RelicInjector.HarmonyHooks.PlayerController_OnGameHandlerInitialized_PostfixPatch)).Patch();
			}
			catch (Exception ex)
			{
				AmLog.Warn("[ADVRIntegration] Failed to hook mod loader: " + ex.Message);
			}
		}

		internal static bool GetManagerEnabledFlag(string modId)
		{
			try
			{
				if ((Object)(object)GameHandler.INSTANCE == (Object)null)
				{
					return false;
				}
				return ES3.Load<bool>("mod_enabled_" + modId, false, GameHandler.INSTANCE.e3Settings);
			}
			catch
			{
				return false;
			}
		}

		private static string GetGameVersionOrFallback()
		{
			try
			{
				return GameHandler.GetGameVersionString();
			}
			catch
			{
				return "unknown";
			}
		}

		private static void AppendPseudoMod(ModLoader __instance)
		{
			//IL_0047: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			try
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					Mod[] array = __instance.loadedMods ?? Array.Empty<Mod>();
					if (!array.Any((Mod m) => string.Equals(m.modId, "ArcadeMovement", StringComparison.OrdinalIgnoreCase)))
					{
						Mod val = new Mod
						{
							modId = "ArcadeMovement",
							modName = "Arcade Movement",
							modDesc = "Sprint + input helpers (MelonLoader)",
							modVersion = GetGameVersionOrFallback()
						};
						Mod[] array2 = (Mod[])(object)new Mod[array.Length + 1];
						Array.Copy(array, array2, array.Length);
						array2[array.Length] = val;
						__instance.loadedMods = array2;
					}
				}
			}
			catch (Exception ex)
			{
				AmLog.Warn("[ADVRIntegration] Failed to append mod to list: " + ex.Message);
			}
		}
	}
	internal static class AssetBundleLoader
	{
		private static AssetBundle? _bundle;

		private static Sprite? _unlimitedSprintSprite;

		private static Sprite? _upgradedDashSprite;

		private const string BundleFileName = "am_assets.bundle";

		private const string UnlimitedSprintSpritePath = "Assets/Images/Unlimited_Sprint.png";

		private const string UpgradedDashSpritePath = "Assets/Images/Upgraded_Dash.png";

		private static string GetModDirectory()
		{
			try
			{
				string location = typeof(ModMain).Assembly.Location;
				if (!string.IsNullOrEmpty(location))
				{
					string text = Path.GetDirectoryName(location) ?? Directory.GetCurrentDirectory();
					AmLog.Msg("[Assets] Mod directory: " + text);
					return text;
				}
			}
			catch
			{
			}
			return Directory.GetCurrentDirectory();
		}

		private static string? FindBundlePath()
		{
			try
			{
				string text = Path.Combine(GetModDirectory(), "Assets");
				if (!Directory.Exists(text))
				{
					AmLog.Warn("[Assets] Assets folder not found: " + text);
					return null;
				}
				string text2 = Path.Combine(text, "am_assets.bundle");
				if (File.Exists(text2))
				{
					AmLog.Msg("[Assets] Found bundle on disk: " + text2);
					return text2;
				}
				AmLog.Warn("[Assets] Bundle not found on disk: " + text2);
				return null;
			}
			catch
			{
				return null;
			}
		}

		private static bool TryExtractEmbeddedBundle(out string? writtenPath)
		{
			writtenPath = null;
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string n) => n.EndsWith("am_assets.bundle", StringComparison.OrdinalIgnoreCase));
				if (string.IsNullOrEmpty(text))
				{
					AmLog.Warn("[Assets] Embedded bundle not found in resources.");
					return false;
				}
				string text2 = Path.Combine(GetModDirectory(), "Assets");
				Directory.CreateDirectory(text2);
				string text3 = Path.Combine(text2, "am_assets.bundle");
				using (Stream stream = executingAssembly.GetManifestResourceStream(text))
				{
					if (stream == null)
					{
						AmLog.Warn("[Assets] Resource stream null.");
						return false;
					}
					using FileStream destination = File.Create(text3);
					stream.CopyTo(destination);
				}
				AmLog.Msg("[Assets] Extracted embedded bundle to: " + text3);
				writtenPath = text3;
				return true;
			}
			catch (Exception ex)
			{
				AmLog.Warn("[Assets] Failed to extract embedded bundle: " + ex.Message);
				return false;
			}
		}

		private static bool EnsureBundleLoaded()
		{
			if ((Object)(object)_bundle != (Object)null)
			{
				return true;
			}
			string writtenPath = FindBundlePath();
			if (string.IsNullOrEmpty(writtenPath) && !TryExtractEmbeddedBundle(out writtenPath))
			{
				return false;
			}
			try
			{
				_bundle = AssetBundle.LoadFromFile(writtenPath);
				AmLog.Msg(((Object)(object)_bundle != (Object)null) ? "[Assets] AssetBundle loaded." : "[Assets] AssetBundle load failed.");
			}
			catch
			{
				_bundle = null;
			}
			return (Object)(object)_bundle != (Object)null;
		}

		public static Sprite? GetUnlimitedSprintSprite()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_unlimitedSprintSprite != (Object)null)
			{
				return _unlimitedSprintSprite;
			}
			if (!EnsureBundleLoaded())
			{
				return null;
			}
			try
			{
				Texture2D val = _bundle.LoadAsset<Texture2D>("Assets/Images/Unlimited_Sprint.png");
				if ((Object)(object)val == (Object)null)
				{
					AmLog.Warn("[Assets] Unlimited_Sprint texture missing in bundle.");
					return null;
				}
				((Texture)val).filterMode = (FilterMode)0;
				_unlimitedSprintSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
				AmLog.Msg($"[Assets] Created Unlimited_Sprint sprite from texture ({((Texture)val).width}x{((Texture)val).height}).");
				return _unlimitedSprintSprite;
			}
			catch
			{
				return null;
			}
		}

		public static Sprite? GetUpgradedDashSprite()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_upgradedDashSprite != (Object)null)
			{
				return _upgradedDashSprite;
			}
			if (!EnsureBundleLoaded())
			{
				return null;
			}
			try
			{
				Texture2D val = _bundle.LoadAsset<Texture2D>("Assets/Images/Upgraded_Dash.png");
				if ((Object)(object)val == (Object)null)
				{
					AmLog.Warn("[Assets] Upgraded_Dash texture missing in bundle.");
					return null;
				}
				((Texture)val).filterMode = (FilterMode)0;
				_upgradedDashSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
				AmLog.Msg($"[Assets] Created Upgraded_Dash sprite from texture ({((Texture)val).width}x{((Texture)val).height}).");
				return _upgradedDashSprite;
			}
			catch
			{
				return null;
			}
		}

		public static AudioClip? GetWooshClip()
		{
			if (!EnsureBundleLoaded())
			{
				return null;
			}
			try
			{
				AudioClip obj = _bundle.LoadAsset<AudioClip>("Assets/Audio/woosh.wav");
				AmLog.Msg(((Object)(object)obj != (Object)null) ? "[Assets] Loaded woosh.wav." : "[Assets] woosh.wav missing.");
				return obj;
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class RelicInjector
	{
		internal static class HarmonyHooks
		{
			[HarmonyPatch(typeof(PlayerController), "OnGameHandlerInitialized")]
			internal static class PlayerController_OnGameHandlerInitialized_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix(PlayerController __instance)
				{
					try
					{
						if ((Object)(object)__instance != (Object)null && ((NetworkBehaviour)__instance).HasStateAuthority)
						{
							EnsureRelicRepresentations();
							if (ADVRIntegration.GetManagerEnabledFlag("ArcadeMovement"))
							{
								EnsureUnlimitedSprintRelicForLocal();
								EnsureUpgradedDashRelicForLocal();
							}
							else
							{
								RemoveUnlimitedSprintRelicForLocal();
								RemoveUpgradedDashRelicForLocal();
							}
						}
					}
					catch
					{
					}
				}
			}

			[HarmonyPatch(typeof(PlayerController), "RpcMpQuickAction")]
			internal static class PlayerController_RpcMpQuickAction_PostfixPatch
			{
				[HarmonyPostfix]
				private static void Postfix(PlayerController __instance, byte pAction, NetworkObject pNetObj, PlayerRef pSource)
				{
					//IL_001e: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						if (pAction == 240)
						{
							AudioClip wooshClip = AssetBundleLoader.GetWooshClip();
							if ((Object)(object)wooshClip != (Object)null)
							{
								AudioSource.PlayClipAtPoint(wooshClip, ((Component)__instance).transform.position, 1f);
							}
						}
					}
					catch
					{
					}
				}
			}

			private const byte QuickActionDashWoosh = 240;
		}

		private const string RelicId = "am_unlimited_sprint";

		private const string RelicName = "Unlimited Sprint";

		private const string RelicDesc = "Hold stick/trackpad click to sprint indefinitely.";

		private const string RelicLuaPath = "gamedata/items/am_unlimited_sprint/am_unlimited_sprint.lua";

		private const string RelicPngPath = "gamedata/items/am_unlimited_sprint/am_unlimited_sprint.png";

		public static void EnsureUnlimitedSprintRelicForLocal()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			try
			{
				if (!ADVRIntegration.GetManagerEnabledFlag("ArcadeMovement"))
				{
					return;
				}
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.itemInterpreter == (Object)null || iNSTANCE.itemInterpreter.AmountPickupFoundByLocalPlayer("am_unlimited_sprint") > 0 || iNSTANCE.itemInterpreter.GetPickupById("am_unlimited_sprint") != null)
				{
					return;
				}
				PickupDiskRepresentation val = new PickupDiskRepresentation("function ADVR.onLoad()\n    pickup.name = \"Unlimited Sprint\"\n    pickup.desc = \"Hold stick/trackpad click to sprint indefinitely.\"\n    pickup.maxAmount = 1\n    pickup.amountUses = -1\n    pickup.price = 0\n    pickup.tier = 3\n    pickup.supportedInMultiplayer = true\n    pickup.probability = 0\n    pickup.spawnsIn = {}\nend\n", "gamedata/items/am_unlimited_sprint/am_unlimited_sprint.lua", "am_unlimited_sprint", (Mod)null);
				try
				{
					val.spawnsIn = Array.Empty<string>();
				}
				catch
				{
				}
				try
				{
					val.probability = 0f;
				}
				catch
				{
				}
				try
				{
					val.sprite = AssetBundleLoader.GetUnlimitedSprintSprite();
				}
				catch
				{
				}
				try
				{
					List<PickupDiskRepresentation> list = (iNSTANCE.itemInterpreter.pickupsOnDisk ?? Array.Empty<PickupDiskRepresentation>()).ToList();
					list.Add(val);
					iNSTANCE.itemInterpreter.pickupsOnDisk = list.ToArray();
				}
				catch
				{
				}
			}
			catch
			{
			}
		}

		public static void EnsureUpgradedDashRelicForLocal()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			try
			{
				if (!ADVRIntegration.GetManagerEnabledFlag("ArcadeMovement"))
				{
					return;
				}
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.itemInterpreter == (Object)null || iNSTANCE.itemInterpreter.GetPickupById("am_upgraded_dash") != null)
				{
					return;
				}
				PickupDiskRepresentation val = new PickupDiskRepresentation("function ADVR.onLoad()\n    pickup.name = \"Upgraded Dash\"\n    pickup.desc = \"+1 dash charge and faster recharge.\"\n    pickup.maxAmount = 1\n    pickup.amountUses = -1\n    pickup.price = 0\n    pickup.tier = 3\n    pickup.supportedInMultiplayer = true\n    pickup.probability = 0\n    pickup.spawnsIn = {}\nend\n", "gamedata/items/am_upgraded_dash/am_upgraded_dash.lua", "am_upgraded_dash", (Mod)null);
				try
				{
					val.spawnsIn = Array.Empty<string>();
				}
				catch
				{
				}
				try
				{
					val.probability = 0f;
				}
				catch
				{
				}
				try
				{
					val.sprite = AssetBundleLoader.GetUpgradedDashSprite();
				}
				catch
				{
				}
				try
				{
					List<PickupDiskRepresentation> list = (iNSTANCE.itemInterpreter.pickupsOnDisk ?? Array.Empty<PickupDiskRepresentation>()).ToList();
					list.Add(val);
					iNSTANCE.itemInterpreter.pickupsOnDisk = list.ToArray();
				}
				catch
				{
				}
			}
			catch
			{
			}
		}

		public static void RemoveUpgradedDashRelicForLocal()
		{
			try
			{
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.itemInterpreter == (Object)null)
				{
					return;
				}
				PickupDiskRepresentation pickupById = iNSTANCE.itemInterpreter.GetPickupById("am_upgraded_dash");
				if (pickupById == null || iNSTANCE.itemInterpreter.AmountPickupFoundByLocalPlayer("am_upgraded_dash") <= 0)
				{
					return;
				}
				try
				{
					pickupById.UnregisterItem();
				}
				catch
				{
				}
			}
			catch
			{
			}
		}

		public static void EnsureRelicRepresentations()
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			try
			{
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.itemInterpreter == (Object)null)
				{
					return;
				}
				if (iNSTANCE.itemInterpreter.GetPickupById("am_unlimited_sprint") == null)
				{
					PickupDiskRepresentation val = new PickupDiskRepresentation("function ADVR.onLoad()\n    pickup.name = \"Unlimited Sprint\"\n    pickup.desc = \"Hold stick/trackpad click to sprint indefinitely.\"\n    pickup.maxAmount = 1\n    pickup.amountUses = -1\n    pickup.price = 0\n    pickup.tier = 3\n    pickup.supportedInMultiplayer = true\n    pickup.probability = 0\n    pickup.spawnsIn = {}\nend\n", "gamedata/items/am_unlimited_sprint/am_unlimited_sprint.lua", "am_unlimited_sprint", (Mod)null);
					try
					{
						val.spawnsIn = Array.Empty<string>();
					}
					catch
					{
					}
					try
					{
						val.probability = 0f;
					}
					catch
					{
					}
					try
					{
						val.sprite = AssetBundleLoader.GetUnlimitedSprintSprite();
					}
					catch
					{
					}
					try
					{
						List<PickupDiskRepresentation> list = (iNSTANCE.itemInterpreter.pickupsOnDisk ?? Array.Empty<PickupDiskRepresentation>()).ToList();
						list.Add(val);
						iNSTANCE.itemInterpreter.pickupsOnDisk = list.ToArray();
					}
					catch
					{
					}
				}
				try
				{
					ES3.Save<bool>("found_am_unlimited_sprint", true, iNSTANCE.e3Settings);
				}
				catch
				{
				}
				if (iNSTANCE.itemInterpreter.GetPickupById("am_upgraded_dash") == null)
				{
					PickupDiskRepresentation val2 = new PickupDiskRepresentation("function ADVR.onLoad()\n    pickup.name = \"Upgraded Dash\"\n    pickup.desc = \"+1 dash charge and faster recharge.\"\n    pickup.maxAmount = 1\n    pickup.amountUses = -1\n    pickup.price = 0\n    pickup.tier = 3\n    pickup.supportedInMultiplayer = true\n    pickup.probability = 0\n    pickup.spawnsIn = {}\nend\n", "gamedata/items/am_upgraded_dash/am_upgraded_dash.lua", "am_upgraded_dash", (Mod)null);
					try
					{
						val2.spawnsIn = Array.Empty<string>();
					}
					catch
					{
					}
					try
					{
						val2.probability = 0f;
					}
					catch
					{
					}
					try
					{
						val2.sprite = AssetBundleLoader.GetUpgradedDashSprite();
					}
					catch
					{
					}
					try
					{
						List<PickupDiskRepresentation> list2 = (iNSTANCE.itemInterpreter.pickupsOnDisk ?? Array.Empty<PickupDiskRepresentation>()).ToList();
						list2.Add(val2);
						iNSTANCE.itemInterpreter.pickupsOnDisk = list2.ToArray();
					}
					catch
					{
					}
				}
				try
				{
					ES3.Save<bool>("found_am_upgraded_dash", true, iNSTANCE.e3Settings);
				}
				catch
				{
				}
			}
			catch
			{
			}
		}

		public static void RemoveUnlimitedSprintRelicForLocal()
		{
			try
			{
				GameHandler iNSTANCE = GameHandler.INSTANCE;
				if ((Object)(object)iNSTANCE == (Object)null || (Object)(object)iNSTANCE.itemInterpreter == (Object)null)
				{
					return;
				}
				PickupDiskRepresentation pickupById = iNSTANCE.itemInterpreter.GetPickupById("am_unlimited_sprint");
				if (pickupById == null || iNSTANCE.itemInterpreter.AmountPickupFoundByLocalPlayer("am_unlimited_sprint") <= 0)
				{
					return;
				}
				try
				{
					pickupById.UnregisterItem();
				}
				catch
				{
				}
			}
			catch
			{
			}
		}
	}
}
namespace NoisyItems.Audio
{
	internal struct WavData
	{
		public int Channels;

		public int SampleRate;

		public int Frames;

		public float[] Samples;
	}
	internal static class WavLoader
	{
		public static bool TryParse(byte[] data, out WavData wav)
		{
			wav = default(WavData);
			try
			{
				using MemoryStream memoryStream = new MemoryStream(data, writable: false);
				using BinaryReader binaryReader = new BinaryReader(memoryStream);
				if (ReadFourCC(binaryReader) != "RIFF")
				{
					return false;
				}
				binaryReader.ReadInt32();
				if (ReadFourCC(binaryReader) != "WAVE")
				{
					return false;
				}
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				ushort num4 = 0;
				byte[] array = null;
				while (memoryStream.Position + 8 <= memoryStream.Length)
				{
					string text = ReadFourCC(binaryReader);
					int num5 = binaryReader.ReadInt32();
					long position = memoryStream.Position + num5;
					if (text == "fmt ")
					{
						num4 = binaryReader.ReadUInt16();
						num = binaryReader.ReadInt16();
						num2 = binaryReader.ReadInt32();
						binaryReader.ReadInt32();
						binaryReader.ReadInt16();
						num3 = binaryReader.ReadInt16();
						if (num5 > 16)
						{
							int num6 = num5 - 16;
							if (num6 >= 2)
							{
								ushort num7 = binaryReader.ReadUInt16();
								num6 -= 2;
								if (num4 == 65534 && num7 >= 22 && num6 >= 22)
								{
									binaryReader.ReadUInt16();
									binaryReader.ReadUInt32();
									byte[] b = binaryReader.ReadBytes(16);
									num6 -= 22;
									Guid guid = new Guid(b);
									Guid guid2 = new Guid("00000001-0000-0010-8000-00AA00389B71");
									Guid guid3 = new Guid("00000003-0000-0010-8000-00AA00389B71");
									if (guid == guid2)
									{
										num4 = 1;
									}
									else if (guid == guid3)
									{
										num4 = 3;
									}
								}
								if (num6 > 0)
								{
									memoryStream.Position += num6;
								}
							}
							else
							{
								memoryStream.Position = position;
							}
						}
					}
					else if (text == "data")
					{
						array = binaryReader.ReadBytes(num5);
					}
					else
					{
						memoryStream.Position = position;
					}
					if ((memoryStream.Position & 1) == 1)
					{
						memoryStream.Position++;
					}
				}
				if (array == null || num <= 0 || num2 <= 0)
				{
					return false;
				}
				int num9;
				float[] array2;
				switch (num4)
				{
				case 1:
					switch (num3)
					{
					case 8:
					{
						num9 = array.Length / num;
						if (num9 <= 0)
						{
							return false;
						}
						array2 = new float[num9 * num];
						for (int k = 0; k < array2.Length; k++)
						{
							array2[k] = (float)(array[k] - 128) / 128f;
						}
						break;
					}
					case 16:
					{
						num9 = array.Length / 2 / num;
						if (num9 <= 0)
						{
							return false;
						}
						array2 = new float[num9 * num];
						int num15 = 0;
						for (int l = 0; l < array2.Length; l++)
						{
							float num16 = (float)(short)(array[num15] | (array[num15 + 1] << 8)) / 32768f;
							if (num16 < -1f)
							{
								num16 = -1f;
							}
							else if (num16 > 1f)
							{
								num16 = 1f;
							}
							array2[l] = num16;
							num15 += 2;
						}
						break;
					}
					case 24:
					{
						int num11 = 3;
						num9 = array.Length / num11 / num;
						if (num9 <= 0)
						{
							return false;
						}
						array2 = new float[num9 * num];
						int num12 = 0;
						for (int j = 0; j < array2.Length; j++)
						{
							int num13 = array[num12] | (array[num12 + 1] << 8) | (array[num12 + 2] << 16);
							if (((uint)num13 & 0x800000u) != 0)
							{
								num13 |= -16777216;
							}
							float num14 = (float)num13 / 8388608f;
							if (num14 < -1f)
							{
								num14 = -1f;
							}
							else if (num14 > 1f)
							{
								num14 = 1f;
							}
							array2[j] = num14;
							num12 += 3;
						}
						break;
					}
					default:
						return false;
					}
					break;
				case 3:
				{
					if (num3 != 32)
					{
						return false;
					}
					int num8 = array.Length / 4;
					num9 = num8 / Math.Max(1, num);
					if (num9 <= 0)
					{
						return false;
					}
					array2 = new float[num8];
					Buffer.BlockCopy(array, 0, array2, 0, array.Length);
					for (int i = 0; i < array2.Length; i++)
					{
						float num10 = array2[i];
						if (num10 < -1f)
						{
							num10 = -1f;
						}
						else if (num10 > 1f)
						{
							num10 = 1f;
						}
						array2[i] = num10;
					}
					break;
				}
				default:
					return false;
				}
				wav = new WavData
				{
					Channels = num,
					SampleRate = num2,
					Frames = num9,
					Samples = array2
				};
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static string ReadFourCC(BinaryReader br)
		{
			byte[] bytes = br.ReadBytes(4);
			return Encoding.ASCII.GetString(bytes);
		}
	}
}