Decompiled source of DeathHelper v0.2.0

DeathHelper.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace DeathHelper;

[BepInPlugin("com.burks.deathhelper", "Death Helper", "0.2.0")]
public class DeathHelperPlugin : BaseUnityPlugin
{
	public const string GUID = "com.burks.deathhelper";

	public const string NAME = "Death Helper";

	public const string VERSION = "0.2.0";

	public static ConfigEntry<bool> ShowArrow;

	public static ConfigEntry<bool> RemoveEmpty;

	public static ConfigEntry<float> ArrowMaxDistance;

	public static ConfigEntry<float> CheckRange;

	public static ConfigEntry<float> TombRadius;

	public static ConfigEntry<float> ConfirmSeconds;

	public static ConfigEntry<KeyCode> ToggleKey;

	public static ConfigEntry<KeyCode> TeleportKey;

	public static ConfigEntry<bool> TeleportOn;

	public static ConfigEntry<int> TeleportCost;

	public static DeathHelperPlugin Instance;

	private bool _cmd;

	private bool _btnFailed;

	private GameObject _button;

	private static readonly FieldRef<Minimap, List<PinData>> Pins = AccessTools.FieldRefAccess<Minimap, List<PinData>>("m_pins");

	private float _next;

	private readonly Dictionary<PinData, float> _emptySince = new Dictionary<PinData, float>();

	private readonly List<PinData> _deaths = new List<PinData>();

	private PinData _target;

	private Texture2D _arrow;

	private GUIStyle _style;

	private void Awake()
	{
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Invalid comparison between Unknown and I4
		ShowArrow = ((BaseUnityPlugin)this).Config.Bind<bool>("Arrow", "ShowArrow", true, "Show an arrow and distance to your nearest death marker at the top of the screen.");
		ArrowMaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Arrow", "MaxDistance", 0f, "Hide the arrow when the marker is further than this many metres. 0 = always show.");
		ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Arrow", "ToggleKey", (KeyCode)0, "Optional key to switch the arrow on and off.");
		RemoveEmpty = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "RemoveMarkersWithoutTombstone", true, "Remove a death marker from the map once you can see there is no tombstone at it.");
		CheckRange = ((BaseUnityPlugin)this).Config.Bind<float>("Cleanup", "CheckRange", 30f, "A marker is only checked while it is this close to you, so the area is certain to be loaded.");
		TombRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Cleanup", "TombstoneRadius", 15f, "A tombstone within this many metres of the marker counts as belonging to it (tombstones float and slide a little).");
		ConfirmSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Cleanup", "ConfirmSeconds", 5f, "The spot must be seen empty for this long before the marker is removed.");
		TeleportOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Teleport", "Enabled", true, "Allow paying to teleport to your nearest death marker (Esc menu button, the 'grave' console command, or the key below).");
		TeleportCost = ((BaseUnityPlugin)this).Config.Bind<int>("Teleport", "Cost", 100, "Price in value: coins count 1 each, other valuables count what the trader pays for them (amber 5, amber pearl 10, ruby 20, silver necklace 30).");
		TeleportKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Teleport", "Key", (KeyCode)0, "Optional hotkey.");
		Instance = this;
		if ((int)SystemInfo.graphicsDeviceType == 4)
		{
			((Behaviour)this).enabled = false;
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Death Helper 0.2.0 loaded.");
		}
	}

	private void Update()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		if ((int)ToggleKey.Value != 0 && Input.GetKeyDown(ToggleKey.Value) && !Console.IsVisible() && ((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()))
		{
			ShowArrow.Value = !ShowArrow.Value;
		}
		if ((Object)(object)Player.m_localPlayer != (Object)null)
		{
			if (!_cmd)
			{
				_cmd = true;
				try
				{
					new ConsoleCommand("grave", "pay to teleport to your nearest death marker", (ConsoleEvent)delegate(ConsoleEventArgs a)
					{
						Teleport(a.Context);
					}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not add the 'grave' command: " + ex.Message));
				}
			}
			if ((int)TeleportKey.Value != 0 && Input.GetKeyDown(TeleportKey.Value) && !Console.IsVisible() && ((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()))
			{
				Teleport(null);
			}
			try
			{
				EnsureButton();
			}
			catch (Exception ex2)
			{
				if (!_btnFailed)
				{
					_btnFailed = true;
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not add the menu button: " + ex2.Message));
				}
			}
		}
		if (Time.unscaledTime < _next)
		{
			return;
		}
		_next = Time.unscaledTime + 1f;
		try
		{
			Check();
		}
		catch (Exception ex3)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Check failed: " + ex3.Message));
			_next = Time.unscaledTime + 30f;
		}
	}

	private void Check()
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Invalid comparison between Unknown and I4
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_033b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0340: Unknown result type (might be due to invalid IL or missing references)
		//IL_0341: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: 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_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
		_target = null;
		_deaths.Clear();
		if ((Object)(object)Minimap.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)Game.instance == (Object)null)
		{
			_emptySince.Clear();
			return;
		}
		List<PinData> list = Pins.Invoke(Minimap.instance);
		if (list == null)
		{
			return;
		}
		foreach (PinData item in list)
		{
			if (item != null && (int)item.m_type == 4)
			{
				_deaths.Add(item);
			}
		}
		Player localPlayer = Player.m_localPlayer;
		Vector3 val = (((Object)(object)localPlayer != (Object)null) ? ((Component)localPlayer).transform.position : ZNet.instance.GetReferencePosition());
		if (RemoveEmpty.Value && !Game.instance.IsShuttingDown())
		{
			float num = Mathf.Clamp(CheckRange.Value, 10f, 60f);
			float num2 = Mathf.Clamp(TombRadius.Value, 3f, 40f);
			TombStone[] array = null;
			List<PinData> list2 = null;
			foreach (PinData death in _deaths)
			{
				Vector3 val2 = death.m_pos - val;
				val2.y = 0f;
				if (((Vector3)(ref val2)).magnitude > num || !ZNetScene.instance.IsAreaReady(death.m_pos))
				{
					_emptySince.Remove(death);
					continue;
				}
				if (array == null)
				{
					array = Object.FindObjectsByType<TombStone>((FindObjectsSortMode)0);
				}
				bool flag = false;
				TombStone[] array2 = array;
				foreach (TombStone val3 in array2)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						Vector3 val4 = ((Component)val3).transform.position - death.m_pos;
						val4.y = 0f;
						if (((Vector3)(ref val4)).magnitude <= num2)
						{
							flag = true;
							break;
						}
					}
				}
				float value;
				if (flag)
				{
					_emptySince.Remove(death);
				}
				else if (!_emptySince.TryGetValue(death, out value))
				{
					_emptySince[death] = Time.unscaledTime;
				}
				else if (Time.unscaledTime - value >= Mathf.Max(1f, ConfirmSeconds.Value))
				{
					if (list2 == null)
					{
						list2 = new List<PinData>();
					}
					list2.Add(death);
				}
			}
			if (list2 != null)
			{
				foreach (PinData item2 in list2)
				{
					Minimap.instance.RemovePin(item2);
					_emptySince.Remove(item2);
					_deaths.Remove(item2);
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Removed a death marker with no tombstone at " + ((Vector3)(ref item2.m_pos)).ToString("0") + "."));
				}
			}
		}
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		float num3 = float.MaxValue;
		foreach (PinData death2 in _deaths)
		{
			Vector3 val5 = death2.m_pos - val;
			val5.y = 0f;
			if (((Vector3)(ref val5)).sqrMagnitude < num3)
			{
				num3 = ((Vector3)(ref val5)).sqrMagnitude;
				_target = death2;
			}
		}
	}

	private void EnsureButton()
	{
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Expected O, but got Unknown
		if (_btnFailed || (Object)(object)Menu.instance == (Object)null)
		{
			return;
		}
		if ((Object)(object)_button == (Object)null)
		{
			Button settingsButton = Menu.instance.m_settingsButton;
			if ((Object)(object)settingsButton == (Object)null)
			{
				throw new Exception("no Settings button to copy");
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)settingsButton).gameObject, ((Component)settingsButton).transform.parent);
			((Object)val).name = "GraveTeleportButton";
			val.transform.SetSiblingIndex(((Component)settingsButton).transform.GetSiblingIndex() + 1);
			Button component = val.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				try
				{
					Menu.instance.Hide();
				}
				catch (Exception)
				{
				}
				Teleport(null);
			});
			_button = val;
		}
		bool flag = TeleportOn.Value && _target != null;
		if (_button.activeSelf != flag)
		{
			_button.SetActive(flag);
		}
		if (!flag || !Menu.IsVisible())
		{
			return;
		}
		string text = "Go to grave (" + Mathf.Max(0, TeleportCost.Value) + ")";
		TMP_Text[] componentsInChildren = _button.GetComponentsInChildren<TMP_Text>(true);
		foreach (TMP_Text val2 in componentsInChildren)
		{
			if (val2.text != text)
			{
				val2.text = text;
			}
		}
	}

	private static void Tell(Terminal ctx, string text)
	{
		if ((Object)(object)ctx != (Object)null)
		{
			ctx.AddString(text);
		}
		if ((Object)(object)MessageHud.instance != (Object)null)
		{
			MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
		}
	}

	private static bool Valuable(ItemData i)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Invalid comparison between Unknown and I4
		if (i != null && i.m_shared != null && i.m_shared.m_value > 0 && !i.m_equipped)
		{
			return (int)i.m_shared.m_itemType == 1;
		}
		return false;
	}

	private void Teleport(Terminal ctx)
	{
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		if (!TeleportOn.Value)
		{
			Tell(ctx, "Grave teleport is switched off.");
			return;
		}
		if (_target == null)
		{
			Tell(ctx, "You have no death marker.");
			return;
		}
		if (((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || ((Character)localPlayer).InBed() || ((Character)localPlayer).IsAttached())
		{
			Tell(ctx, "You can't do that right now.");
			return;
		}
		if (localPlayer.IsTargeted() || localPlayer.IsSensed())
		{
			Tell(ctx, "Not while enemies are aware of you.");
			return;
		}
		if (!((Humanoid)localPlayer).IsTeleportable((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)35)))
		{
			Tell(ctx, "You are carrying something that can't be teleported.");
			return;
		}
		int num = Mathf.Max(0, TeleportCost.Value);
		Inventory inventory = ((Humanoid)localPlayer).GetInventory();
		List<ItemData> list = new List<ItemData>();
		int num2 = 0;
		foreach (ItemData allItem in inventory.GetAllItems())
		{
			if (Valuable(allItem))
			{
				list.Add(allItem);
				num2 += allItem.m_shared.m_value * allItem.m_stack;
			}
		}
		if (num2 < num)
		{
			Tell(ctx, "You need " + num + " in coins or valuables (you carry " + num2 + ").");
			return;
		}
		Vector3 val = _target.m_pos + Vector3.up * 0.5f;
		if (!((Character)localPlayer).TeleportTo(val, ((Component)localPlayer).transform.rotation, true))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"The game refused the teleport; nothing was charged.");
			Tell(ctx, "The teleport failed.");
			return;
		}
		list.Sort((ItemData a, ItemData b) => a.m_shared.m_value.CompareTo(b.m_shared.m_value));
		int num3 = num;
		foreach (ItemData item in list)
		{
			if (num3 <= 0)
			{
				break;
			}
			int value = item.m_shared.m_value;
			int num4 = Mathf.Min(item.m_stack, (num3 + value - 1) / value);
			if (num4 > 0)
			{
				inventory.RemoveItem(item, num4);
				num3 -= num4 * value;
			}
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Teleported to the death marker at " + ((Vector3)(ref _target.m_pos)).ToString("0") + " for " + (num - num3) + " value."));
	}

	private void OnGUI()
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Invalid comparison between Unknown and I4
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Expected O, but got Unknown
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Unknown result type (might be due to invalid IL or missing references)
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
		if (!ShowArrow.Value || _target == null || (int)Event.current.type != 7)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		Camera main = Camera.main;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)main == (Object)null || ((Character)localPlayer).IsDead() || Hud.IsUserHidden() || Minimap.IsOpen() || Menu.IsVisible() || InventoryGui.IsVisible())
		{
			return;
		}
		Vector3 val = _target.m_pos - ((Component)localPlayer).transform.position;
		val.y = 0f;
		float magnitude = ((Vector3)(ref val)).magnitude;
		float value = ArrowMaxDistance.Value;
		if (!(value > 0f) || !(magnitude > value))
		{
			Vector3 forward = ((Component)main).transform.forward;
			forward.y = 0f;
			float num = ((magnitude > 1f && ((Vector3)(ref forward)).sqrMagnitude > 0.0001f) ? Vector3.SignedAngle(forward, val, Vector3.up) : 0f);
			if ((Object)(object)_arrow == (Object)null)
			{
				_arrow = MakeArrow();
			}
			if (_style == null)
			{
				_style = new GUIStyle(GUI.skin.label);
				_style.alignment = (TextAnchor)3;
				_style.fontStyle = (FontStyle)1;
			}
			float num2 = Mathf.Max(1f, (float)Screen.height / 1080f);
			_style.fontSize = Mathf.RoundToInt(18f * num2);
			float num3 = 34f * num2;
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor((float)Screen.width / 2f - 70f * num2, 70f * num2, num3, num3);
			Matrix4x4 matrix = GUI.matrix;
			GUIUtility.RotateAroundPivot(num, ((Rect)(ref val2)).center);
			GUI.DrawTexture(val2, (Texture)(object)_arrow);
			GUI.matrix = matrix;
			string text = "Grave  " + ((magnitude >= 1000f) ? ((magnitude / 1000f).ToString("0.0") + " km") : (Mathf.RoundToInt(magnitude) + " m"));
			Rect val3 = default(Rect);
			((Rect)(ref val3))..ctor(((Rect)(ref val2)).xMax + 8f * num2, ((Rect)(ref val2)).y, 240f * num2, num3);
			Color color = GUI.color;
			GUI.color = new Color(0f, 0f, 0f, 0.8f);
			GUI.Label(new Rect(((Rect)(ref val3)).x + 1.5f, ((Rect)(ref val3)).y + 1.5f, ((Rect)(ref val3)).width, ((Rect)(ref val3)).height), text, _style);
			GUI.color = new Color(1f, 0.86f, 0.55f, 1f);
			GUI.Label(val3, text, _style);
			GUI.color = color;
		}
	}

	private static Texture2D MakeArrow()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		Color val2 = default(Color);
		((Color)(ref val2))..ctor(1f, 0.86f, 0.55f, 1f);
		Color val3 = default(Color);
		((Color)(ref val3))..ctor(0f, 0f, 0f, 0.85f);
		Color val4 = default(Color);
		((Color)(ref val4))..ctor(0f, 0f, 0f, 0f);
		for (int i = 0; i < 64; i++)
		{
			float num;
			float num3;
			int num4;
			int num5;
			bool flag;
			bool flag2;
			for (int j = 0; j < 64; flag = (byte)num5 != 0, flag2 = num4 != 0 && Mathf.Abs(num) < num3, val.SetPixel(j, i, flag ? val2 : (flag2 ? val3 : val4)), j++)
			{
				num = ((float)j + 0.5f) / 64f - 0.5f;
				float num2 = ((float)i + 0.5f) / 64f;
				num3 = 0.36f * Mathf.InverseLerp(0.94f, 0.12f, num2);
				if (num2 > 0.12f)
				{
					num4 = ((num2 < 0.94f) ? 1 : 0);
					if (num4 != 0 && Mathf.Abs(num) < num3 - 0.045f)
					{
						num5 = ((num2 > 0.17f) ? 1 : 0);
						continue;
					}
				}
				else
				{
					num4 = 0;
				}
				num5 = 0;
			}
		}
		val.Apply();
		return val;
	}
}