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 Monster Alert v1.0.1
MonsterAlert.dll
Decompiled 6 months agousing System; using System.Collections; 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 HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Omniscye")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MonsterAlert")] [assembly: AssemblyTitle("MonsterAlert")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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.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] [Microsoft.CodeAnalysis.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] [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 Omniscye.MonsterDirectionAlert { [BepInPlugin("Omniscye.MonsterDirectionAlert", "MonsterDirectionAlert", "1.0.0")] public class MonsterDirectionAlertPlugin : BaseUnityPlugin { private sealed class DirectionUI { private sealed class UIUpdater : MonoBehaviour { private DirectionUI _owner = null; public void Init(DirectionUI owner) { _owner = owner; } private void LateUpdate() { _owner?.Tick(); } } private readonly GameObject _root; private readonly TextMeshProUGUI _text; private float _alphaVelocity; private float _targetAlpha; public bool Visible { get; private set; } private DirectionUI(GameObject root, TextMeshProUGUI text) { _root = root; _text = text; ((Object)_root).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)_root); UIUpdater uIUpdater = _root.AddComponent<UIUpdater>(); uIUpdater.Init(this); } public static DirectionUI Create() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("MonsterDirectionAlertUI"); Canvas val2 = val.AddComponent<Canvas>(); val2.renderMode = (RenderMode)0; val2.sortingOrder = 32767; CanvasScaler val3 = val.AddComponent<CanvasScaler>(); val3.uiScaleMode = (ScaleMode)1; val3.referenceResolution = new Vector2(1920f, 1080f); val3.matchWidthOrHeight = 1f; val.AddComponent<GraphicRaycaster>(); GameObject val4 = new GameObject("Text"); val4.transform.SetParent(val.transform, false); RectTransform val5 = val4.AddComponent<RectTransform>(); val5.anchorMin = new Vector2(0.5f, 0.9f); val5.anchorMax = new Vector2(0.5f, 0.9f); val5.pivot = new Vector2(0.5f, 0.5f); val5.anchoredPosition = Vector2.zero; val5.sizeDelta = new Vector2(1200f, 140f); TextMeshProUGUI val6 = val4.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val6).alignment = (TextAlignmentOptions)514; ((TMP_Text)val6).fontSize = 60f; ((TMP_Text)val6).fontStyle = (FontStyles)17; ((TMP_Text)val6).enableWordWrapping = false; ((TMP_Text)val6).text = ""; ((Graphic)val6).color = new Color(0.8f, 0.1f, 0.1f, 0f); ((TMP_Text)val6).outlineWidth = 0.3f; ((TMP_Text)val6).outlineColor = Color32.op_Implicit(new Color(0f, 0f, 0f, 1f)); ((TMP_Text)val6).fontSharedMaterial = Object.Instantiate<Material>(((TMP_Text)val6).fontSharedMaterial); ((TMP_Text)val6).fontSharedMaterial.SetFloat(ShaderUtilities.ID_UnderlaySoftness, 0.2f); ((TMP_Text)val6).fontSharedMaterial.SetColor(ShaderUtilities.ID_UnderlayColor, new Color(0f, 0f, 0f, 0.6f)); ((TMP_Text)val6).fontSharedMaterial.SetFloat(ShaderUtilities.ID_UnderlayDilate, 0.2f); ((TMP_Text)val6).fontSharedMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetX, 1.5f); ((TMP_Text)val6).fontSharedMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetY, -1.5f); ((TMP_Text)val6).fontSharedMaterial.SetFloat(ShaderUtilities.ID_GlowPower, 0.5f); ((TMP_Text)val6).fontSharedMaterial.SetFloat(ShaderUtilities.ID_GlowOffset, 0.1f); ((TMP_Text)val6).fontSharedMaterial.SetFloat(ShaderUtilities.ID_GlowOuter, 0.2f); ((TMP_Text)val6).fontSharedMaterial.SetColor(ShaderUtilities.ID_GlowColor, new Color(1f, 0.2f, 0.2f, 1f)); return new DirectionUI(val, val6); } public void Show(string message) { ((TMP_Text)_text).text = message; Visible = true; _targetAlpha = 1f; } public void Hide() { _targetAlpha = 0f; } public void HideImmediate() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) _targetAlpha = 0f; Color color = ((Graphic)_text).color; color.a = 0f; ((Graphic)_text).color = color; ((TMP_Text)_text).text = ""; Visible = false; } public void Destroy() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } } private void Tick() { //IL_0007: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) Color color = ((Graphic)_text).color; float num = (color.a = Mathf.SmoothDamp(color.a, _targetAlpha, ref _alphaVelocity, 0.08f, float.PositiveInfinity, Time.unscaledDeltaTime)); ((Graphic)_text).color = color; if (_targetAlpha <= 0.001f && num <= 0.01f) { Visible = false; ((TMP_Text)_text).text = ""; } else if (num > 0.01f) { Visible = true; } } } public const string PluginGuid = "Omniscye.MonsterDirectionAlert"; public const string PluginName = "MonsterDirectionAlert"; public const string PluginVersion = "1.0.0"; private ConfigEntry<bool> _enabled = null; private ConfigEntry<float> _distanceThreshold = null; private ConfigEntry<float> _checkInterval = null; private ConfigEntry<float> _displayDuration = null; private ConfigEntry<bool> _useCameraForward = null; private float _checkTimer; private float _hideAt; private string _lastBucket = ""; private DirectionUI _ui = null; internal static MonsterDirectionAlertPlugin Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; private set; } private void Awake() { Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; BindConfig(); _ui = DirectionUI.Create(); _ui.HideImmediate(); Patch(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} loaded. Stay sharp."); } private void OnDestroy() { try { _ui?.Destroy(); } catch { } Unpatch(); } private void BindConfig() { _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for the alert."); _distanceThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DistanceThreshold", 18f, "Distance (units) at which a monster triggers the alert."); _checkInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "CheckInterval", 0.2f, "How often (seconds) to scan."); _displayDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "DisplayDuration", 1.25f, "How long (seconds) the popup stays visible per trigger."); _useCameraForward = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "UseCameraForward", true, "Use main camera forward (recommended)."); } internal void Patch() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0026: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(); } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) if (!_enabled.Value) { if (_ui.Visible) { _ui.Hide(); } return; } _checkTimer -= Time.deltaTime; if (_checkTimer > 0f) { if (_ui.Visible && Time.time >= _hideAt) { _ui.Hide(); } return; } _checkTimer = Mathf.Max(0.02f, _checkInterval.Value); Transform forwardReference = GetForwardReference(); if ((Object)(object)forwardReference == (Object)null) { if (_ui.Visible) { _ui.Hide(); } return; } Vector3 position = forwardReference.position; Enemy val = null; float num = float.MaxValue; try { Enemy[] array = Object.FindObjectsOfType<Enemy>(); Enemy[] array2 = array; foreach (Enemy val2 in array2) { if (!((Object)(object)val2 == (Object)null) && ((Component)val2).gameObject.activeInHierarchy && IsEnemyAlive(val2)) { float num2 = Vector3.Distance(position, ((Component)val2).transform.position); if (num2 < num) { val = val2; num = num2; } } } } catch (Exception arg) { Logger.LogDebug((object)$"Enemy scan failed: {arg}"); } if ((Object)(object)val == (Object)null || num > _distanceThreshold.Value) { if (_ui.Visible && Time.time >= _hideAt) { _ui.Hide(); } return; } string directionBucket = GetDirectionBucket(forwardReference, ((Component)val).transform.position); if (!_ui.Visible || !string.Equals(directionBucket, _lastBucket, StringComparison.Ordinal)) { _lastBucket = directionBucket; _ui.Show("Monster to the " + directionBucket + "!"); _hideAt = Time.time + Mathf.Max(0.2f, _displayDuration.Value); } else { _hideAt = Time.time + Mathf.Max(0.2f, _displayDuration.Value); } } private Transform GetForwardReference() { if (_useCameraForward.Value) { Camera main = Camera.main; if ((Object)(object)main != (Object)null) { return ((Component)main).transform; } if ((Object)(object)CameraNoise.Instance != (Object)null) { return ((Component)CameraNoise.Instance).transform; } } try { Type type = AccessTools.TypeByName("GameDirector"); if (type != null) { object obj = AccessTools.Field(type, "instance")?.GetValue(null); if (obj != null && AccessTools.Field(type, "PlayerList")?.GetValue(obj) is IEnumerable enumerable) { foreach (object item in enumerable) { FieldInfo fieldInfo = AccessTools.Field(item.GetType(), "isLocal"); if (fieldInfo != null && (bool)fieldInfo.GetValue(item)) { Component val = (Component)((item is Component) ? item : null); if ((Object)(object)val != (Object)null) { return val.transform; } } } } } } catch (Exception arg) { Logger.LogDebug((object)$"Forward reference (player) lookup failed: {arg}"); } return null; } private static bool IsEnemyAlive(Enemy e) { try { EnemyHealth component = ((Component)e).GetComponent<EnemyHealth>(); if ((Object)(object)component == (Object)null) { return true; } FieldInfo fieldInfo = AccessTools.Field(typeof(EnemyHealth), "dead"); if (fieldInfo != null && (bool)fieldInfo.GetValue(component)) { return false; } FieldInfo fieldInfo2 = AccessTools.Field(typeof(EnemyHealth), "healthCurrent"); if (fieldInfo2 != null && (int)fieldInfo2.GetValue(component) <= 0) { return false; } } catch { } return ((Behaviour)e).enabled && ((Component)e).gameObject.activeInHierarchy; } private static string GetDirectionBucket(Transform forwardRef, Vector3 targetPos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0029: Unknown result type (might be due to invalid IL or missing references) Vector3 val = targetPos - forwardRef.position; Vector3 normalized = ((Vector3)(ref val)).normalized; float num = Vector3.Dot(forwardRef.forward, normalized); float num2 = Vector3.Dot(forwardRef.right, normalized); if (num >= 0.5f) { return "front"; } if (num <= -0.5f) { return "behind"; } return (num2 >= 0f) ? "right" : "left"; } } }