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.2.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.2.0"; internal static ManualLogSource Log; internal static Plugin Instance; internal ConfigEntry hideAtRestConfig; internal ConfigEntry minSpeedToShowConfig; internal ConfigEntry 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("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("Display", "MinSpeedToShow", 0.3f, "Speed threshold (m/s) below which the label hides when HideAtRest is true."); verticalOffsetConfig = ((BaseUnityPlugin)this).Config.Bind("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.2.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(); GolfBall val = (((Object)(object)parent != (Object)null) ? ((Component)parent).GetComponent() : 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.Bind(icon, val); } private void Bind(WorldspaceIconUi icon, GolfBall ball) { host = icon; ballRigidbody = (((Object)(object)ball != (Object)null) ? ((Component)ball).GetComponent() : 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.SpeedUnitChanged = (Action)Delegate.Combine(GeneralSettings.SpeedUnitChanged, 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(((Component)distanceLabel).gameObject, ((TMP_Text)distanceLabel).transform.parent); ((Object)val).name = "ShotSpeedometer-SpeedLabel"; speedLabel = val.GetComponent(); 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) { float num = speedMps * 3.6f; int speedInCurrentUnits = GameSettings.All.General.GetSpeedInCurrentUnits(num); if (speedInCurrentUnits != lastDisplayed) { lastDisplayed = speedInCurrentUnits; ((TMP_Text)speedLabel).text = string.Format(GameSettings.All.General.GetLocalizedSpeedUnitName(), speedInCurrentUnits); } } private void OnUnitChanged() { lastDisplayed = int.MinValue; } private void OnDestroy() { if (unitListenerHooked) { GeneralSettings.SpeedUnitChanged = (Action)Delegate.Remove(GeneralSettings.SpeedUnitChanged, new Action(OnUnitChanged)); unitListenerHooked = false; } } } }