Decompiled source of Observe v1.1.1

Observe.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
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 Observe.Patches;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("headclef")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1+fb16e3c1316d6f39cd4649ac84ad34188bad4448")]
[assembly: AssemblyProduct("Observe")]
[assembly: AssemblyTitle("Observe")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.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 Observe
{
	internal static class MapReveal
	{
		private struct Marker
		{
			public GameObject Go;

			public float Expire;
		}

		private static readonly Dictionary<ValuableObject, Marker> _markers = new Dictionary<ValuableObject, Marker>();

		private static readonly HashSet<ValuableObject> _onMap = new HashSet<ValuableObject>();

		internal static void RefreshOnMapSet()
		{
			_onMap.Clear();
			MapValuable[] array = Object.FindObjectsOfType<MapValuable>();
			foreach (MapValuable val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.target != (Object)null)
				{
					_onMap.Add(val.target);
				}
			}
		}

		internal static void AddOrRefresh(ValuableObject valuable, float duration)
		{
			Map instance = Map.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)valuable == (Object)null)
			{
				return;
			}
			float expire = Time.time + duration;
			if (_markers.TryGetValue(valuable, out var value))
			{
				value.Expire = expire;
				_markers[valuable] = value;
			}
			else if (!_onMap.Contains(valuable))
			{
				Transform overLayerParent = instance.OverLayerParent;
				int childCountBefore = (((Object)(object)overLayerParent != (Object)null) ? overLayerParent.childCount : (-1));
				instance.AddValuable(valuable);
				GameObject val = CaptureNewMarker(overLayerParent, childCountBefore, valuable);
				if (!((Object)(object)val == (Object)null))
				{
					_markers[valuable] = new Marker
					{
						Go = val,
						Expire = expire
					};
					_onMap.Add(valuable);
				}
			}
		}

		private static GameObject? CaptureNewMarker(Transform? parent, int childCountBefore, ValuableObject valuable)
		{
			if ((Object)(object)parent == (Object)null || parent.childCount <= childCountBefore)
			{
				return null;
			}
			MapValuable component = ((Component)parent.GetChild(parent.childCount - 1)).GetComponent<MapValuable>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.target == (Object)(object)valuable)
			{
				return ((Component)component).gameObject;
			}
			int num = parent.childCount - 1;
			while (num >= 0 && num >= childCountBefore)
			{
				MapValuable component2 = ((Component)parent.GetChild(num)).GetComponent<MapValuable>();
				if ((Object)(object)component2 != (Object)null && (Object)(object)component2.target == (Object)(object)valuable)
				{
					return ((Component)component2).gameObject;
				}
				num--;
			}
			if (!((Object)(object)component != (Object)null))
			{
				return null;
			}
			return ((Component)component).gameObject;
		}

		internal static void Tick()
		{
			if (_markers.Count == 0)
			{
				return;
			}
			if ((Object)(object)Map.Instance == (Object)null || !SemiFunc.RunIsLevel())
			{
				_markers.Clear();
				_onMap.Clear();
				return;
			}
			float time = Time.time;
			List<ValuableObject> list = null;
			foreach (KeyValuePair<ValuableObject, Marker> marker in _markers)
			{
				if ((Object)(object)marker.Value.Go == (Object)null || (Object)(object)marker.Key == (Object)null || time >= marker.Value.Expire)
				{
					(list ?? (list = new List<ValuableObject>())).Add(marker.Key);
					if ((Object)(object)marker.Value.Go != (Object)null)
					{
						Object.Destroy((Object)(object)marker.Value.Go);
					}
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (ValuableObject item in list)
			{
				_markers.Remove(item);
				_onMap.Remove(item);
			}
		}

		internal static void ClearAll()
		{
			foreach (KeyValuePair<ValuableObject, Marker> marker in _markers)
			{
				if ((Object)(object)marker.Value.Go != (Object)null)
				{
					Object.Destroy((Object)(object)marker.Value.Go);
				}
			}
			_markers.Clear();
			_onMap.Clear();
		}
	}
	[BepInPlugin("headclef.Observe", "Observe", "1.1.1")]
	public class Observe : BaseUnityPlugin
	{
		private const string PluginGuid = "headclef.Observe";

		private const string PluginName = "Observe";

		private const string PluginVersion = "1.1.1";

		internal static ConfigEntry<KeyboardShortcut> ObserveKey;

		internal static ConfigEntry<float> Radius;

		internal static ConfigEntry<float> Cooldown;

		internal static ConfigEntry<bool> ShowCooldownBar;

		internal static ConfigEntry<bool> ShowOnMap;

		internal static ConfigEntry<float> MapMarkerDuration;

		private GUIStyle? _hudStyle;

		internal static Observe Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_004f: Expected O, but got Unknown
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			BindConfiguration();
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		private void OnDestroy()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void BindConfiguration()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			ObserveKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Observe", "Observe Key", new KeyboardShortcut((KeyCode)102, Array.Empty<KeyCode>()), "Key to press to reveal nearby valuables.");
			Radius = ((BaseUnityPlugin)this).Config.Bind<float>("Observe", "Radius", 10f, new ConfigDescription("Radius in meters around you within which valuables are revealed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			Cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Observe", "Cooldown", 10f, new ConfigDescription("Cooldown in seconds between uses.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			ShowCooldownBar = ((BaseUnityPlugin)this).Config.Bind<bool>("Observe", "Show Cooldown Bar", true, "Show an on-screen bar and countdown while Observe is on cooldown.");
			ShowOnMap = ((BaseUnityPlugin)this).Config.Bind<bool>("Observe", "Show On Map", true, "Also mark revealed valuables on the Map tool when you scan (in addition to the through-wall world marker). Client-side only — just you see them.");
			MapMarkerDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Observe", "Map Marker Duration", 10f, new ConfigDescription("How long (seconds) revealed valuables stay marked on the map after a scan. Independent of the cooldown. Valuables you genuinely discover stay on the map as usual — this only governs the temporary markers Observe adds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
		}

		private void OnGUI()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			if (!ShowCooldownBar.Value || !SemiFunc.RunIsLevel())
			{
				return;
			}
			float num = ObservePatch.CooldownRemaining();
			if (!(num <= 0f))
			{
				float num2 = Mathf.Max(Cooldown.Value, 0.0001f);
				float num3 = Mathf.Clamp01(num / num2);
				float num4 = ((float)Screen.width - 280f) / 2f;
				float num5 = (float)Screen.height - 200f;
				Color color = GUI.color;
				GUI.color = new Color(0f, 0f, 0f, 0.6f);
				GUI.DrawTexture(new Rect(num4 - 2f, num5 - 2f, 284f, 26f), (Texture)(object)Texture2D.whiteTexture);
				GUI.color = new Color(0.12f, 0.12f, 0.12f, 0.9f);
				GUI.DrawTexture(new Rect(num4, num5, 280f, 22f), (Texture)(object)Texture2D.whiteTexture);
				GUI.color = new Color(1f, 0.82f, 0.1f, 0.95f);
				GUI.DrawTexture(new Rect(num4, num5, 280f * num3, 22f), (Texture)(object)Texture2D.whiteTexture);
				if (_hudStyle == null)
				{
					_hudStyle = new GUIStyle(GUI.skin.label)
					{
						alignment = (TextAnchor)4,
						fontStyle = (FontStyle)1,
						fontSize = 14
					};
				}
				string text = $"Observe  {num:0.0}s";
				GUI.color = new Color(0f, 0f, 0f, 0.85f);
				GUI.Label(new Rect(num4 + 1f, num5 + 1f, 280f, 22f), text, _hudStyle);
				GUI.color = Color.white;
				GUI.Label(new Rect(num4, num5, 280f, 22f), text, _hudStyle);
				GUI.color = color;
			}
		}
	}
}
namespace Observe.Patches
{
	[HarmonyPatch]
	internal static class ObservePatch
	{
		private static float _lastObserveTime = -999f;

		private static Coroutine? _revealRoutine;

		private const int RevealsPerFrame = 4;

		private static bool _prewarmStarted;

		internal static float CooldownRemaining()
		{
			float num = Observe.Cooldown.Value - (Time.time - _lastObserveTime);
			return Mathf.Max(num, 0f);
		}

		[HarmonyPatch(typeof(PlayerController), "Update")]
		[HarmonyPostfix]
		private static void PlayerController_Update_Postfix(PlayerController __instance)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance != (Object)(object)PlayerController.instance)
				{
					return;
				}
				MapReveal.Tick();
				TryLazyPrewarm();
				if (!ObserveKeyPressed() || !SemiFunc.RunIsLevel())
				{
					return;
				}
				float value = Observe.Cooldown.Value;
				if (Time.time - _lastObserveTime < value)
				{
					Observe.Logger.LogDebug((object)$"Observe on cooldown ({value - (Time.time - _lastObserveTime):F1}s remaining)");
					return;
				}
				_lastObserveTime = Time.time;
				if (_revealRoutine != null)
				{
					((MonoBehaviour)Observe.Instance).StopCoroutine(_revealRoutine);
				}
				_revealRoutine = ((MonoBehaviour)Observe.Instance).StartCoroutine(RevealNearbyValuables(((Component)__instance).transform.position));
			}
			catch (Exception ex)
			{
				Observe.Logger.LogError((object)("Observe exception: " + ex.Message));
			}
		}

		private static IEnumerator RevealNearbyValuables(Vector3 origin)
		{
			//IL_0007: 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)
			ValuableDiscover discover = ValuableDiscover.instance;
			if ((Object)(object)discover == (Object)null)
			{
				Observe.Logger.LogWarning((object)"ValuableDiscover.instance is null — cannot reveal.");
				_revealRoutine = null;
				yield break;
			}
			float value = Observe.Radius.Value;
			float sqrRadius = value * value;
			int revealed = 0;
			int thisFrame = 0;
			bool showOnMap = Observe.ShowOnMap.Value;
			float mapDuration = Observe.MapMarkerDuration.Value;
			if (showOnMap)
			{
				MapReveal.RefreshOnMapSet();
			}
			ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>();
			ValuableObject[] array2 = array;
			foreach (ValuableObject val in array2)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val.physGrabObject == (Object)null)
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - origin;
				if (!(((Vector3)(ref val2)).sqrMagnitude > sqrRadius))
				{
					discover.New(val.physGrabObject, (State)0, (ValuableDiscoverCustom)null);
					if (showOnMap)
					{
						MapReveal.AddOrRefresh(val, mapDuration);
					}
					revealed++;
					int num = thisFrame + 1;
					thisFrame = num;
					if (num >= 4)
					{
						thisFrame = 0;
						yield return null;
					}
				}
			}
			_revealRoutine = null;
		}

		private static bool ObserveKeyPressed()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Observe.ObserveKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				if (!Input.GetKey(modifier))
				{
					return false;
				}
			}
			return true;
		}

		private static void TryLazyPrewarm()
		{
			if (!_prewarmStarted && SemiFunc.RunIsLevel())
			{
				_prewarmStarted = true;
				((MonoBehaviour)Observe.Instance).StartCoroutine(PrewarmDelayed());
			}
		}

		private static IEnumerator PrewarmDelayed()
		{
			yield return (object)new WaitForSeconds(2f);
			ValuableDiscover instance = ValuableDiscover.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.graphicPrefab == (Object)null)
			{
				yield break;
			}
			try
			{
				GameObject val = Object.Instantiate<GameObject>(instance.graphicPrefab, ((Component)instance).transform);
				val.SetActive(false);
				Object.Destroy((Object)(object)val);
				Observe.Logger.LogDebug((object)"Observe pre-warmed the discovery graphic.");
			}
			catch (Exception ex)
			{
				Observe.Logger.LogDebug((object)("Observe pre-warm skipped: " + ex.Message));
			}
		}
	}
}