using 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";
}
}
}