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;
}
}
}