Decompiled source of Speedometer v1.1.2

Patch3_MelonLoader0.5/Mods/Speedometer.P3.ML5.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using SLZ.Interaction;
using SLZ.Marrow.SceneStreaming;
using SLZ.Marrow.Warehouse;
using SLZ.Rig;
using Sst.Speedometer;
using Sst.Utilities;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Speedometer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany(null)]
[assembly: AssemblyProduct("Speedometer")]
[assembly: AssemblyCopyright("Created by jakzo")]
[assembly: AssemblyTrademark(null)]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.1.2")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: MelonInfo(typeof(Mod), "Speedometer", "1.1.2", "jakzo", "https://bonelab.thunderstore.io/package/jakzo/Speedometer/")]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.1.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Sst
{
	public class Metadata
	{
		public const string AUTHOR = "jakzo";

		public const string COMPANY = null;

		public const string DEVELOPER = "Stress Level Zero";

		public const string GAME = "BONELAB";

		public const string GAME_BONEWORKS = "BONEWORKS";
	}
	public class Dbg
	{
		private static MelonPreferences_Entry<bool> _prefPrintDebugLogs;

		public static void Init(string prefCategoryId)
		{
			_prefPrintDebugLogs = MelonPreferences.CreateCategory(prefCategoryId).CreateEntry<bool>("printDebugLogs", false, "Print debug logs to console", (string)null, false, false, (ValueValidator)null, (string)null);
		}

		public static void Log(string msg, params object[] data)
		{
			if (_prefPrintDebugLogs.Value)
			{
				MelonLogger.Msg("dbg: " + msg);
			}
		}
	}
}
namespace Sst.Utilities
{
	internal static class LevelHooks
	{
		[HarmonyPatch(typeof(BasicTrackingRig), "Awake")]
		private class BasicTrackingRig_Awake_Patch
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static LemonAction <0>__WaitForLoadFinished;
			}

			[HarmonyPrefix]
			internal static void Prefix(BasicTrackingRig __instance)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: 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)
				//IL_0076: Expected O, but got Unknown
				Dbg.Log("BasicTrackingRig_Awake_Patch");
				_loadingScene = ((Component)__instance).gameObject.scene;
				if (Object.op_Implicit((Object)(object)CurrentLevel))
				{
					PrevLevel = CurrentLevel;
				}
				CurrentLevel = null;
				NextLevel = SceneStreamer.Session.Level;
				RigManager = null;
				BasicTrackingRig = __instance;
				MelonEvent onUpdate = MelonEvents.OnUpdate;
				object obj = <>O.<0>__WaitForLoadFinished;
				if (obj == null)
				{
					LemonAction val = WaitForLoadFinished;
					<>O.<0>__WaitForLoadFinished = val;
					obj = (object)val;
				}
				((MelonEventBase<LemonAction>)(object)onUpdate).Subscribe((LemonAction)obj, 0, false);
				LevelCrate nextLevel = NextLevel;
				Dbg.Log("OnLoad " + ((nextLevel != null) ? ((Scannable)nextLevel).Title : null));
				SafeInvoke("OnLoad", LevelHooks.OnLoad, NextLevel);
			}
		}

		[HarmonyPatch(typeof(RigManager), "Awake")]
		private class RigManager_Awake_Patch
		{
			[HarmonyPrefix]
			internal static void Prefix(RigManager __instance)
			{
				Dbg.Log("RigManager_Awake_Patch");
				RigManager = __instance;
				BasicTrackingRig = null;
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static LemonAction <0>__WaitForLoadFinished;
		}

		public static LevelCrate PrevLevel;

		public static LevelCrate CurrentLevel;

		public static LevelCrate NextLevel;

		public static RigManager RigManager;

		public static BasicTrackingRig BasicTrackingRig;

		private static Scene _loadingScene;

		public static bool IsLoading => !Object.op_Implicit((Object)(object)CurrentLevel);

		public static event Action<LevelCrate> OnLoad;

		public static event Action<LevelCrate> OnLevelStart;

		private static void SafeInvoke(string name, Action<LevelCrate> action, LevelCrate level)
		{
			try
			{
				action?.Invoke(level);
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Failed to execute " + name + " event: " + ex.ToString());
			}
		}

		private static void WaitForLoadFinished()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if (!((Scene)(ref _loadingScene)).isLoaded)
			{
				MelonEvent onUpdate = MelonEvents.OnUpdate;
				object obj = <>O.<0>__WaitForLoadFinished;
				if (obj == null)
				{
					LemonAction val = WaitForLoadFinished;
					<>O.<0>__WaitForLoadFinished = val;
					obj = (object)val;
				}
				((MelonEventBase<LemonAction>)(object)onUpdate).Unsubscribe((LemonAction)obj);
				CurrentLevel = NextLevel ?? SceneStreamer.Session.Level ?? CurrentLevel;
				NextLevel = null;
				LevelCrate currentLevel = CurrentLevel;
				Dbg.Log("OnLevelStart " + ((currentLevel != null) ? ((Scannable)currentLevel).Title : null));
				SafeInvoke("OnLevelStart", LevelHooks.OnLevelStart, CurrentLevel);
			}
		}
	}
	public class Bonelab
	{
		private static Shader _highlightShader;

		public static Shader HighlightShader => _highlightShader ?? (_highlightShader = ((IEnumerable<Shader>)Resources.FindObjectsOfTypeAll<Shader>()).First((Shader shader) => ((Object)shader).name == "SLZ/Highlighter"));

		public static void DockToWrist(GameObject gameObject, bool rightHand = false)
		{
			//IL_0043: 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)
			PhysicsRig physicsRig = LevelHooks.RigManager.physicsRig;
			Hand val = (rightHand ? physicsRig.rightHand : physicsRig.leftHand);
			gameObject.transform.SetParent(((Component)val).transform);
			gameObject.transform.localPosition = new Vector3(-0.31f, 0.3f, 0f);
			gameObject.transform.localRotation = Quaternion.Euler(32f, 4f, 3f);
		}

		public static TextMeshPro CreateTextOnWrist(string name, bool rightHand = false)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			TextMeshPro obj = val.AddComponent<TextMeshPro>();
			((TMP_Text)obj).alignment = (TextAlignmentOptions)1028;
			((TMP_Text)obj).fontSize = 0.5f;
			((TMP_Text)obj).rectTransform.sizeDelta = new Vector2(0.8f, 0.5f);
			DockToWrist(val, rightHand);
			return obj;
		}
	}
}
namespace Sst.Speedometer
{
	internal static class AppVersion
	{
		public const string Value = "1.1.2";
	}
	public static class BuildInfo
	{
		public const string NAME = "Speedometer";
	}
	public class Mod : MelonMod
	{
		private enum Units
		{
			MS,
			KPH,
			MPH
		}

		private const string SPEEDOMETER_TEXT_NAME = "Speedometer";

		private MelonPreferences_Entry<bool> _prefRightHand;

		private MelonPreferences_Entry<Units> _prefUnits;

		private MelonPreferences_Entry<float> _prefWindowDuration;

		private TextMeshPro _tmp;

		private SpeedTracker _speedTracker;

		public override void OnInitializeMelon()
		{
			Dbg.Init("Speedometer");
			MelonPreferences_Category val = MelonPreferences.CreateCategory("Speedometer");
			_prefRightHand = val.CreateEntry<bool>("right_hand", false, "Show speed reading on right hand instead of left", (string)null, false, false, (ValueValidator)null, (string)null);
			_prefUnits = val.CreateEntry<Units>("units", Units.MS, "Units to measure speed in", (string)null, false, false, (ValueValidator)null, (string)null);
			_prefWindowDuration = val.CreateEntry<float>("window_duration", 0.25f, "Number of seconds to average the speed over", (string)null, false, false, (ValueValidator)null, (string)null);
			LevelHooks.OnLevelStart += OnLevelStart;
		}

		public void OnLevelStart(LevelCrate level)
		{
			float value = _prefWindowDuration.Value;
			_speedTracker = new SpeedTracker
			{
				WindowDuration = value,
				BufferSize = Mathf.CeilToInt(value * 240f)
			};
			_tmp = Bonelab.CreateTextOnWrist("Speedometer", _prefRightHand.Value);
		}

		public override void OnUpdate()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			if (!LevelHooks.IsLoading && _speedTracker != null)
			{
				Vector3 position = ((Rig)LevelHooks.RigManager.physicsRig).m_head.position;
				_speedTracker.OnFrame(Time.time, position.x, position.z);
				TextMeshPro tmp = _tmp;
				if (tmp != null)
				{
					((TMP_Text)tmp).SetText(GetSpeedText(_speedTracker.GetSpeed()), true);
				}
			}
		}

		private string GetSpeedText(float speedMs)
		{
			return _prefUnits.Value switch
			{
				Units.KPH => $"{speedMs * 3.6f:N1}kph", 
				Units.MPH => $"{speedMs * 2.237f:N1}mph", 
				_ => $"{speedMs:N2}m/s", 
			};
		}
	}
	internal class SpeedTracker
	{
		public int BufferSize = 1000;

		public float WindowDuration = 1f;

		private (float, float, float)[] _frames;

		private int _idxStart;

		private int _idxEnd;

		public SpeedTracker()
		{
			_frames = new(float, float, float)[BufferSize];
		}

		public void OnFrame(float time, float posX, float posZ)
		{
			_frames[_idxEnd] = (time, posX, posZ);
			_idxEnd++;
			if (_idxEnd >= _frames.Length)
			{
				_idxEnd = 0;
			}
			if (_idxEnd == _idxStart)
			{
				_idxStart++;
				if (_idxStart >= _frames.Length)
				{
					_idxStart = 0;
				}
			}
		}

		public float GetSpeed()
		{
			if (_idxEnd == _idxStart)
			{
				return 0f;
			}
			(float, float, float) tuple = _frames[((_idxEnd <= 0) ? _frames.Length : _idxEnd) - 1];
			float num = tuple.Item1 - WindowDuration;
			while (_idxStart != _idxEnd && _frames[_idxStart].Item1 < num)
			{
				_idxStart++;
				if (_idxStart >= _frames.Length)
				{
					_idxStart = 0;
				}
			}
			(float, float, float) tuple2 = _frames[_idxStart];
			float num2 = tuple.Item2 - tuple2.Item2;
			float num3 = tuple.Item3 - tuple2.Item3;
			float num4 = tuple.Item1 - tuple2.Item1;
			return Mathf.Sqrt(num2 * num2 + num3 * num3) / num4;
		}
	}
}

Patch4_MelonLoader0.6/Mods/Speedometer.P4.ML6.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using HarmonyLib;
using Il2CppSLZ.Interaction;
using Il2CppSLZ.Marrow.SceneStreaming;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.Rig;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using Sst.Speedometer;
using Sst.Utilities;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Speedometer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany(null)]
[assembly: AssemblyProduct("Speedometer")]
[assembly: AssemblyCopyright("Created by jakzo")]
[assembly: AssemblyTrademark(null)]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.1.2")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: MelonInfo(typeof(Mod), "Speedometer", "1.1.2", "jakzo", "https://bonelab.thunderstore.io/package/jakzo/Speedometer/")]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("1.1.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Sst
{
	public class Metadata
	{
		public const string AUTHOR = "jakzo";

		public const string COMPANY = null;

		public const string DEVELOPER = "Stress Level Zero";

		public const string GAME = "BONELAB";

		public const string GAME_BONEWORKS = "BONEWORKS";
	}
	public class Dbg
	{
		private static MelonPreferences_Entry<bool> _prefPrintDebugLogs;

		public static void Init(string prefCategoryId)
		{
			_prefPrintDebugLogs = MelonPreferences.CreateCategory(prefCategoryId).CreateEntry<bool>("printDebugLogs", false, "Print debug logs to console", (string)null, false, false, (ValueValidator)null, (string)null);
		}

		public static void Log(string msg, params object[] data)
		{
			if (_prefPrintDebugLogs.Value)
			{
				MelonLogger.Msg("dbg: " + msg);
			}
		}
	}
}
namespace Sst.Utilities
{
	internal static class LevelHooks
	{
		[HarmonyPatch(typeof(BasicTrackingRig), "Awake")]
		private class BasicTrackingRig_Awake_Patch
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static LemonAction <0>__WaitForLoadFinished;
			}

			[HarmonyPrefix]
			internal static void Prefix(BasicTrackingRig __instance)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: 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)
				//IL_0076: Expected O, but got Unknown
				Dbg.Log("BasicTrackingRig_Awake_Patch");
				_loadingScene = ((Component)__instance).gameObject.scene;
				if (Object.op_Implicit((Object)(object)CurrentLevel))
				{
					PrevLevel = CurrentLevel;
				}
				CurrentLevel = null;
				NextLevel = SceneStreamer.Session.Level;
				RigManager = null;
				BasicTrackingRig = __instance;
				MelonEvent onUpdate = MelonEvents.OnUpdate;
				object obj = <>O.<0>__WaitForLoadFinished;
				if (obj == null)
				{
					LemonAction val = WaitForLoadFinished;
					<>O.<0>__WaitForLoadFinished = val;
					obj = (object)val;
				}
				((MelonEventBase<LemonAction>)(object)onUpdate).Subscribe((LemonAction)obj, 0, false);
				LevelCrate nextLevel = NextLevel;
				Dbg.Log("OnLoad " + ((nextLevel != null) ? ((Scannable)nextLevel).Title : null));
				SafeInvoke("OnLoad", LevelHooks.OnLoad, NextLevel);
			}
		}

		[HarmonyPatch(typeof(RigManager), "Awake")]
		private class RigManager_Awake_Patch
		{
			[HarmonyPrefix]
			internal static void Prefix(RigManager __instance)
			{
				Dbg.Log("RigManager_Awake_Patch");
				RigManager = __instance;
				BasicTrackingRig = null;
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static LemonAction <0>__WaitForLoadFinished;
		}

		public static LevelCrate PrevLevel;

		public static LevelCrate CurrentLevel;

		public static LevelCrate NextLevel;

		public static RigManager RigManager;

		public static BasicTrackingRig BasicTrackingRig;

		private static Scene _loadingScene;

		public static bool IsLoading => !Object.op_Implicit((Object)(object)CurrentLevel);

		public static event Action<LevelCrate> OnLoad;

		public static event Action<LevelCrate> OnLevelStart;

		private static void SafeInvoke(string name, Action<LevelCrate> action, LevelCrate level)
		{
			try
			{
				action?.Invoke(level);
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Failed to execute " + name + " event: " + ex.ToString());
			}
		}

		private static void WaitForLoadFinished()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if (!((Scene)(ref _loadingScene)).isLoaded)
			{
				MelonEvent onUpdate = MelonEvents.OnUpdate;
				object obj = <>O.<0>__WaitForLoadFinished;
				if (obj == null)
				{
					LemonAction val = WaitForLoadFinished;
					<>O.<0>__WaitForLoadFinished = val;
					obj = (object)val;
				}
				((MelonEventBase<LemonAction>)(object)onUpdate).Unsubscribe((LemonAction)obj);
				CurrentLevel = NextLevel ?? SceneStreamer.Session.Level ?? CurrentLevel;
				NextLevel = null;
				LevelCrate currentLevel = CurrentLevel;
				Dbg.Log("OnLevelStart " + ((currentLevel != null) ? ((Scannable)currentLevel).Title : null));
				SafeInvoke("OnLevelStart", LevelHooks.OnLevelStart, CurrentLevel);
			}
		}
	}
	public class Bonelab
	{
		private static Shader _highlightShader;

		public static Shader HighlightShader => _highlightShader ?? (_highlightShader = ((IEnumerable<Shader>)Resources.FindObjectsOfTypeAll<Shader>()).First((Shader shader) => ((Object)shader).name == "SLZ/Highlighter"));

		public static void DockToWrist(GameObject gameObject, bool rightHand = false)
		{
			//IL_0043: 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)
			PhysicsRig physicsRig = LevelHooks.RigManager.physicsRig;
			Hand val = (rightHand ? physicsRig.rightHand : physicsRig.leftHand);
			gameObject.transform.SetParent(((Component)val).transform);
			gameObject.transform.localPosition = new Vector3(-0.31f, 0.3f, 0f);
			gameObject.transform.localRotation = Quaternion.Euler(32f, 4f, 3f);
		}

		public static TextMeshPro CreateTextOnWrist(string name, bool rightHand = false)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			TextMeshPro obj = val.AddComponent<TextMeshPro>();
			((TMP_Text)obj).alignment = (TextAlignmentOptions)1028;
			((TMP_Text)obj).fontSize = 0.5f;
			((TMP_Text)obj).rectTransform.sizeDelta = new Vector2(0.8f, 0.5f);
			DockToWrist(val, rightHand);
			return obj;
		}
	}
}
namespace Sst.Speedometer
{
	internal static class AppVersion
	{
		public const string Value = "1.1.2";
	}
	public static class BuildInfo
	{
		public const string NAME = "Speedometer";
	}
	public class Mod : MelonMod
	{
		private enum Units
		{
			MS,
			KPH,
			MPH
		}

		private const string SPEEDOMETER_TEXT_NAME = "Speedometer";

		private MelonPreferences_Entry<bool> _prefRightHand;

		private MelonPreferences_Entry<Units> _prefUnits;

		private MelonPreferences_Entry<float> _prefWindowDuration;

		private TextMeshPro _tmp;

		private SpeedTracker _speedTracker;

		public override void OnInitializeMelon()
		{
			Dbg.Init("Speedometer");
			MelonPreferences_Category val = MelonPreferences.CreateCategory("Speedometer");
			_prefRightHand = val.CreateEntry<bool>("right_hand", false, "Show speed reading on right hand instead of left", (string)null, false, false, (ValueValidator)null, (string)null);
			_prefUnits = val.CreateEntry<Units>("units", Units.MS, "Units to measure speed in", (string)null, false, false, (ValueValidator)null, (string)null);
			_prefWindowDuration = val.CreateEntry<float>("window_duration", 0.25f, "Number of seconds to average the speed over", (string)null, false, false, (ValueValidator)null, (string)null);
			LevelHooks.OnLevelStart += OnLevelStart;
		}

		public void OnLevelStart(LevelCrate level)
		{
			float value = _prefWindowDuration.Value;
			_speedTracker = new SpeedTracker
			{
				WindowDuration = value,
				BufferSize = Mathf.CeilToInt(value * 240f)
			};
			_tmp = Bonelab.CreateTextOnWrist("Speedometer", _prefRightHand.Value);
		}

		public override void OnUpdate()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			if (!LevelHooks.IsLoading && _speedTracker != null)
			{
				Vector3 position = ((Rig)LevelHooks.RigManager.physicsRig).m_head.position;
				_speedTracker.OnFrame(Time.time, position.x, position.z);
				TextMeshPro tmp = _tmp;
				if (tmp != null)
				{
					((TMP_Text)tmp).SetText(GetSpeedText(_speedTracker.GetSpeed()), true);
				}
			}
		}

		private string GetSpeedText(float speedMs)
		{
			return _prefUnits.Value switch
			{
				Units.KPH => $"{speedMs * 3.6f:N1}kph", 
				Units.MPH => $"{speedMs * 2.237f:N1}mph", 
				_ => $"{speedMs:N2}m/s", 
			};
		}
	}
	internal class SpeedTracker
	{
		public int BufferSize = 1000;

		public float WindowDuration = 1f;

		private (float, float, float)[] _frames;

		private int _idxStart;

		private int _idxEnd;

		public SpeedTracker()
		{
			_frames = new(float, float, float)[BufferSize];
		}

		public void OnFrame(float time, float posX, float posZ)
		{
			_frames[_idxEnd] = (time, posX, posZ);
			_idxEnd++;
			if (_idxEnd >= _frames.Length)
			{
				_idxEnd = 0;
			}
			if (_idxEnd == _idxStart)
			{
				_idxStart++;
				if (_idxStart >= _frames.Length)
				{
					_idxStart = 0;
				}
			}
		}

		public float GetSpeed()
		{
			if (_idxEnd == _idxStart)
			{
				return 0f;
			}
			(float, float, float) tuple = _frames[((_idxEnd <= 0) ? _frames.Length : _idxEnd) - 1];
			float num = tuple.Item1 - WindowDuration;
			while (_idxStart != _idxEnd && _frames[_idxStart].Item1 < num)
			{
				_idxStart++;
				if (_idxStart >= _frames.Length)
				{
					_idxStart = 0;
				}
			}
			(float, float, float) tuple2 = _frames[_idxStart];
			float num2 = tuple.Item2 - tuple2.Item2;
			float num3 = tuple.Item3 - tuple2.Item3;
			float num4 = tuple.Item1 - tuple2.Item1;
			return Mathf.Sqrt(num2 * num2 + num3 * num3) / num4;
		}
	}
}