Decompiled source of Skateboard v1.0.0

GK2Skateboard.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LazyBearTechnology;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Audio;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("GK2Skateboard")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GK2Skateboard")]
[assembly: AssemblyTitle("GK2Skateboard")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GK2Skateboard
{
	[BepInPlugin("sean.gk2.skateboard", "Skateboard", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "sean.gk2.skateboard";

		public const string Version = "1.0.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<float> TopSpeedMult;

		internal static ConfigEntry<float> AccelTime;

		internal static ConfigEntry<float> CoastTime;

		internal static ConfigEntry<float> TurnRate;

		internal static ConfigEntry<float> BrakeTime;

		internal static ConfigEntry<bool> DebugLog;

		internal static ConfigEntry<float> Volume;

		internal static ConfigEntry<string> PadButton;

		internal static ConfigEntry<string> OlliePadButton;

		internal static ConfigEntry<KeyboardShortcut> OllieKey;

		internal static ConfigEntry<int> RideHeightPx;

		internal static ConfigEntry<int> OllieHeightPx;

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ToggleKey", new KeyboardShortcut((KeyCode)107, Array.Empty<KeyCode>()), "Hop on / off the skateboard.");
			TopSpeedMult = ((BaseUnityPlugin)this).Config.Bind<float>("Feel", "TopSpeedMultiplier", 1.9f, "Top speed relative to the keeper's measured walking speed.");
			AccelTime = ((BaseUnityPlugin)this).Config.Bind<float>("Feel", "AccelSeconds", 0.45f, "Seconds of pushing to go from standstill to top speed.");
			CoastTime = ((BaseUnityPlugin)this).Config.Bind<float>("Feel", "CoastSeconds", 1.2f, "Seconds to roll from top speed to a stop with no input.");
			TurnRate = ((BaseUnityPlugin)this).Config.Bind<float>("Feel", "TurnDegreesPerSecond", 900f, "How fast the board carves toward the stick direction. Higher = tighter.");
			BrakeTime = ((BaseUnityPlugin)this).Config.Bind<float>("Feel", "BrakeSeconds", 0.3f, "Seconds to stop from top speed when pushing the opposite way.");
			PadButton = ((BaseUnityPlugin)this).Config.Bind<string>("Controls", "PadToggle", "L3", "Gamepad button that toggles the board (XInput names: A B X Y LB RB LT RT L3 R3 Back Start DpadUp/Down/Left/Right; empty = off). L3 is unused by GK2.");
			OlliePadButton = ((BaseUnityPlugin)this).Config.Bind<string>("Controls", "PadOllie", "RT", "Gamepad button for an ollie while riding. RT is unused by GK2; A is Interaction, so avoid it.");
			OllieKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "OllieKey", new KeyboardShortcut((KeyCode)32, Array.Empty<KeyCode>()), "Keyboard ollie while riding.");
			RideHeightPx = ((BaseUnityPlugin)this).Config.Bind<int>("Visual", "RideHeightPixels", 5, "Art pixels the keeper is lifted to stand on the deck.");
			OllieHeightPx = ((BaseUnityPlugin)this).Config.Bind<int>("Visual", "OllieHeightPixels", 14, "Peak height of an ollie, in art pixels.");
			Volume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 0.6f, new ConfigDescription("Board sound volume (on top of the game's SFX volume).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLog", false, "Log speeds and renderer setup.");
			Harmony val = new Harmony("sean.gk2.skateboard");
			val.PatchAll(typeof(BodyPatches));
			val.PatchAll(typeof(ViewPatches));
			GameObject val2 = new GameObject("GK2Skateboard.Runner")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val2);
			val2.AddComponent<SkateRunner>();
			Log.LogInfo((object)string.Format("Skateboard {0} loaded. Toggle: {1}", "1.0.0", ToggleKey.Value));
		}
	}
	internal class SkateRunner : MonoBehaviour
	{
		private static bool PadDown(string name)
		{
			return XPad.Down(XPad.MaskFor(name));
		}

		private static bool KeyDown(KeyboardShortcut k)
		{
			//IL_0002: 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)
			if ((int)((KeyboardShortcut)(ref k)).MainKey != 0)
			{
				return Input.GetKeyDown(((KeyboardShortcut)(ref k)).MainKey);
			}
			return false;
		}

		private void Update()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			XPad.Poll();
			if (KeyDown(Plugin.ToggleKey.Value) || PadDown(Plugin.PadButton.Value))
			{
				Skate.Toggle();
			}
			else if (Skate.Active && (KeyDown(Plugin.OllieKey.Value) || PadDown(Plugin.OlliePadButton.Value)))
			{
				Skate.View?.Ollie();
			}
			Skate.Validate();
		}
	}
	internal static class Skate
	{
		private static readonly Vector3 WorldScale = new Vector3(1f, 0.5999999f, 0.8f);

		public static bool Active;

		public static PlayerPhysicalBody Body;

		private static float savedDamping;

		private static BoardView view;

		public static Vector3 InputScreen;

		public static float LastMoveCallTime = -1f;

		private static float integratedAt = -1f;

		private static Vector3 capturedWorldVel;

		private static bool captured;

		private static Vector3 resultScreen;

		private static float walkSpeed = 3.8f;

		private static bool walkMeasured;

		private static float dismountedAt = -10f;

		private static float walkInputSince = -1f;

		public static BoardView View => view;

		public static Vector3 ScreenVelocity => resultScreen;

		private static PlayerController Controller
		{
			get
			{
				if (!((Object)(object)MainGame.Instance != (Object)null))
				{
					return null;
				}
				return MainGame.PlayerController;
			}
		}

		public static float TopSpeed => walkSpeed * Plugin.TopSpeedMult.Value;

		public static Vector3 ToScreen(Vector3 w)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(w.x, w.y / WorldScale.y, w.z / WorldScale.z);
		}

		public static Vector3 ToWorld(Vector3 s)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Vector3.Scale(s, WorldScale);
		}

		public static void Toggle()
		{
			if (Active)
			{
				Dismount("toggled off");
				return;
			}
			PlayerController controller = Controller;
			if (!((Object)(object)controller == (Object)null) && !((Object)(object)controller.PhysicalBody == (Object)null) && controller.IsControlsEnabled)
			{
				Mount(controller);
			}
		}

		private static void Mount(PlayerController pc)
		{
			//IL_002b: 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)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			Body = pc.PhysicalBody;
			Rigidbody rb = Body.Rb;
			savedDamping = rb.linearDamping;
			rb.linearDamping = 0f;
			resultScreen = ToScreen(Vector3.ProjectOnPlane(rb.linearVelocity, -Body.GravityNormalized));
			integratedAt = -1f;
			LastMoveCallTime = -1f;
			Active = true;
			GameObject val = new GameObject("GK2Skateboard.Board");
			val.transform.SetParent(((Component)Body.PlayerView).transform, false);
			view = val.AddComponent<BoardView>();
			view.Init(Body.PlayerView);
			if (Plugin.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)string.Format("Mounted. damping was {0:F2}, walk ref {1:F2}{2}, top {3:F2}", savedDamping, walkSpeed, walkMeasured ? "" : " (default)", TopSpeed));
			}
		}

		public static void Dismount(string why)
		{
			if (Active)
			{
				Active = false;
				dismountedAt = Time.time;
				if ((Object)(object)Body != (Object)null && (Object)(object)Body.Rb != (Object)null)
				{
					Body.Rb.linearDamping = savedDamping;
				}
				if ((Object)(object)view != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)view).gameObject);
				}
				view = null;
				Body = null;
				if (Plugin.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("Dismounted: " + why));
				}
			}
		}

		public static void Validate()
		{
			if (Active)
			{
				PlayerController controller = Controller;
				if ((Object)(object)Body == (Object)null || (Object)(object)controller == (Object)null || (Object)(object)controller.PhysicalBody != (Object)(object)Body)
				{
					Dismount("player changed");
				}
			}
		}

		public static void Capture(PlayerPhysicalBody body)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (integratedAt != Time.fixedTime)
			{
				capturedWorldVel = body.Rb.linearVelocity;
				captured = true;
			}
		}

		public static void Apply(PlayerPhysicalBody body)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: 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_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody rb = body.Rb;
			if (rb.isKinematic)
			{
				return;
			}
			float fixedDeltaTime = Time.fixedDeltaTime;
			if (!(Time.fixedTime - LastMoveCallTime <= fixedDeltaTime * 1.5f))
			{
				resultScreen = Vector3.zero;
				return;
			}
			Vector3 val = -body.GravityNormalized;
			if (integratedAt != Time.fixedTime && captured)
			{
				integratedAt = Time.fixedTime;
				captured = false;
				Vector3 val2 = ToScreen(Vector3.ProjectOnPlane(capturedWorldVel, val));
				float topSpeed = TopSpeed;
				if (((Vector3)(ref InputScreen)).sqrMagnitude > 0.0001f)
				{
					Vector3 normalized = ((Vector3)(ref InputScreen)).normalized;
					float magnitude = ((Vector3)(ref val2)).magnitude;
					Vector3 val3 = ((magnitude > 0.3f) ? (val2 / magnitude) : normalized);
					if (magnitude > 0.3f && Vector3.Angle(val3, normalized) > 150f)
					{
						magnitude = Mathf.MoveTowards(magnitude, 0f, topSpeed / Mathf.Max(0.05f, Plugin.BrakeTime.Value) * fixedDeltaTime);
					}
					else
					{
						val3 = Vector3.RotateTowards(val3, normalized, Plugin.TurnRate.Value * (MathF.PI / 180f) * fixedDeltaTime, 0f);
						magnitude += topSpeed / Mathf.Max(0.05f, Plugin.AccelTime.Value) * fixedDeltaTime;
					}
					val2 = val3 * magnitude;
				}
				else
				{
					val2 = Vector3.MoveTowards(val2, Vector3.zero, topSpeed / Mathf.Max(0.05f, Plugin.CoastTime.Value) * fixedDeltaTime);
				}
				if (((Vector3)(ref val2)).magnitude > topSpeed)
				{
					val2 = ((Vector3)(ref val2)).normalized * topSpeed;
				}
				resultScreen = val2;
				if (Plugin.DebugLog.Value && Time.frameCount % 30 == 0)
				{
					Plugin.Log.LogInfo((object)$"skate speed {((Vector3)(ref val2)).magnitude:F2}/{topSpeed:F2}");
				}
			}
			Vector3 linearVelocity = rb.linearVelocity;
			Vector3 val4 = linearVelocity - Vector3.ProjectOnPlane(linearVelocity, val);
			rb.linearVelocity = val4 + Vector3.ProjectOnPlane(ToWorld(resultScreen), val);
		}

		public static void ObserveWalk(PlayerPhysicalBody body, bool hasInput)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if (Active || !hasInput)
			{
				walkInputSince = -1f;
				return;
			}
			if (walkInputSince < 0f)
			{
				walkInputSince = Time.time;
			}
			if (Time.time - dismountedAt < 2f || Time.time - walkInputSince < 0.5f)
			{
				return;
			}
			Vector3 val = ToScreen(Vector3.ProjectOnPlane(body.Rb.linearVelocity, -body.GravityNormalized));
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (!(magnitude < 1f) && !(magnitude > 8f))
			{
				if (!walkMeasured)
				{
					walkMeasured = true;
					walkSpeed = magnitude;
				}
				else if (Mathf.Abs(magnitude - walkSpeed) < walkSpeed * 0.4f)
				{
					walkSpeed = Mathf.Lerp(walkSpeed, magnitude, 0.02f);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerPhysicalBody))]
	internal static class BodyPatches
	{
		private static readonly FieldRef<PlayerPhysicalBody, bool> HasPhysUpdated = AccessTools.FieldRefAccess<PlayerPhysicalBody, bool>("hasPhysUpdatedThisFixedFrame");

		private static readonly FieldRef<PlayerPhysicalBody, bool> MovedThisFrame = AccessTools.FieldRefAccess<PlayerPhysicalBody, bool>("movedByDirectionThisFrame");

		private static readonly MethodInfo UpdatePhysicsM = AccessTools.Method(typeof(PlayerPhysicalBody), "UpdatePhysics", (Type[])null, (Type[])null);

		private static readonly MethodInfo HasMovementPossibilityM = AccessTools.Method(typeof(PlayerPhysicalBody), "HasMovementPossibility", (Type[])null, (Type[])null);

		private static readonly MethodInfo GetFacingDirectionM = AccessTools.Method(typeof(PlayerPhysicalBody), "GetFacingDirection", (Type[])null, (Type[])null);

		private static readonly MethodInfo SetAnimStateM = AccessTools.Method(typeof(PlayerPhysicalBody), "SetCurrentAnimationState", (Type[])null, (Type[])null);

		[HarmonyPrefix]
		[HarmonyPatch("MoveByDirection")]
		private static bool MoveByDirectionPrefix(PlayerPhysicalBody __instance, Vector2 direction)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (!Skate.Active || (Object)(object)__instance != (Object)(object)Skate.Body)
			{
				return true;
			}
			if ((Object)(object)__instance.PhysicsConfig == (Object)null || MainGame.IsGamePaused)
			{
				return false;
			}
			Skate.LastMoveCallTime = Time.fixedTime;
			UpdatePhysicsM.Invoke(__instance, null);
			if ((bool)HasMovementPossibilityM.Invoke(__instance, new object[1] { direction }))
			{
				Vector3 gravityNormalized = __instance.GravityNormalized;
				Vector3 val = Physics.gravity;
				Quaternion val2 = Quaternion.FromToRotation(((Vector3)(ref val)).normalized, Vector3.ProjectOnPlane(gravityNormalized, Vector3.right));
				val = Physics.gravity;
				Quaternion val3 = Quaternion.FromToRotation(((Vector3)(ref val)).normalized, Vector3.ProjectOnPlane(gravityNormalized, Vector3.back));
				Quaternion val4 = val2 * val3;
				val = new Vector3(direction.x, 0f, direction.y);
				Skate.InputScreen = val4 * ((Vector3)(ref val)).normalized;
				__instance.PlayerView.UpdateAnimationDirection((Vector2)GetFacingDirectionM.Invoke(__instance, new object[1] { direction }));
			}
			else
			{
				Skate.InputScreen = Vector3.zero;
			}
			SetAnimStateM.Invoke(__instance, new object[1] { (object)(AnimationState)0 });
			MovedThisFrame.Invoke(__instance) = true;
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch("MoveByDirection")]
		private static void MoveByDirectionPostfix(PlayerPhysicalBody __instance, Vector2 direction)
		{
			Skate.ObserveWalk(__instance, ((Vector2)(ref direction)).sqrMagnitude > 0.01f);
		}

		[HarmonyPrefix]
		[HarmonyPatch("UpdatePhysics")]
		private static void UpdatePhysicsPrefix(PlayerPhysicalBody __instance, out bool __state)
		{
			__state = Skate.Active && (Object)(object)__instance == (Object)(object)Skate.Body && (Object)(object)__instance.PhysicsConfig != (Object)null && !HasPhysUpdated.Invoke(__instance);
			if (__state)
			{
				Skate.Capture(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("UpdatePhysics")]
		private static void UpdatePhysicsPostfix(PlayerPhysicalBody __instance, bool __state)
		{
			if (__state)
			{
				Skate.Apply(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerView), "LateUpdate")]
	internal static class ViewPatches
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerView __instance)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			BoardView view = Skate.View;
			if (Skate.Active && (Object)(object)view != (Object)null && (Object)(object)Skate.Body != (Object)null && (Object)(object)Skate.Body.PlayerView == (Object)(object)__instance)
			{
				view.Place(((Component)__instance).transform.position);
			}
		}
	}
	internal class BoardView : MonoBehaviour
	{
		private const int CellW = 26;

		private const int CellH = 22;

		private const float SidePivotPx = 0f;

		private const float FrontPivotPx = 0f;

		private const float PixelsPerFrame = 6f;

		private static Texture2D sheet;

		private static readonly Dictionary<float, Sprite[]> spritesByPpu = new Dictionary<float, Sprite[]>();

		private PlayerView playerView;

		private SpriteRenderer body;

		private SpriteRenderer sr;

		private Sprite[] sprites;

		private float travelled;

		private bool facingSide = true;

		private bool flip;

		private const float OllieDuration = 0.5f;

		private float ollieT = -1f;

		private SkateAudio audio;

		private float bornAt = -1f;

		private bool reported;

		private float ArtPixelWorldY => (((Object)(object)body != (Object)null) ? ((Component)body).transform.lossyScale.y : 1.6666667f) / sprites[0].pixelsPerUnit;

		public void Ollie()
		{
			if (!(ollieT >= 0f))
			{
				ollieT = 0f;
				audio?.OnOllie();
			}
		}

		public void Init(PlayerView pv)
		{
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			playerView = pv;
			sr = ((Component)this).gameObject.AddComponent<SpriteRenderer>();
			try
			{
				audio = ((Component)this).gameObject.AddComponent<SkateAudio>();
				audio.Init();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Skate audio disabled: " + ex.Message));
				audio = null;
			}
			body = FindBodyRenderer(pv);
			float num = (((Object)(object)body != (Object)null && (Object)(object)body.sprite != (Object)null) ? body.sprite.pixelsPerUnit : 100f);
			sprites = GetSprites(num);
			sr.sprite = sprites[0];
			if ((Object)(object)body != (Object)null)
			{
				((Renderer)sr).sharedMaterial = ((Renderer)body).sharedMaterial;
				((Renderer)sr).sortingLayerID = ((Renderer)body).sortingLayerID;
				((Renderer)sr).sortingOrder = ((Renderer)body).sortingOrder - 1;
				((Component)this).gameObject.layer = ((Component)body).gameObject.layer;
				if (Plugin.DebugLog.Value)
				{
					ManualLogSource log = Plugin.Log;
					object[] obj = new object[7]
					{
						((Object)body).name,
						num,
						null,
						null,
						null,
						null,
						null
					};
					Material sharedMaterial = ((Renderer)body).sharedMaterial;
					obj[2] = ((sharedMaterial != null) ? ((Object)sharedMaterial).name : null);
					obj[3] = ((Renderer)body).sortingLayerName;
					obj[4] = ((Renderer)body).sortingOrder;
					Quaternion rotation = ((Component)body).transform.rotation;
					obj[5] = ((Quaternion)(ref rotation)).eulerAngles;
					obj[6] = ((Component)body).transform.lossyScale;
					log.LogInfo((object)string.Format("Board copies '{0}': ppu {1}, mat '{2}', layer {3}/{4}, rot {5}, scale {6}", obj));
				}
			}
			else
			{
				Plugin.Log.LogWarning((object)"No keeper SpriteRenderer found; board uses defaults.");
			}
		}

		private static SpriteRenderer FindBodyRenderer(PlayerView pv)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerAnimation), "spriteRenderers");
			IEnumerable<SpriteRenderer> enumerable = (((Object)(object)pv.PlayerAnimation != (Object)null) ? (fieldInfo?.GetValue(pv.PlayerAnimation) as List<SpriteRenderer>) : null);
			IEnumerable<SpriteRenderer> obj = enumerable ?? ((Component)pv).GetComponentsInChildren<SpriteRenderer>();
			SpriteRenderer result = null;
			float num = 0f;
			foreach (SpriteRenderer item in obj)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item.sprite == (Object)null) && ((Component)item).gameObject.activeInHierarchy)
				{
					Rect rect = item.sprite.rect;
					float width = ((Rect)(ref rect)).width;
					rect = item.sprite.rect;
					float num2 = width * ((Rect)(ref rect)).height;
					if (num2 > num)
					{
						num = num2;
						result = item;
					}
				}
			}
			return result;
		}

		private static void LoadSheet()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			if ((Object)(object)sheet != (Object)null)
			{
				return;
			}
			sheet = new Texture2D(2, 2, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				wrapMode = (TextureWrapMode)1,
				name = "GK2Skateboard"
			};
			using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("GK2Skateboard.skateboard.png"))
			{
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				ImageConversion.LoadImage(sheet, memoryStream.ToArray());
			}
			((Texture)sheet).filterMode = (FilterMode)0;
		}

		private static Sprite[] GetSprites(float ppu)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (spritesByPpu.TryGetValue(ppu, out var value))
			{
				return value;
			}
			LoadSheet();
			Sprite[] array = (Sprite[])(object)new Sprite[4];
			for (int i = 0; i < 4; i++)
			{
				float num = ((i < 2) ? 0f : 0f);
				array[i] = Sprite.Create(sheet, new Rect((float)(i * 26), 0f, 26f, 22f), new Vector2(0.5f, num / 22f), ppu, 0u, (SpriteMeshType)0);
				((Object)array[i]).name = "Skateboard_" + i;
			}
			spritesByPpu[ppu] = array;
			return array;
		}

		public void Place(Vector3 groundPos)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			float artPixelWorldY = ArtPixelWorldY;
			float num = 0f;
			if (ollieT >= 0f)
			{
				ollieT += Time.deltaTime;
				float num2 = ollieT / 0.5f;
				if (num2 >= 1f)
				{
					ollieT = -1f;
					audio?.OnLand();
				}
				else
				{
					num = Mathf.Round(4f * num2 * (1f - num2) * (float)Plugin.OllieHeightPx.Value) * artPixelWorldY;
				}
			}
			((Component)playerView).transform.position = groundPos + Vector3.up * ((float)Plugin.RideHeightPx.Value * artPixelWorldY + num);
			Vector3 val = (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform.forward : Vector3.forward);
			((Component)this).transform.position = groundPos + Vector3.up * num + val * 0.05f;
		}

		private void LateUpdate()
		{
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: 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_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: 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_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Invalid comparison between Unknown and I4
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Invalid comparison between Unknown and I4
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Invalid comparison between Unknown and I4
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Invalid comparison between Unknown and I4
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Invalid comparison between Unknown and I4
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)playerView == (Object)null)
			{
				return;
			}
			if (bornAt < 0f)
			{
				bornAt = Time.time;
			}
			if (!reported && Plugin.DebugLog.Value && Time.time - bornAt > 0.5f)
			{
				reported = true;
				Camera main = Camera.main;
				string text = (((Object)(object)main != (Object)null) ? $"board@{main.WorldToScreenPoint(((Component)this).transform.position)} keeper@{main.WorldToScreenPoint(((Component)playerView).transform.position)}" : "no camera");
				ManualLogSource log = Plugin.Log;
				object[] obj = new object[5]
				{
					((Renderer)sr).isVisible,
					((Renderer)sr).enabled,
					null,
					null,
					null
				};
				Sprite sprite = sr.sprite;
				obj[2] = ((sprite != null) ? ((Object)sprite).name : null);
				obj[3] = ((Renderer)sr).bounds;
				obj[4] = text;
				log.LogInfo((object)string.Format("Board check: visible={0} enabled={1} sprite={2} bounds={3} {4}", obj));
			}
			if ((Object)(object)body != (Object)null)
			{
				((Component)this).transform.rotation = ((Component)body).transform.rotation;
				Vector3 lossyScale = ((Component)this).transform.parent.lossyScale;
				Vector3 lossyScale2 = ((Component)body).transform.lossyScale;
				((Component)this).transform.localScale = new Vector3(Mathf.Abs(lossyScale2.x) / lossyScale.x, lossyScale2.y / lossyScale.y, lossyScale2.z / lossyScale.z);
				((Renderer)sr).sortingOrder = ((Renderer)body).sortingOrder - 1;
			}
			Vector3 screenVelocity = Skate.ScreenVelocity;
			Vector2 animationDirection = playerView.GetAnimationDirection();
			if (((Vector2)(ref animationDirection)).sqrMagnitude > 0.0001f)
			{
				Direction val = DirectionExtensions.ConvertFromSignedAngle(Mathf.Atan2(animationDirection.y, animationDirection.x) * 57.29578f);
				if ((int)val == 3 || (int)val == 1)
				{
					facingSide = true;
					flip = (int)val == 3;
				}
				else if ((int)val == 2 || (int)val == 4)
				{
					facingSide = false;
				}
			}
			travelled += ((Vector3)(ref screenVelocity)).magnitude * Time.deltaTime * 100f;
			int num = (int)(travelled / 6f) & 1;
			sr.sprite = sprites[((!facingSide) ? 2 : 0) + num];
			sr.flipX = facingSide && flip;
		}
	}
	internal class SkateAudio : MonoBehaviour
	{
		private static AudioClip roll;

		private static AudioClip pop;

		private static AudioClip land;

		private static AudioMixerGroup sfxGroup;

		private static bool groupSearched;

		private AudioSource rollSrc;

		private AudioSource shotSrc;

		private bool airborne;

		public void Init()
		{
			LoadClips();
			AudioMixerGroup outputAudioMixerGroup = FindSfxGroup();
			rollSrc = ((Component)this).gameObject.AddComponent<AudioSource>();
			rollSrc.clip = roll;
			rollSrc.loop = true;
			rollSrc.playOnAwake = false;
			rollSrc.spatialBlend = 0f;
			rollSrc.volume = 0f;
			rollSrc.outputAudioMixerGroup = outputAudioMixerGroup;
			rollSrc.Play();
			shotSrc = ((Component)this).gameObject.AddComponent<AudioSource>();
			shotSrc.playOnAwake = false;
			shotSrc.spatialBlend = 0f;
			shotSrc.outputAudioMixerGroup = outputAudioMixerGroup;
		}

		public void OnOllie()
		{
			airborne = true;
			shotSrc.PlayOneShot(pop, Plugin.Volume.Value);
		}

		public void OnLand()
		{
			airborne = false;
			shotSrc.PlayOneShot(land, Plugin.Volume.Value);
		}

		private void Update()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rollSrc == (Object)null))
			{
				bool isGamePaused = MainGame.IsGamePaused;
				if (isGamePaused && rollSrc.isPlaying)
				{
					rollSrc.Pause();
				}
				else if (!isGamePaused && !rollSrc.isPlaying)
				{
					rollSrc.UnPause();
				}
				float num = Mathf.Max(0.01f, Skate.TopSpeed);
				Vector3 screenVelocity = Skate.ScreenVelocity;
				float num2 = Mathf.Clamp01(((Vector3)(ref screenVelocity)).magnitude / num);
				float num3 = (airborne ? 0f : (Plugin.Volume.Value * 0.8f * Mathf.Sqrt(num2)));
				rollSrc.volume = Mathf.MoveTowards(rollSrc.volume, num3, Time.unscaledDeltaTime * 3f);
				rollSrc.pitch = 0.75f + 0.55f * num2;
			}
		}

		private static AudioMixerGroup FindSfxGroup()
		{
			if (groupSearched)
			{
				return sfxGroup;
			}
			groupSearched = true;
			try
			{
				AudioMixer val = default(AudioMixer);
				if (!LazyAudio.TryGetAudioMixer(ref val) || (Object)(object)val == (Object)null)
				{
					return null;
				}
				AudioMixerGroup[] array = val.FindMatchingGroups(string.Empty);
				if (Plugin.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("Mixer groups: " + string.Join(", ", Array.ConvertAll(array, (AudioMixerGroup g) => ((Object)g).name))));
				}
				string[] array2 = new string[3] { "sfx", "sound", "effect" };
				foreach (string value in array2)
				{
					AudioMixerGroup[] array3 = array;
					foreach (AudioMixerGroup val2 in array3)
					{
						if (((Object)val2).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
						{
							return sfxGroup = val2;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Mixer lookup failed: " + ex.Message));
			}
			return null;
		}

		private static void LoadClips()
		{
			if (!((Object)(object)roll != (Object)null))
			{
				roll = LoadWav("roll");
				pop = LoadWav("pop");
				land = LoadWav("land");
			}
		}

		private static AudioClip LoadWav(string name)
		{
			byte[] array;
			using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("GK2Skateboard." + name + ".wav"))
			{
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				array = memoryStream.ToArray();
			}
			int num = 1;
			int num2 = 44100;
			int num3;
			for (int i = 12; i + 8 <= array.Length; i += 8 + num3 + (num3 & 1))
			{
				string text = Encoding.ASCII.GetString(array, i, 4);
				num3 = BitConverter.ToInt32(array, i + 4);
				if (text == "fmt ")
				{
					num = BitConverter.ToInt16(array, i + 10);
					num2 = BitConverter.ToInt32(array, i + 12);
				}
				else if (text == "data")
				{
					int num4 = num3 / 2;
					float[] array2 = new float[num4];
					for (int j = 0; j < num4; j++)
					{
						array2[j] = (float)BitConverter.ToInt16(array, i + 8 + j * 2) / 32768f;
					}
					AudioClip obj = AudioClip.Create("Skateboard_" + name, num4 / num, num, num2, false);
					obj.SetData(array2, 0);
					return obj;
				}
			}
			throw new InvalidDataException("No data chunk in " + name);
		}
	}
	internal static class XPad
	{
		private struct State
		{
			public uint packet;

			public ushort buttons;

			public byte leftTrigger;

			public byte rightTrigger;

			public short lx;

			public short ly;

			public short rx;

			public short ry;
		}

		private static bool use910;

		private static bool unavailable;

		private static int prevMask;

		private static int curMask;

		private const int LT = 65536;

		private const int RT = 131072;

		[DllImport("xinput1_4.dll", EntryPoint = "XInputGetState")]
		private static extern int GetState14(int user, out State state);

		[DllImport("xinput9_1_0.dll", EntryPoint = "XInputGetState")]
		private static extern int GetState910(int user, out State state);

		public static int MaskFor(string name)
		{
			return (name ?? "").Trim().ToUpperInvariant() switch
			{
				"DPADUP" => 1, 
				"DPADDOWN" => 2, 
				"DPADLEFT" => 4, 
				"DPADRIGHT" => 8, 
				"START" => 16, 
				"BACK" => 32, 
				"L3" => 64, 
				"R3" => 128, 
				"LB" => 256, 
				"RB" => 512, 
				"A" => 4096, 
				"B" => 8192, 
				"X" => 16384, 
				"Y" => 32768, 
				"LT" => 65536, 
				"RT" => 131072, 
				_ => 0, 
			};
		}

		public static void Poll()
		{
			prevMask = curMask;
			curMask = 0;
			if (unavailable)
			{
				return;
			}
			for (int i = 0; i < 4; i++)
			{
				int num;
				State state;
				try
				{
					num = (use910 ? GetState910(i, out state) : GetState14(i, out state));
				}
				catch (DllNotFoundException)
				{
					if (!use910)
					{
						use910 = true;
						break;
					}
					unavailable = true;
					Plugin.Log.LogWarning((object)"XInput not available; gamepad skate buttons disabled.");
					break;
				}
				catch (EntryPointNotFoundException)
				{
					unavailable = true;
					break;
				}
				if (num == 0)
				{
					curMask |= state.buttons;
					if (state.leftTrigger > 128)
					{
						curMask |= 65536;
					}
					if (state.rightTrigger > 128)
					{
						curMask |= 131072;
					}
				}
			}
		}

		public static bool Down(int mask)
		{
			if (mask != 0 && (curMask & mask) == mask)
			{
				return (prevMask & mask) != mask;
			}
			return false;
		}
	}
}