Decompiled source of ShotSpeedometer v0.1.0

ShotSpeedometer.dll

Decompiled 5 hours ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ShotSpeedometer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShotSpeedometer")]
[assembly: AssemblyTitle("ShotSpeedometer")]
[assembly: AssemblyVersion("1.0.0.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 ShotSpeedometer
{
	[BepInPlugin("sbg.shotspeedometer", "ShotSpeedometer", "0.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(WorldspaceIconUi), "Initialize")]
		private static class Patch_WorldspaceIconUi_Initialize
		{
			private static void Postfix(WorldspaceIconUi __instance, Transform parent)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					BallSpeedLabel.AttachOrUpdate(__instance, parent);
				}
			}
		}

		public const string ModGuid = "sbg.shotspeedometer";

		public const string ModName = "ShotSpeedometer";

		public const string ModVersion = "0.1.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal ConfigEntry<bool> hideAtRestConfig;

		internal ConfigEntry<float> minSpeedToShowConfig;

		internal ConfigEntry<float> verticalOffsetConfig;

		private void Awake()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			hideAtRestConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "HideAtRest", true, "Hide the speed line when the ball is below MinSpeedToShow. Disable to keep it visible whenever the ball icon is on screen.");
			minSpeedToShowConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "MinSpeedToShow", 0.3f, "Speed threshold (m/s) below which the label hides when HideAtRest is true.");
			verticalOffsetConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "VerticalOffset", -22f, "Vertical offset in pixels of the speed line relative to the distance label. Negative values place it below.");
			new Harmony("sbg.shotspeedometer").PatchAll();
			Log.LogInfo((object)"ShotSpeedometer v0.1.0 loaded.");
		}
	}
	internal sealed class BallSpeedLabel : MonoBehaviour
	{
		private static readonly FieldInfo distanceLabelField = AccessTools.Field(typeof(WorldspaceIconUi), "distanceLabel");

		private WorldspaceIconUi host;

		private TextMeshProUGUI distanceLabel;

		private TextMeshProUGUI speedLabel;

		private Rigidbody ballRigidbody;

		private int lastDisplayed = int.MinValue;

		private bool unitListenerHooked;

		public static void AttachOrUpdate(WorldspaceIconUi icon, Transform parent)
		{
			BallSpeedLabel ballSpeedLabel = ((Component)icon).GetComponent<BallSpeedLabel>();
			GolfBall val = (((Object)(object)parent != (Object)null) ? ((Component)parent).GetComponent<GolfBall>() : null);
			if ((Object)(object)val == (Object)null)
			{
				if ((Object)(object)ballSpeedLabel != (Object)null)
				{
					ballSpeedLabel.Detach();
				}
				return;
			}
			if ((Object)(object)ballSpeedLabel == (Object)null)
			{
				ballSpeedLabel = ((Component)icon).gameObject.AddComponent<BallSpeedLabel>();
			}
			ballSpeedLabel.Bind(icon, val);
		}

		private void Bind(WorldspaceIconUi icon, GolfBall ball)
		{
			host = icon;
			ballRigidbody = (((Object)(object)ball != (Object)null) ? ((Component)ball).GetComponent<Rigidbody>() : null);
			if ((Object)(object)distanceLabel == (Object)null)
			{
				ref TextMeshProUGUI reference = ref distanceLabel;
				object? obj = distanceLabelField?.GetValue(icon);
				reference = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null);
				if ((Object)(object)distanceLabel == (Object)null)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"WorldspaceIconUi.distanceLabel was null; cannot mount speed label.");
					}
					((Behaviour)this).enabled = false;
					return;
				}
			}
			if ((Object)(object)speedLabel == (Object)null)
			{
				BuildSpeedLabel();
			}
			if ((Object)(object)speedLabel != (Object)null)
			{
				((Component)speedLabel).gameObject.SetActive(true);
			}
			if (!unitListenerHooked)
			{
				GeneralSettings.DistanceUnitChanged = (Action)Delegate.Combine(GeneralSettings.DistanceUnitChanged, new Action(OnUnitChanged));
				unitListenerHooked = true;
			}
			lastDisplayed = int.MinValue;
		}

		private void Detach()
		{
			if ((Object)(object)speedLabel != (Object)null)
			{
				((Component)speedLabel).gameObject.SetActive(false);
			}
			ballRigidbody = null;
		}

		private void BuildSpeedLabel()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_008f: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00a9: 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_00cd: 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)
			GameObject val = Object.Instantiate<GameObject>(((Component)distanceLabel).gameObject, ((TMP_Text)distanceLabel).transform.parent);
			((Object)val).name = "ShotSpeedometer-SpeedLabel";
			speedLabel = val.GetComponent<TextMeshProUGUI>();
			if ((Object)(object)speedLabel == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Cloned distance label is missing TMP component.");
				}
				Object.Destroy((Object)(object)val);
			}
			else
			{
				RectTransform val2 = (RectTransform)((TMP_Text)distanceLabel).transform;
				RectTransform val3 = (RectTransform)((TMP_Text)speedLabel).transform;
				val3.anchorMin = val2.anchorMin;
				val3.anchorMax = val2.anchorMax;
				val3.pivot = val2.pivot;
				val3.sizeDelta = val2.sizeDelta;
				val3.anchoredPosition = val2.anchoredPosition + new Vector2(0f, Plugin.Instance.verticalOffsetConfig.Value);
				((TMP_Text)speedLabel).text = string.Empty;
			}
		}

		private void LateUpdate()
		{
			//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)
			if (!((Object)(object)host == (Object)null) && !((Object)(object)speedLabel == (Object)null) && !((Object)(object)ballRigidbody == (Object)null))
			{
				Vector3 linearVelocity = ballRigidbody.linearVelocity;
				float magnitude = ((Vector3)(ref linearVelocity)).magnitude;
				bool flag = !Plugin.Instance.hideAtRestConfig.Value || magnitude >= Plugin.Instance.minSpeedToShowConfig.Value;
				if (((Component)speedLabel).gameObject.activeSelf != flag)
				{
					((Component)speedLabel).gameObject.SetActive(flag);
				}
				if (flag)
				{
					UpdateText(magnitude);
				}
			}
		}

		private void UpdateText(float speedMps)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			float num = speedMps * 3.6f;
			int num2;
			string format;
			if ((int)GameSettings.All.General.DistanceUnits == 1)
			{
				num2 = Mathf.RoundToInt(num * 0.621371f);
				format = "{0} mph";
			}
			else
			{
				num2 = Mathf.RoundToInt(num);
				format = "{0} kph";
			}
			if (num2 != lastDisplayed)
			{
				lastDisplayed = num2;
				((TMP_Text)speedLabel).text = string.Format(format, num2);
			}
		}

		private void OnUnitChanged()
		{
			lastDisplayed = int.MinValue;
		}

		private void OnDestroy()
		{
			if (unitListenerHooked)
			{
				GeneralSettings.DistanceUnitChanged = (Action)Delegate.Remove(GeneralSettings.DistanceUnitChanged, new Action(OnUnitChanged));
				unitListenerHooked = false;
			}
		}
	}
}