Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ShipBeacon v1.0.12
ShipBeacon.dll
Decompiled 3 hours agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ShipBeacon")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyInformationalVersion("1.0.6")] [assembly: AssemblyProduct("ShipBeacon")] [assembly: AssemblyTitle("ShipBeacon")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.6.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 ShipBeacon { [HarmonyPatch(typeof(StartOfRound), "Start")] internal static class StartOfRoundStartPatch { private static void Postfix() { ShipBeaconHud.EnsureExists(); Plugin.Log.LogInfo((object)"ShipBeacon HUD ensured after StartOfRound.Start."); } } [HarmonyPatch(typeof(HUDManager), "Start")] internal static class HudManagerStartPatch { private static void Postfix() { ShipBeaconHud.EnsureExists(); } } [BepInPlugin("com.benhough.lethal.ShipBeacon", "ShipBeacon", "1.0.12")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.benhough.lethal.ShipBeacon"; public const string ModName = "ShipBeacon"; public const string ModVersion = "1.0.12"; private readonly Harmony _harmony = new Harmony("com.benhough.lethal.ShipBeacon"); internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ConfigEntry<bool> Enabled { get; private set; } internal static ConfigEntry<bool> ShowDistance { get; private set; } internal static ConfigEntry<float> HudScale { get; private set; } internal static ConfigEntry<float> VerticalOffset { get; private set; } internal static ConfigEntry<bool> MatchClockStyle { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Show the outdoor ship beacon HUD."); ShowDistance = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowDistance", true, "Show distance to the ship in meters."); HudScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HudScale", 1f, "Scale of the beacon HUD text."); VerticalOffset = ((BaseUnityPlugin)this).Config.Bind<float>("General", "VerticalOffset", 0.1f, "Beacon text vertical position (0 = bottom, 1 = top). Default sits near the bottom of the screen."); MatchClockStyle = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "MatchClockStyle", true, "Use the orange clock HUD color/font when available."); _harmony.PatchAll(typeof(Plugin).Assembly); ShipBeaconHud.EnsureExists(); Log.LogInfo((object)"ShipBeacon v1.0.12 loaded (bottom orange HUD style)."); } } internal static class PluginInfo { public const string PLUGIN_GUID = "com.benhough.lethal.ShipBeacon"; public const string PLUGIN_NAME = "ShipBeacon"; public const string PLUGIN_VERSION = "1.0.12"; } internal sealed class ShipBeaconHud : MonoBehaviour { private static ShipBeaconHud? _instance; private Canvas? _canvas; private TextMeshProUGUI? _label; private RectTransform? _labelRt; private float _nextDebugLog; private string _lastHideReason = ""; private bool _loggedVisible; private float _nextHeartbeat; private bool _fontAssigned; private string _lastBeaconDetail = ""; private static readonly Color ClockOrange = new Color(0.855f, 0.4f, 0.185f, 1f); internal static void EnsureExists() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("ShipBeaconHUD"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<ShipBeaconHud>(); } } private void Awake() { _instance = this; BuildUi(); } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void BuildUi() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_0122: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_canvas != (Object)null)) { _canvas = ((Component)this).gameObject.AddComponent<Canvas>(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 5000; CanvasScaler obj = ((Component)this).gameObject.AddComponent<CanvasScaler>(); obj.uiScaleMode = (ScaleMode)1; obj.referenceResolution = new Vector2(1920f, 1080f); ((Component)this).gameObject.AddComponent<GraphicRaycaster>(); GameObject val = new GameObject("ShipBeaconLabel", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(((Component)this).transform, false); _labelRt = val.GetComponent<RectTransform>(); _labelRt.anchorMin = new Vector2(0.5f, Plugin.VerticalOffset.Value); _labelRt.anchorMax = new Vector2(0.5f, Plugin.VerticalOffset.Value); _labelRt.pivot = new Vector2(0.5f, 0.5f); _labelRt.sizeDelta = new Vector2(980f, 56f); _labelRt.anchoredPosition = Vector2.zero; _label = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_label).alignment = (TextAlignmentOptions)514; ((TMP_Text)_label).fontStyle = (FontStyles)1; ((Graphic)_label).color = ClockOrange; ((TMP_Text)_label).enableWordWrapping = false; ((Graphic)_label).raycastTarget = false; ((TMP_Text)_label).overflowMode = (TextOverflowModes)0; ((TMP_Text)_label).text = ""; ((TMP_Text)_label).fontSharedMaterial = null; TryAssignFont(); ApplyClockStyle(); ApplyScale(); ((Behaviour)_canvas).enabled = false; Plugin.Log.LogInfo((object)"ShipBeacon canvas HUD built."); } } private void TryAssignFont() { if ((Object)(object)_label == (Object)null || _fontAssigned) { return; } try { TMP_FontAsset val = null; HUDManager instance = HUDManager.Instance; if ((Object)(object)instance != (Object)null) { if ((Object)(object)instance.clockNumber != (Object)null && (Object)(object)((TMP_Text)instance.clockNumber).font != (Object)null) { val = ((TMP_Text)instance.clockNumber).font; } if ((Object)(object)val == (Object)null && instance.controlTipLines != null) { TextMeshProUGUI[] controlTipLines = instance.controlTipLines; foreach (TextMeshProUGUI val2 in controlTipLines) { if ((Object)(object)val2 != (Object)null && (Object)(object)((TMP_Text)val2).font != (Object)null) { val = ((TMP_Text)val2).font; break; } } } if ((Object)(object)val == (Object)null && (Object)(object)instance.weightCounter != (Object)null) { val = ((TMP_Text)instance.weightCounter).font; } } if ((Object)(object)val == (Object)null && (Object)(object)TMP_Settings.defaultFontAsset != (Object)null) { val = TMP_Settings.defaultFontAsset; } if ((Object)(object)val != (Object)null) { ((TMP_Text)_label).font = val; _fontAssigned = true; Plugin.Log.LogInfo((object)("ShipBeacon TMP font assigned: " + ((Object)val).name)); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("ShipBeacon font assign failed: " + ex.Message)); } } private void ApplyScale() { if ((Object)(object)_label == (Object)null) { return; } float num = 26f; try { TextMeshProUGUI val = HUDManager.Instance?.clockNumber; if ((Object)(object)val != (Object)null && ((TMP_Text)val).fontSize > 1f) { num = ((TMP_Text)val).fontSize * 0.92f; } } catch { } ((TMP_Text)_label).fontSize = num * Plugin.HudScale.Value; } private void ApplyClockStyle() { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_label == (Object)null) { return; } try { ((Graphic)_label).color = ClockOrange; ((TMP_Text)_label).fontStyle = (FontStyles)1; if (Plugin.MatchClockStyle != null && Plugin.MatchClockStyle.Value) { HUDManager instance = HUDManager.Instance; TextMeshProUGUI val = (((Object)(object)instance != (Object)null) ? instance.clockNumber : null); if (!((Object)(object)val == (Object)null) && (Object)(object)((TMP_Text)val).font != (Object)null) { ((TMP_Text)_label).font = ((TMP_Text)val).font; _fontAssigned = true; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("ApplyClockStyle: " + ex.Message)); try { ((Graphic)_label).color = ClockOrange; } catch { } } } private void LateUpdate() { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_canvas == (Object)null || (Object)(object)_label == (Object)null || (Object)(object)_labelRt == (Object)null) { BuildUi(); } TryAssignFont(); ApplyClockStyle(); ApplyScale(); if (Time.unscaledTime >= _nextHeartbeat) { _nextHeartbeat = Time.unscaledTime + 10f; StartOfRound instance = StartOfRound.Instance; PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; ManualLogSource log = Plugin.Log; object arg = Plugin.Enabled.Value; object arg2 = (Object)(object)_canvas != (Object)null; Canvas? canvas = _canvas; log.LogInfo((object)($"[Heartbeat] enabled={arg}, canvas={arg2}, canvasOn={((canvas != null) ? new bool?(((Behaviour)canvas).enabled) : ((bool?)null))}, " + $"font={_fontAssigned}, hide='{_lastHideReason}', detail='{_lastBeaconDetail}', " + $"inShipPhase={instance?.inShipPhase}, playerNull={(Object)(object)val == (Object)null}, dead={val?.isPlayerDead}, " + $"insideFactory={val?.isInsideFactory}, inShip={val?.isInHangarShipRoom}")); } if (Plugin.Enabled == null || !Plugin.Enabled.Value) { SetVisible(visible: false); _lastHideReason = "disabled"; return; } if ((Object)(object)_labelRt != (Object)null) { float num = Mathf.Clamp01(Plugin.VerticalOffset.Value); _labelRt.anchorMin = new Vector2(0.5f, num); _labelRt.anchorMax = new Vector2(0.5f, num); } ApplyScale(); if (!TryGetBeacon(out float signedAngleDeg, out float distance, out string hideReason)) { SetVisible(visible: false); MaybeLogHidden(hideReason); _loggedVisible = false; return; } try { ((TMP_Text)_label).text = FormatBeacon(signedAngleDeg, distance); SetVisible(visible: true); _lastHideReason = ""; _lastBeaconDetail = $"{distance:0}m bearing={signedAngleDeg:0}"; if (!_loggedVisible) { _loggedVisible = true; Plugin.Log.LogInfo((object)$"ShipBeacon visible: {distance:0}m, bearing {signedAngleDeg:0} deg."); } } catch (Exception ex) { SetVisible(visible: false); MaybeLogHidden("label update: " + ex.Message); _loggedVisible = false; } } private void SetVisible(bool visible) { if ((Object)(object)_canvas != (Object)null && ((Behaviour)_canvas).enabled != visible) { ((Behaviour)_canvas).enabled = visible; } if ((Object)(object)_label != (Object)null && ((Component)_label).gameObject.activeSelf != visible) { ((Component)_label).gameObject.SetActive(visible); } } private void MaybeLogHidden(string reason) { if (reason == null) { reason = ""; } bool num = reason != _lastHideReason; _lastHideReason = reason; if (num || !(Time.unscaledTime < _nextDebugLog)) { _nextDebugLog = Time.unscaledTime + 8f; if (!string.IsNullOrEmpty(reason)) { Plugin.Log.LogInfo((object)("ShipBeacon hidden: " + reason)); } } } private static bool TryGetBeacon(out float signedAngleDeg, out float distance, out string hideReason) { //IL_00ec: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) signedAngleDeg = 0f; distance = 0f; hideReason = ""; try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { hideReason = "StartOfRound missing"; return false; } if (instance.inShipPhase) { hideReason = "inShipPhase (orbit)"; return false; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || val.isPlayerDead) { hideReason = "no local player / dead"; return false; } if (val.isInsideFactory) { hideReason = "inside factory"; return false; } if (val.isInHangarShipRoom) { hideReason = "inside ship"; return false; } Transform val2 = ResolveShipTransform(instance); if ((Object)(object)val2 == (Object)null) { hideReason = "no ship transform"; return false; } Transform val3 = (((Object)(object)val.gameplayCamera != (Object)null) ? ((Component)val.gameplayCamera).transform : ((Component)val).transform); Vector3 val4 = val2.position - val3.position; val4.y = 0f; distance = ((Vector3)(ref val4)).magnitude; if (distance < 0.5f) { hideReason = $"too close ({distance:0.0}m)"; return false; } Vector3 forward = val3.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { hideReason = "bad camera forward"; return false; } signedAngleDeg = Vector3.SignedAngle(((Vector3)(ref forward)).normalized, ((Vector3)(ref val4)).normalized, Vector3.up); return true; } catch (Exception ex) { hideReason = ex.Message; return false; } } private static Transform? ResolveShipTransform(StartOfRound start) { try { GameObject val = GameObject.Find("/Environment/HangarShip") ?? GameObject.Find("Environment/HangarShip") ?? GameObject.Find("HangarShip"); if ((Object)(object)val != (Object)null) { return val.transform; } } catch { } if ((Object)(object)start.shipDoorNode != (Object)null) { return start.shipDoorNode; } if ((Object)(object)start.middleOfShipNode != (Object)null) { return start.middleOfShipNode; } if ((Object)(object)start.elevatorTransform != (Object)null) { return start.elevatorTransform; } if ((Object)(object)start.shipBounds != (Object)null) { return ((Component)start.shipBounds).transform; } if ((Object)(object)start.shipLandingPosition != (Object)null) { return start.shipLandingPosition; } try { HangarShipDoor val2 = Object.FindObjectOfType<HangarShipDoor>(); if ((Object)(object)val2 != (Object)null) { return ((Component)val2).transform; } } catch { } return null; } private static string FormatBeacon(float signedAngleDeg, float distance) { float num = Mathf.Abs(signedAngleDeg); string text = (Plugin.ShowDistance.Value ? $"SHIP {distance:0}m" : "SHIP"); if (num <= 25f) { return "^ " + text + " ^"; } if (num >= 155f) { return "v " + text + " v"; } int count = 1; if (num > 45f) { count = 2; } if (num > 70f) { count = 3; } if (num > 100f) { count = 4; } if (signedAngleDeg < 0f) { return new string('<', count) + " " + text; } return text + " " + new string('>', count); } } }