Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of SkateboardSkitching v1.0.0
Skitching_IL2CPP.dll
Decompiled a day agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.Skating; using Il2CppScheduleOne.Vehicles; using Il2CppScheduleOne.Vehicles.AI; using MelonLoader; using MelonLoader.Preferences; using Skitching; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(global::Skitching.Skitching), "Skitching", "1.0", "Jumble", null)] [assembly: MelonColor] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Skitching_IL2CPP")] [assembly: AssemblyConfiguration("Debug_IL2CPP")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Skitching_IL2CPP")] [assembly: AssemblyTitle("Skitching_IL2CPP")] [assembly: AssemblyVersion("1.0.0.0")] namespace Skitching; public static class BuildInfo { public const string Name = "Skitching"; public const string Description = "Hold onto the back of cars to gain speed on your skateboard."; public const string Author = "Jumble"; public const string Company = null; public const string Version = "1.0"; public const string DownloadLink = null; } public static class Config { private static MelonPreferences_Category configCategory; private static MelonPreferences_Entry<bool> enabledEntry; private static MelonPreferences_Entry<string> skitchKeyEntry; private static MelonPreferences_Entry<float> scanIntervalSecondsEntry; private static MelonPreferences_Entry<float> attachDistanceEntry; private static MelonPreferences_Entry<float> detachDistanceEntry; private static MelonPreferences_Entry<float> tetherBackOffsetEntry; private static MelonPreferences_Entry<float> tetherUpOffsetEntry; private static MelonPreferences_Entry<float> tetherForceEntry; private static MelonPreferences_Entry<float> velocityMatchLerpEntry; private static MelonPreferences_Entry<float> minVehicleSpeedKmhEntry; private static MelonPreferences_Entry<float> npcBoostMinMultiplierEntry; private static MelonPreferences_Entry<float> npcBoostMaxMultiplierEntry; private static MelonPreferences_Entry<float> npcBoostRampPerSecondEntry; public static bool Enabled => enabledEntry?.Value ?? true; public static string SkitchKey => skitchKeyEntry?.Value ?? "E"; public static float ScanIntervalSeconds => scanIntervalSecondsEntry?.Value ?? 0.25f; public static float AttachDistance => attachDistanceEntry?.Value ?? 3f; public static float DetachDistance => detachDistanceEntry?.Value ?? 7f; public static float TetherBackOffset => tetherBackOffsetEntry?.Value ?? 1.3f; public static float TetherUpOffset => tetherUpOffsetEntry?.Value ?? (-0.15f); public static float TetherForce => tetherForceEntry?.Value ?? 35f; public static float VelocityMatchLerp => velocityMatchLerpEntry?.Value ?? 0.9f; public static float MinVehicleSpeedKmh => minVehicleSpeedKmhEntry?.Value ?? 3f; public static float NpcBoostMinMultiplier => npcBoostMinMultiplierEntry?.Value ?? 3f; public static float NpcBoostMaxMultiplier => npcBoostMaxMultiplierEntry?.Value ?? 4f; public static float NpcBoostRampPerSecond => npcBoostRampPerSecondEntry?.Value ?? 0.35f; public static void Load() { configCategory = MelonPreferences.CreateCategory("Skitching"); enabledEntry = configCategory.CreateEntry<bool>("enabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); skitchKeyEntry = configCategory.CreateEntry<string>("skitchKey", "E", (string)null, (string)null, false, false, (ValueValidator)null, (string)null); scanIntervalSecondsEntry = configCategory.CreateEntry<float>("scanIntervalSeconds", 0.25f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); attachDistanceEntry = configCategory.CreateEntry<float>("attachDistance", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); detachDistanceEntry = configCategory.CreateEntry<float>("detachDistance", 7f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); tetherBackOffsetEntry = configCategory.CreateEntry<float>("tetherBackOffset", 1.3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); tetherUpOffsetEntry = configCategory.CreateEntry<float>("tetherUpOffset", -0.15f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); tetherForceEntry = configCategory.CreateEntry<float>("tetherForce", 35f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); velocityMatchLerpEntry = configCategory.CreateEntry<float>("velocityMatchLerp", 0.9f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); minVehicleSpeedKmhEntry = configCategory.CreateEntry<float>("minVehicleSpeedKmh", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); npcBoostMinMultiplierEntry = configCategory.CreateEntry<float>("npcBoostMinMultiplier", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); npcBoostMaxMultiplierEntry = configCategory.CreateEntry<float>("npcBoostMaxMultiplier", 4f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); npcBoostRampPerSecondEntry = configCategory.CreateEntry<float>("npcBoostRampPerSecond", 0.35f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); } } public class Skitching : MelonMod { [HarmonyPatch(typeof(VehicleAgent), "UpdateSpeed")] private static class VehicleAgent_UpdateSpeed_Patch { private static void Prefix(VehicleAgent __instance) { CurrentUpdatingAgentPtr = (((Object)(object)__instance != (Object)null) ? ((Il2CppObjectBase)__instance).Pointer : IntPtr.Zero); Skitching instance = Instance; if (instance == null) { return; } instance.TempBoostLog("UpdateSpeed prefix fired for ptr=0x" + CurrentUpdatingAgentPtr.ToString("X")); if (instance.TryGetBoostedUnmarkedSpeedForCurrentUpdate(out var boostedUnmarkedSpeed)) { if (boostedUnmarkedSpeed > 25f) { VehicleAgent.UnmarkedSpeed = boostedUnmarkedSpeed; instance.TempBoostLog($"Applied temp UnmarkedSpeed override: 25.00 -> {boostedUnmarkedSpeed:F2}"); } if ((Object)(object)__instance != (Object)null && boostedUnmarkedSpeed > __instance.targetSpeed) { instance.TempBoostLog($"Raising targetSpeed in prefix: {__instance.targetSpeed:F2} -> {boostedUnmarkedSpeed:F2}"); __instance.targetSpeed = boostedUnmarkedSpeed; } } } private static void Postfix(VehicleAgent __instance) { Skitching instance = Instance; if (instance != null && instance.TryGetBoostedUnmarkedSpeedForCurrentUpdate(out var boostedUnmarkedSpeed) && (Object)(object)__instance != (Object)null && boostedUnmarkedSpeed > __instance.targetSpeed) { instance.TempBoostLog($"Raising targetSpeed in postfix: {__instance.targetSpeed:F2} -> {boostedUnmarkedSpeed:F2}"); __instance.targetSpeed = boostedUnmarkedSpeed; } if (VehicleAgent.UnmarkedSpeed != 25f) { VehicleAgent.UnmarkedSpeed = 25f; instance?.TempBoostLog("Restoring UnmarkedSpeed to 25.00"); } CurrentUpdatingAgentPtr = IntPtr.Zero; } } internal static Skitching Instance; internal static IntPtr CurrentUpdatingAgentPtr = IntPtr.Zero; private KeyCode _skitchKey = (KeyCode)101; private LandVehicle _skitchedVehicle; private Rigidbody _skitchedVehicleRb; private float _nextVehicleScanTime; private float _nextBoostDebugLogTime; private float _npcBoostTargetMultiplier = 1f; private float _npcBoostCurrentMultiplier = 1f; private float _npcBoostBaseSpeedKmh; private bool _agentBoostActive; private VehicleAgent _boostedAgent; public override void OnInitializeMelon() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) Instance = this; Config.Load(); ((MelonBase)this).HarmonyInstance.PatchAll(); if (!Enum.TryParse<KeyCode>(Config.SkitchKey, ignoreCase: true, out _skitchKey)) { MelonLogger.Warning("Invalid skitchKey '" + Config.SkitchKey + "'. Falling back to 'E'."); _skitchKey = (KeyCode)101; } } public override void OnUpdate() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (!Config.Enabled) { return; } Player local = Player.Local; if ((Object)(object)local == (Object)null) { StopSkitching(); return; } Skateboard activeSkateboard = local.ActiveSkateboard; if ((Object)(object)activeSkateboard == (Object)null) { StopSkitching(); } else if ((Object)(object)_skitchedVehicle != (Object)null && _skitchedVehicle.LocalPlayerIsInVehicle) { StopSkitching(); } else if (!Input.GetKey(_skitchKey)) { StopSkitching(); } else if ((Object)(object)_skitchedVehicle == (Object)null && Time.time >= _nextVehicleScanTime) { _nextVehicleScanTime = Time.time + Mathf.Max(0.05f, Config.ScanIntervalSeconds); TryStartSkitching(local, activeSkateboard); } } public override void OnFixedUpdate() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) if (!Config.Enabled || (Object)(object)_skitchedVehicle == (Object)null || (Object)(object)_skitchedVehicleRb == (Object)null) { return; } Player local = Player.Local; if ((Object)(object)local == (Object)null) { StopSkitching(); return; } Skateboard activeSkateboard = local.ActiveSkateboard; if ((Object)(object)activeSkateboard == (Object)null) { StopSkitching(); return; } Rigidbody rb = activeSkateboard.Rb; if ((Object)(object)rb == (Object)null) { StopSkitching(); return; } float num = Vector3.Distance(((Component)activeSkateboard).transform.position, ((Component)_skitchedVehicle).transform.position); if (num > Config.DetachDistance) { StopSkitching(); return; } Vector3 skitchTargetPosition = GetSkitchTargetPosition(_skitchedVehicle); Vector3 val = skitchTargetPosition - ((Component)activeSkateboard).transform.position; rb.AddForce(val * Config.TetherForce, (ForceMode)5); Vector3 velocity = _skitchedVehicleRb.velocity; float num2 = Mathf.Clamp01(Config.VelocityMatchLerp); rb.velocity = Vector3.Lerp(rb.velocity, velocity, num2); ApplyNpcDriverBoost(); } private void TryStartSkitching(Player player, Skateboard board) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) Il2CppArrayBase<LandVehicle> val = Object.FindObjectsOfType<LandVehicle>(); if (val == null || val.Length == 0) { return; } LandVehicle val2 = null; Rigidbody skitchedVehicleRb = null; float num = float.MaxValue; Vector3 position = ((Component)board).transform.position; for (int i = 0; i < val.Length; i++) { LandVehicle val3 = val[i]; if ((Object)(object)val3 == (Object)null || val3.isParked || val3.Speed_Kmh < Config.MinVehicleSpeedKmh || val3.LocalPlayerIsInVehicle) { continue; } Rigidbody rb = val3.Rb; if (!((Object)(object)rb == (Object)null)) { float num2 = Vector3.Distance(position, ((Component)val3).transform.position); if (num2 <= Config.AttachDistance && num2 < num) { num = num2; val2 = val3; skitchedVehicleRb = rb; } } } if (!((Object)(object)val2 == (Object)null)) { _skitchedVehicle = val2; _skitchedVehicleRb = skitchedVehicleRb; _npcBoostCurrentMultiplier = 1f; _npcBoostBaseSpeedKmh = 25f; float num3 = Mathf.Max(1f, Config.NpcBoostMinMultiplier); float num4 = Mathf.Max(num3, Config.NpcBoostMaxMultiplier); _npcBoostTargetMultiplier = Random.Range(num3, num4); } } private static Vector3 GetSkitchTargetPosition(LandVehicle vehicle) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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_011d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)vehicle == (Object)null) { return Vector3.zero; } if ((Object)(object)vehicle.boundingBox != (Object)null) { BoxCollider boundingBox = vehicle.boundingBox; Vector3 center = boundingBox.center; Vector3 size = boundingBox.size; float num = Mathf.Abs(size.z * ((Component)boundingBox).transform.lossyScale.z) * 0.5f; float num2 = Mathf.Abs(size.y * ((Component)boundingBox).transform.lossyScale.y) * 0.5f; Vector3 val = ((Component)boundingBox).transform.TransformPoint(center); return val - ((Component)vehicle).transform.forward * (num + Config.TetherBackOffset) - ((Component)vehicle).transform.up * (num2 * 0.6f) + ((Component)vehicle).transform.up * Config.TetherUpOffset; } float num3 = 1.5f; try { Vector3 boundingBoxDimensions = vehicle.BoundingBoxDimensions; if (boundingBoxDimensions.z > 0.1f) { num3 = boundingBoxDimensions.z * 0.5f; } } catch { } return ((Component)vehicle).transform.position - ((Component)vehicle).transform.forward * (num3 + Config.TetherBackOffset) + ((Component)vehicle).transform.up * Config.TetherUpOffset; } private void ApplyNpcDriverBoost() { if ((Object)(object)_skitchedVehicle == (Object)null || (Object)(object)_skitchedVehicleRb == (Object)null || !_skitchedVehicle.IsOccupied || !((Object)(object)_skitchedVehicle.DriverPlayer == (Object)null)) { return; } _npcBoostCurrentMultiplier = Mathf.MoveTowards(_npcBoostCurrentMultiplier, _npcBoostTargetMultiplier, Mathf.Max(0.01f, Config.NpcBoostRampPerSecond) * Time.fixedDeltaTime); VehicleAgent agent = _skitchedVehicle.Agent; if ((Object)(object)agent == (Object)null) { TempBoostLog("ApplyNpcDriverBoost: vehicle has no agent"); return; } if (!_agentBoostActive) { _boostedAgent = agent; _agentBoostActive = true; } TempBoostLog($"Boost active: mult={_npcBoostCurrentMultiplier:F2}, boostedSpeed={_npcBoostBaseSpeedKmh * _npcBoostCurrentMultiplier:F2} km/h, vehicleSpeed={_skitchedVehicle.Speed_Kmh:F1} km/h"); } private void StopSkitching() { bool flag = (Object)(object)_skitchedVehicle != (Object)null || (Object)(object)_skitchedVehicleRb != (Object)null || _agentBoostActive || (Object)(object)_boostedAgent != (Object)null; _skitchedVehicle = null; _skitchedVehicleRb = null; _npcBoostCurrentMultiplier = 1f; _npcBoostTargetMultiplier = 1f; _npcBoostBaseSpeedKmh = 0f; _agentBoostActive = false; _boostedAgent = null; VehicleAgent.UnmarkedSpeed = 25f; } internal bool TryGetBoostedUnmarkedSpeedForCurrentUpdate(out float boostedUnmarkedSpeed) { boostedUnmarkedSpeed = 0f; if (!_agentBoostActive || (Object)(object)_boostedAgent == (Object)null) { return false; } if (CurrentUpdatingAgentPtr == IntPtr.Zero) { return false; } if (((Il2CppObjectBase)_boostedAgent).Pointer != CurrentUpdatingAgentPtr) { return false; } boostedUnmarkedSpeed = _npcBoostBaseSpeedKmh * _npcBoostCurrentMultiplier; return true; } private void TempBoostLog(string message) { } }
Skitching_Mono.dll
Decompiled a day agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using MelonLoader; using MelonLoader.Preferences; using ScheduleOne.PlayerScripts; using ScheduleOne.Skating; using ScheduleOne.Vehicles; using ScheduleOne.Vehicles.AI; using Skitching; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(global::Skitching.Skitching), "Skitching", "1.0", "Jumble", null)] [assembly: MelonColor] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Skitching_Mono")] [assembly: AssemblyConfiguration("Debug_Mono")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Skitching_Mono")] [assembly: AssemblyTitle("Skitching_Mono")] [assembly: AssemblyVersion("1.0.0.0")] namespace Skitching; public static class BuildInfo { public const string Name = "Skitching"; public const string Description = "Hold onto the back of cars to gain speed on your skateboard."; public const string Author = "Jumble"; public const string Company = null; public const string Version = "1.0"; public const string DownloadLink = null; } public static class Config { private static MelonPreferences_Category configCategory; private static MelonPreferences_Entry<bool> enabledEntry; private static MelonPreferences_Entry<string> skitchKeyEntry; private static MelonPreferences_Entry<float> scanIntervalSecondsEntry; private static MelonPreferences_Entry<float> attachDistanceEntry; private static MelonPreferences_Entry<float> detachDistanceEntry; private static MelonPreferences_Entry<float> tetherBackOffsetEntry; private static MelonPreferences_Entry<float> tetherUpOffsetEntry; private static MelonPreferences_Entry<float> tetherForceEntry; private static MelonPreferences_Entry<float> velocityMatchLerpEntry; private static MelonPreferences_Entry<float> minVehicleSpeedKmhEntry; private static MelonPreferences_Entry<float> npcBoostMinMultiplierEntry; private static MelonPreferences_Entry<float> npcBoostMaxMultiplierEntry; private static MelonPreferences_Entry<float> npcBoostRampPerSecondEntry; public static bool Enabled => enabledEntry?.Value ?? true; public static string SkitchKey => skitchKeyEntry?.Value ?? "E"; public static float ScanIntervalSeconds => scanIntervalSecondsEntry?.Value ?? 0.25f; public static float AttachDistance => attachDistanceEntry?.Value ?? 3f; public static float DetachDistance => detachDistanceEntry?.Value ?? 7f; public static float TetherBackOffset => tetherBackOffsetEntry?.Value ?? 1.3f; public static float TetherUpOffset => tetherUpOffsetEntry?.Value ?? (-0.15f); public static float TetherForce => tetherForceEntry?.Value ?? 35f; public static float VelocityMatchLerp => velocityMatchLerpEntry?.Value ?? 0.9f; public static float MinVehicleSpeedKmh => minVehicleSpeedKmhEntry?.Value ?? 3f; public static float NpcBoostMinMultiplier => npcBoostMinMultiplierEntry?.Value ?? 3f; public static float NpcBoostMaxMultiplier => npcBoostMaxMultiplierEntry?.Value ?? 4f; public static float NpcBoostRampPerSecond => npcBoostRampPerSecondEntry?.Value ?? 0.35f; public static void Load() { configCategory = MelonPreferences.CreateCategory("Skitching"); enabledEntry = configCategory.CreateEntry<bool>("enabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); skitchKeyEntry = configCategory.CreateEntry<string>("skitchKey", "E", (string)null, (string)null, false, false, (ValueValidator)null, (string)null); scanIntervalSecondsEntry = configCategory.CreateEntry<float>("scanIntervalSeconds", 0.25f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); attachDistanceEntry = configCategory.CreateEntry<float>("attachDistance", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); detachDistanceEntry = configCategory.CreateEntry<float>("detachDistance", 7f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); tetherBackOffsetEntry = configCategory.CreateEntry<float>("tetherBackOffset", 1.3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); tetherUpOffsetEntry = configCategory.CreateEntry<float>("tetherUpOffset", -0.15f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); tetherForceEntry = configCategory.CreateEntry<float>("tetherForce", 35f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); velocityMatchLerpEntry = configCategory.CreateEntry<float>("velocityMatchLerp", 0.9f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); minVehicleSpeedKmhEntry = configCategory.CreateEntry<float>("minVehicleSpeedKmh", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); npcBoostMinMultiplierEntry = configCategory.CreateEntry<float>("npcBoostMinMultiplier", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); npcBoostMaxMultiplierEntry = configCategory.CreateEntry<float>("npcBoostMaxMultiplier", 4f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); npcBoostRampPerSecondEntry = configCategory.CreateEntry<float>("npcBoostRampPerSecond", 0.35f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); } } public class Skitching : MelonMod { [HarmonyPatch(typeof(VehicleAgent), "UpdateSpeed")] private static class VehicleAgent_UpdateSpeed_Patch { private static void Prefix(VehicleAgent __instance) { CurrentUpdatingAgent = __instance; Skitching instance = Instance; if (instance == null) { return; } instance.TempBoostLog("UpdateSpeed prefix fired for ptr=0x" + CurrentUpdatingAgentPtr.ToString("X")); if (!instance.TryGetBoostedUnmarkedSpeedForCurrentUpdate(out var boostedUnmarkedSpeed)) { return; } if (boostedUnmarkedSpeed > 25f) { VehicleAgent.UnmarkedSpeed = boostedUnmarkedSpeed; instance.TempBoostLog($"Applied temp UnmarkedSpeed override: 25.00 -> {boostedUnmarkedSpeed:F2}"); } if ((Object)(object)__instance != (Object)null) { float targetSpeed = GetTargetSpeed(__instance); if (boostedUnmarkedSpeed > targetSpeed) { instance.TempBoostLog($"Raising targetSpeed in prefix: {targetSpeed:F2} -> {boostedUnmarkedSpeed:F2}"); SetTargetSpeed(__instance, boostedUnmarkedSpeed); } } } private static void Postfix(VehicleAgent __instance) { Skitching instance = Instance; if (instance != null && instance.TryGetBoostedUnmarkedSpeedForCurrentUpdate(out var boostedUnmarkedSpeed) && (Object)(object)__instance != (Object)null) { float targetSpeed = GetTargetSpeed(__instance); if (boostedUnmarkedSpeed > targetSpeed) { instance.TempBoostLog($"Raising targetSpeed in postfix: {targetSpeed:F2} -> {boostedUnmarkedSpeed:F2}"); SetTargetSpeed(__instance, boostedUnmarkedSpeed); } } if (VehicleAgent.UnmarkedSpeed != 25f) { VehicleAgent.UnmarkedSpeed = 25f; instance?.TempBoostLog("Restoring UnmarkedSpeed to 25.00"); } CurrentUpdatingAgentPtr = IntPtr.Zero; CurrentUpdatingAgent = null; } } internal static Skitching Instance; internal static IntPtr CurrentUpdatingAgentPtr = IntPtr.Zero; internal static VehicleAgent CurrentUpdatingAgent; private KeyCode _skitchKey = (KeyCode)101; private LandVehicle _skitchedVehicle; private Rigidbody _skitchedVehicleRb; private float _nextVehicleScanTime; private float _nextBoostDebugLogTime; private float _npcBoostTargetMultiplier = 1f; private float _npcBoostCurrentMultiplier = 1f; private float _npcBoostBaseSpeedKmh; private bool _agentBoostActive; private VehicleAgent _boostedAgent; public override void OnInitializeMelon() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) Instance = this; Config.Load(); ((MelonBase)this).HarmonyInstance.PatchAll(); if (!Enum.TryParse<KeyCode>(Config.SkitchKey, ignoreCase: true, out _skitchKey)) { MelonLogger.Warning("Invalid skitchKey '" + Config.SkitchKey + "'. Falling back to 'E'."); _skitchKey = (KeyCode)101; } } public override void OnUpdate() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (!Config.Enabled) { return; } Player local = Player.Local; if ((Object)(object)local == (Object)null) { StopSkitching(); return; } Skateboard activeSkateboard = local.ActiveSkateboard; if ((Object)(object)activeSkateboard == (Object)null) { StopSkitching(); } else if ((Object)(object)_skitchedVehicle != (Object)null && _skitchedVehicle.LocalPlayerIsInVehicle) { StopSkitching(); } else if (!Input.GetKey(_skitchKey)) { StopSkitching(); } else if ((Object)(object)_skitchedVehicle == (Object)null && Time.time >= _nextVehicleScanTime) { _nextVehicleScanTime = Time.time + Mathf.Max(0.05f, Config.ScanIntervalSeconds); TryStartSkitching(local, activeSkateboard); } } public override void OnFixedUpdate() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) if (!Config.Enabled || (Object)(object)_skitchedVehicle == (Object)null || (Object)(object)_skitchedVehicleRb == (Object)null) { return; } Player local = Player.Local; if ((Object)(object)local == (Object)null) { StopSkitching(); return; } Skateboard activeSkateboard = local.ActiveSkateboard; if ((Object)(object)activeSkateboard == (Object)null) { StopSkitching(); return; } Rigidbody rb = activeSkateboard.Rb; if ((Object)(object)rb == (Object)null) { StopSkitching(); return; } float num = Vector3.Distance(((Component)activeSkateboard).transform.position, ((Component)_skitchedVehicle).transform.position); if (num > Config.DetachDistance) { StopSkitching(); return; } Vector3 skitchTargetPosition = GetSkitchTargetPosition(_skitchedVehicle); Vector3 val = skitchTargetPosition - ((Component)activeSkateboard).transform.position; rb.AddForce(val * Config.TetherForce, (ForceMode)5); Vector3 velocity = _skitchedVehicleRb.velocity; float num2 = Mathf.Clamp01(Config.VelocityMatchLerp); rb.velocity = Vector3.Lerp(rb.velocity, velocity, num2); ApplyNpcDriverBoost(); } private void TryStartSkitching(Player player, Skateboard board) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) LandVehicle[] array = Object.FindObjectsOfType<LandVehicle>(); if (array == null || array.Length == 0) { return; } LandVehicle val = null; Rigidbody skitchedVehicleRb = null; float num = float.MaxValue; Vector3 position = ((Component)board).transform.position; foreach (LandVehicle val2 in array) { if ((Object)(object)val2 == (Object)null || val2.isParked || val2.Speed_Kmh < Config.MinVehicleSpeedKmh || val2.LocalPlayerIsInVehicle) { continue; } Rigidbody rb = val2.Rb; if (!((Object)(object)rb == (Object)null)) { float num2 = Vector3.Distance(position, ((Component)val2).transform.position); if (num2 <= Config.AttachDistance && num2 < num) { num = num2; val = val2; skitchedVehicleRb = rb; } } } if (!((Object)(object)val == (Object)null)) { _skitchedVehicle = val; _skitchedVehicleRb = skitchedVehicleRb; _npcBoostCurrentMultiplier = 1f; _npcBoostBaseSpeedKmh = 25f; float num3 = Mathf.Max(1f, Config.NpcBoostMinMultiplier); float num4 = Mathf.Max(num3, Config.NpcBoostMaxMultiplier); _npcBoostTargetMultiplier = Random.Range(num3, num4); } } private static Vector3 GetSkitchTargetPosition(LandVehicle vehicle) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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_011d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)vehicle == (Object)null) { return Vector3.zero; } if ((Object)(object)vehicle.boundingBox != (Object)null) { BoxCollider boundingBox = vehicle.boundingBox; Vector3 center = boundingBox.center; Vector3 size = boundingBox.size; float num = Mathf.Abs(size.z * ((Component)boundingBox).transform.lossyScale.z) * 0.5f; float num2 = Mathf.Abs(size.y * ((Component)boundingBox).transform.lossyScale.y) * 0.5f; Vector3 val = ((Component)boundingBox).transform.TransformPoint(center); return val - ((Component)vehicle).transform.forward * (num + Config.TetherBackOffset) - ((Component)vehicle).transform.up * (num2 * 0.6f) + ((Component)vehicle).transform.up * Config.TetherUpOffset; } float num3 = 1.5f; try { Vector3 boundingBoxDimensions = vehicle.BoundingBoxDimensions; if (boundingBoxDimensions.z > 0.1f) { num3 = boundingBoxDimensions.z * 0.5f; } } catch { } return ((Component)vehicle).transform.position - ((Component)vehicle).transform.forward * (num3 + Config.TetherBackOffset) + ((Component)vehicle).transform.up * Config.TetherUpOffset; } private void ApplyNpcDriverBoost() { if ((Object)(object)_skitchedVehicle == (Object)null || (Object)(object)_skitchedVehicleRb == (Object)null || !_skitchedVehicle.IsOccupied || !((Object)(object)_skitchedVehicle.DriverPlayer == (Object)null)) { return; } _npcBoostCurrentMultiplier = Mathf.MoveTowards(_npcBoostCurrentMultiplier, _npcBoostTargetMultiplier, Mathf.Max(0.01f, Config.NpcBoostRampPerSecond) * Time.fixedDeltaTime); VehicleAgent agent = _skitchedVehicle.Agent; if ((Object)(object)agent == (Object)null) { TempBoostLog("ApplyNpcDriverBoost: vehicle has no agent"); return; } if (!_agentBoostActive) { _boostedAgent = agent; _agentBoostActive = true; } TempBoostLog($"Boost active: mult={_npcBoostCurrentMultiplier:F2}, boostedSpeed={_npcBoostBaseSpeedKmh * _npcBoostCurrentMultiplier:F2} km/h, vehicleSpeed={_skitchedVehicle.Speed_Kmh:F1} km/h"); } private void StopSkitching() { bool flag = (Object)(object)_skitchedVehicle != (Object)null || (Object)(object)_skitchedVehicleRb != (Object)null || _agentBoostActive || (Object)(object)_boostedAgent != (Object)null; _skitchedVehicle = null; _skitchedVehicleRb = null; _npcBoostCurrentMultiplier = 1f; _npcBoostTargetMultiplier = 1f; _npcBoostBaseSpeedKmh = 0f; _agentBoostActive = false; _boostedAgent = null; VehicleAgent.UnmarkedSpeed = 25f; } internal bool TryGetBoostedUnmarkedSpeedForCurrentUpdate(out float boostedUnmarkedSpeed) { boostedUnmarkedSpeed = 0f; if (!_agentBoostActive || (Object)(object)_boostedAgent == (Object)null) { return false; } if ((Object)(object)CurrentUpdatingAgent == (Object)null) { return false; } if (_boostedAgent != CurrentUpdatingAgent) { return false; } boostedUnmarkedSpeed = _npcBoostBaseSpeedKmh * _npcBoostCurrentMultiplier; return true; } private static float GetTargetSpeed(VehicleAgent agent) { FieldInfo fieldInfo = AccessTools.Field(typeof(VehicleAgent), "targetSpeed"); if (fieldInfo == null) { return 0f; } return (fieldInfo.GetValue(agent) is float num) ? num : 0f; } private static void SetTargetSpeed(VehicleAgent agent, float value) { AccessTools.Field(typeof(VehicleAgent), "targetSpeed")?.SetValue(agent, value); } private void TempBoostLog(string message) { } }