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.14
ShipBeacon.dll
Decompiled a month 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 Unity.Collections; using Unity.Netcode; 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.14.0")] [assembly: AssemblyInformationalVersion("1.0.14")] [assembly: AssemblyProduct("ShipBeacon")] [assembly: AssemblyTitle("ShipBeacon")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.14.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 { internal static class HostModGate { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnMessage; public static Action<ulong> <1>__OnClientConnected; } public const string MessageName = "MrGlim.ShipBeacon"; private const byte OpHostHello = 0; private const byte OpClientSyncRequest = 1; private static bool _registered; private static bool _clientConnectedHooked; private static bool _requestedSync; private static bool _clientHostEnabled; public static bool HostHasMod { get { EnsureRegistered(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return true; } if (singleton.IsServer || singleton.IsHost) { return LocalEnabled(); } return _clientHostEnabled; } } public static bool FeaturesActive => HostHasMod; private static bool LocalEnabled() { if (Plugin.Enabled != null) { return Plugin.Enabled.Value; } return false; } public static void Reset() { _registered = false; _clientConnectedHooked = false; _requestedSync = false; _clientHostEnabled = false; } public static void EnsureRegistered() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { _registered = false; _clientConnectedHooked = false; return; } if (!_registered) { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<0>__OnMessage; if (obj == null) { HandleNamedMessageDelegate val = OnMessage; <>O.<0>__OnMessage = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("MrGlim.ShipBeacon", (HandleNamedMessageDelegate)obj); _registered = true; Plugin.Log.LogInfo((object)"MrGlim.ShipBeacon net handler registered."); } if (singleton.IsServer && !_clientConnectedHooked) { singleton.OnClientConnectedCallback += OnClientConnected; _clientConnectedHooked = true; } if (!singleton.IsServer && singleton.IsConnectedClient && !_requestedSync) { _requestedSync = true; RequestSync(); } } private static void OnClientConnected(ulong clientId) { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsServer && clientId != singleton.LocalClientId) { SendHello(clientId); } } private static void RequestSync() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && !singleton.IsServer) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); byte b = 1; ((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("MrGlim.ShipBeacon", 0uL, val, (NetworkDelivery)2); ((FastBufferWriter)(ref val)).Dispose(); } } private static void SendHello(ulong clientId) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsServer) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); byte b = 0; ((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives)); bool flag = LocalEnabled(); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("MrGlim.ShipBeacon", clientId, val, (NetworkDelivery)2); ((FastBufferWriter)(ref val)).Dispose(); } } private static void OnMessage(ulong sender, FastBufferReader reader) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives)); NetworkManager singleton = NetworkManager.Singleton; switch (b) { case 1: if ((Object)(object)singleton != (Object)null && singleton.IsServer) { SendHello(sender); } break; case 0: { bool clientHostEnabled = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref clientHostEnabled, default(ForPrimitives)); if ((Object)(object)singleton != (Object)null && !singleton.IsServer) { _clientHostEnabled = clientHostEnabled; Plugin.Log.LogInfo((object)("Host hello: enabled=" + clientHostEnabled)); } break; } } } } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] internal static class HostModGateDisconnectPatch { public static void Prefix() { HostModGate.Reset(); Plugin.Log.LogInfo((object)"MrGlim.ShipBeacon gate reset on disconnect."); } } [HarmonyPatch(typeof(StartOfRound), "Start")] internal static class StartOfRoundStartPatch { private static void Postfix() { ShipBeaconHud.EnsureExists(); HostModGate.EnsureRegistered(); Plugin.Log.LogInfo((object)"ShipBeacon HUD ensured after StartOfRound.Start."); } } [HarmonyPatch(typeof(HUDManager), "Start")] internal static class HudManagerStartPatch { private static void Postfix() { ShipBeaconHud.EnsureExists(); HostModGate.EnsureRegistered(); } } [BepInPlugin("com.benhough.lethal.ShipBeacon", "ShipBeacon", "1.0.14")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.benhough.lethal.ShipBeacon"; public const string ModName = "ShipBeacon"; public const string ModVersion = "1.0.14"; 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.06f, "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.14 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.14"; } 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_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: 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 = HostModGate.FeaturesActive; object arg2 = (Object)(object)_canvas != (Object)null; Canvas? canvas = _canvas; log.LogInfo((object)($"[Heartbeat] featuresActive={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}")); } HostModGate.EnsureRegistered(); if (!HostModGate.FeaturesActive) { 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); } } }