Decompiled source of FlickRacingTimer v1.0.0

Mods/FlickRacingTimer.dll

Decompiled 3 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using FlickRacingTimer;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppRUMBLE.Environment.Minigames;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.MoveSystem;
using Il2CppRUMBLE.Physics.Utility;
using Il2CppRUMBLE.Players.Subsystems;
using Il2CppRUMBLE.Utilities;
using Il2CppTMPro;
using MelonLoader;
using RumbleModUI;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Mod), "FlickRacingTimer", "1.0.0", "Tortaneose and MasterMischief", null)]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: AssemblyTitle("FlickRacingTimer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FlickRacingTimer")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: MelonColor(255, 0, 255, 0)]
[assembly: MelonAuthorColor(255, 0, 255, 0)]
[assembly: ComVisible(false)]
[assembly: Guid("d3e35beb-1a4f-42df-bda4-23a479aac4a2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace FlickRacingTimer;

public class Mod : MelonMod
{
	[HarmonyPatch(typeof(Stack), "Execute")]
	private static class Stack_Execute_Patch
	{
		private static void Postfix(Stack __instance, IProcessor processor)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.cachedName == "Jump" && !isFlying && (Object)(object)((Il2CppObjectBase)processor).Cast<PlayerStackProcessor>() == (Object)(object)Singleton<PlayerManager>.instance.localPlayer.Controller.GetSubsystem<PlayerStackProcessor>())
			{
				isFlying = true;
				takeoffChecked = false;
				timer = 0.0;
				if ((Object)(object)timerObject != (Object)null)
				{
					((TMP_Text)timerText).text = FormatTimeSpan(new TimeSpan(0L));
					((Graphic)timerText).color = Color.white;
				}
			}
		}
	}

	[HarmonyPatch(typeof(PlayerMovement), "OnBecameGrounded")]
	private static class PlayerMovement_OnBecameGrounded_Patch
	{
		private static void Postfix(PlayerMovement __instance)
		{
			if (isFlying && (Object)(object)__instance == (Object)(object)Singleton<PlayerManager>.instance.localPlayer.Controller.GetSubsystem<PlayerMovement>())
			{
				HandleLanding();
			}
		}
	}

	[HarmonyPatch(typeof(PlayAudioOnImpact), "OnCollisionEnter")]
	private static class PlayAudioOnImpact_OnCollisionEnter_Patch
	{
		private static void Postfix(PlayAudioOnImpact __instance, Collision collision)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			if (!isFlying)
			{
				return;
			}
			ContactPoint val = ((Il2CppArrayBase<ContactPoint>)(object)collision.contacts)[0];
			if (!((Object)(object)((ContactPoint)(ref val)).thisCollider == (Object)(object)Singleton<PlayerManager>.instance.localPlayer.Controller.GetSubsystem<PlayerPhysics>().pillBodyCollider) || vehicles.Contains(((Object)collision.gameObject).name))
			{
				return;
			}
			for (int i = 0; i < collision.contactCount; i++)
			{
				val = ((Il2CppArrayBase<ContactPoint>)(object)collision.contacts)[i];
				if (((ContactPoint)(ref val)).normal.y > maxNormalY)
				{
					HandleLanding();
				}
			}
		}
	}

	[HarmonyPatch(typeof(ParkMinigame), "OnMiniGameEnded")]
	private static class Patch
	{
		private static void Prefix()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (isFlying)
			{
				if ((bool)((ModSetting)logTimes).Value)
				{
					MelonLogger.Msg("Flick Racing time: " + FormatTimeSpan(TimeSpan.FromSeconds(timer)));
				}
				isFlying = false;
				if ((Object)(object)timerObject != (Object)null)
				{
					((Graphic)timerText).color = Color.red;
				}
			}
		}
	}

	private static readonly Vector3 leftRelativeTranslate = new Vector3(-0.03f, -0.02f, 0f);

	private static readonly Vector3 rightRelativeTranslate = new Vector3(0f - leftRelativeTranslate.x, leftRelativeTranslate.y, leftRelativeTranslate.z);

	private static readonly Vector3 globalTranslate = new Vector3(0f, 0.15f, 0f);

	private static readonly Vector3 healthRelativeTranslate = new Vector3(0f, 0.05f, 1f);

	private static readonly HashSet<string> vehicles = new HashSet<string> { "Disc", "Pillar", "Ball", "RockCube", "Wall", "LargeRock", "SmallRock", "BoulderBall" };

	private static readonly float maxNormalY = 0.5f;

	private static Mod settings = new Mod();

	private static ModSetting<bool> displayTimer;

	private static ModSetting<bool> logTimes;

	private static ModSetting<bool> swapHand;

	private static ModSetting<bool> displayAboveHealth;

	private static double timer = 0.0;

	private static bool isFlying = false;

	private static bool takeoffChecked = false;

	private static GameObject timerObject;

	private static TextMeshPro timerText;

	private static GameObject healthBar;

	public static string FormatTimeSpan(TimeSpan timeSpan)
	{
		List<string> list = new List<string>();
		if (timeSpan.Days > 0)
		{
			list.Add(timeSpan.Days.ToString());
		}
		if (timeSpan.Hours > 0 || list.Count > 0)
		{
			list.Add(timeSpan.Hours.ToString("D2"));
		}
		if (timeSpan.Minutes > 0 || list.Count > 0)
		{
			list.Add(timeSpan.Minutes.ToString("D2"));
		}
		list.Add(timeSpan.Seconds.ToString((list.Count == 0) ? "D1" : "D2") + "." + timeSpan.Milliseconds.ToString("D3"));
		if (list.Count == 1)
		{
			list[0] += "s";
		}
		return string.Join(":", list);
	}

	private static void HandleLanding()
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		if ((bool)((ModSetting)logTimes).Value)
		{
			MelonLogger.Msg("Flight time: " + FormatTimeSpan(TimeSpan.FromSeconds(timer)));
		}
		isFlying = false;
		if ((Object)(object)timerObject != (Object)null)
		{
			((Graphic)timerText).color = Color.green;
		}
	}

	private static void CreateTimer()
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)timerObject == (Object)null))
		{
			return;
		}
		timerObject = new GameObject("FlightTimer");
		timerText = timerObject.AddComponent<TextMeshPro>();
		((TMP_Text)timerText).text = FormatTimeSpan(new TimeSpan(0L));
		foreach (TMP_FontAsset item in Resources.FindObjectsOfTypeAll<TMP_FontAsset>())
		{
			if (((Object)item).name == "GOODDP__ SDF Global Text Material")
			{
				((TMP_Text)timerText).font = item;
				break;
			}
		}
		((TMP_Text)timerText).fontSize = 0.5f;
		((Graphic)timerText).color = Color.white;
		((TMP_Text)timerText).alignment = (TextAlignmentOptions)514;
		((TMP_Text)timerText).enableWordWrapping = false;
		if (!(bool)((ModSetting)displayTimer).SavedValue)
		{
			((TMP_Text)timerText).maxVisibleCharacters = 0;
		}
	}

	public override void OnLateInitializeMelon()
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Expected O, but got Unknown
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Expected O, but got Unknown
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Expected O, but got Unknown
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Expected O, but got Unknown
		settings.ModName = "FlightTimer";
		settings.ModVersion = "1.0.0";
		settings.SetFolder("FlightTimer");
		displayTimer = settings.AddToList("Display Timer", true, 0, "Disable to hide the timer. Times will still be logged if \"Log Times\" is true.", new Tags());
		logTimes = settings.AddToList("Log Times", true, 0, "Enable to log flight times to the console.", new Tags());
		swapHand = settings.AddToList("Swap Hand", false, 0, "Enable to display the timer on the right hand instead of the left.", new Tags());
		displayAboveHealth = settings.AddToList("Display Above Health", false, 0, "Enable to display the timer above the health bar instead of either hand.", new Tags());
		settings.GetFromFile();
		((ModSetting)displayTimer).SavedValueChanged += OnDisplayTimerChange;
		((ModSetting)displayAboveHealth).SavedValueChanged += OnDisplayAboveHealthChanged;
		UI.instance.UI_Initialized += OnUIInit;
	}

	public static void OnUIInit()
	{
		UI.instance.AddMod(settings);
	}

	public static void OnDisplayTimerChange(object sender, EventArgs args)
	{
		if ((Object)(object)timerObject != (Object)null)
		{
			if (((ValueChange<bool>)(object)args).Value)
			{
				((TMP_Text)timerText).maxVisibleCharacters = 999;
			}
			else
			{
				((TMP_Text)timerText).maxVisibleCharacters = 0;
			}
		}
	}

	public static void OnDisplayAboveHealthChanged(object sender, EventArgs args)
	{
		if ((Object)(object)timerObject != (Object)null)
		{
			if (((ValueChange<bool>)(object)args).Value)
			{
				healthBar = null;
			}
			else
			{
				timerObject.transform.parent = null;
			}
		}
	}

	public override void OnSceneWasInitialized(int buildIndex, string sceneName)
	{
		healthBar = null;
		CreateTimer();
	}

	public override void OnUpdate()
	{
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: 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)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: 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)
		if (isFlying)
		{
			timer += Time.deltaTime;
			if ((Object)(object)timerObject != (Object)null)
			{
				((TMP_Text)timerText).text = FormatTimeSpan(TimeSpan.FromSeconds(timer));
			}
			if (!takeoffChecked && timer > 1.0)
			{
				takeoffChecked = true;
				if (Singleton<PlayerManager>.instance.localPlayer.Controller.GetSubsystem<PlayerMovement>().IsGrounded())
				{
					HandleLanding();
				}
			}
		}
		if ((Object)(object)timerObject == (Object)null)
		{
			CreateTimer();
		}
		if (!((Object)(object)timerObject != (Object)null) || !((Object)(object)Singleton<PlayerManager>.instance != (Object)null) || Singleton<PlayerManager>.instance.localPlayer == null || !((Object)(object)Singleton<PlayerManager>.instance.localPlayer.Controller != (Object)null))
		{
			return;
		}
		if (!(bool)((ModSetting)displayAboveHealth).SavedValue)
		{
			Transform child = ((Component)Singleton<PlayerManager>.instance.localPlayer.Controller).gameObject.transform.GetChild(1).GetChild((!(bool)((ModSetting)swapHand).SavedValue) ? 1 : 2);
			timerObject.transform.position = child.position;
			timerObject.transform.Translate(((bool)((ModSetting)swapHand).SavedValue) ? rightRelativeTranslate : leftRelativeTranslate, child);
			timerObject.transform.Translate(globalTranslate, (Space)0);
		}
		else if ((Object)(object)healthBar == (Object)null)
		{
			healthBar = Singleton<PlayerManager>.instance.localPlayer.Controller.GetSubsystem<PlayerHealth>().localHealthbar;
			if ((Object)(object)healthBar != (Object)null)
			{
				timerObject.transform.parent = healthBar.transform;
				timerObject.transform.localPosition = healthRelativeTranslate;
			}
		}
		timerObject.transform.rotation = Quaternion.LookRotation(timerObject.transform.position - ((Component)Camera.main).transform.position);
	}
}