Decompiled source of ChestItemsHoverDisplay v0.2.0

CDEV.ChestItemsHoverDisplay.dll

Decompiled 4 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("CDEV.ChestItemsHoverDisplay")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0")]
[assembly: AssemblyProduct("CDEV.ChestItemsHoverDisplay")]
[assembly: AssemblyTitle("CDEV.ChestItemsHoverDisplay")]
[assembly: AssemblyVersion("0.2.0.0")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CDEV.ChestItemsHoverDisplay
{
	internal class HoverInventoryPanel : MonoBehaviour
	{
		private struct SlotView
		{
			public GameObject Go;

			public Image Icon;

			public Text Count;
		}

		private RectTransform _root;

		private RectTransform _gridRoot;

		private GridLayoutGroup _grid;

		private Text _title;

		private List<SlotView> _slots;

		private Font _font;

		private Container _current;

		private Inventory _trackedInventory;

		private int _gridW;

		private int _gridH;

		private bool _dirty = true;

		private bool _built;

		private static readonly string[] s_stackCache = BuildStackCache(128);

		private static string[] BuildStackCache(int n)
		{
			string[] array = new string[n + 1];
			for (int i = 0; i <= n; i++)
			{
				array[i] = "x" + i;
			}
			return array;
		}

		private void Awake()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			_root = (RectTransform)((Component)this).transform;
			_slots = new List<SlotView>(32);
			Build();
		}

		private void OnDestroy()
		{
			UnsubscribeCurrent();
		}

		private void Build()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Expected O, but got Unknown
			if (!_built)
			{
				_built = true;
				_font = FindValheimFont();
				_root.anchorMin = new Vector2(0.5f, 0.5f);
				_root.anchorMax = new Vector2(0.5f, 0.5f);
				_root.pivot = new Vector2(0.5f, 1f);
				_root.anchoredPosition = new Vector2(0f, (float)Plugin.CfgVerticalOffset.Value);
				Image obj = ((Component)this).gameObject.AddComponent<Image>();
				((Graphic)obj).color = new Color(0f, 0f, 0f, 0.66f);
				((Graphic)obj).raycastTarget = false;
				ContentSizeFitter obj2 = ((Component)this).gameObject.AddComponent<ContentSizeFitter>();
				obj2.horizontalFit = (FitMode)2;
				obj2.verticalFit = (FitMode)2;
				VerticalLayoutGroup obj3 = ((Component)this).gameObject.AddComponent<VerticalLayoutGroup>();
				((LayoutGroup)obj3).padding = new RectOffset(6, 6, 5, 6);
				((HorizontalOrVerticalLayoutGroup)obj3).spacing = 5f;
				((LayoutGroup)obj3).childAlignment = (TextAnchor)0;
				((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = false;
				((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true;
				((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = false;
				((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false;
				GameObject val = new GameObject("Title", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent(((Component)this).transform, false);
				_title = val.AddComponent<Text>();
				_title.font = _font;
				_title.fontSize = 16;
				_title.fontStyle = (FontStyle)1;
				((Graphic)_title).color = Color.white;
				_title.alignment = (TextAnchor)3;
				_title.horizontalOverflow = (HorizontalWrapMode)1;
				_title.verticalOverflow = (VerticalWrapMode)1;
				((Graphic)_title).raycastTarget = false;
				Outline obj4 = val.AddComponent<Outline>();
				((Shadow)obj4).effectColor = Color.black;
				((Shadow)obj4).effectDistance = new Vector2(1f, -1f);
				LayoutElement obj5 = val.AddComponent<LayoutElement>();
				obj5.minHeight = _title.fontSize;
				obj5.preferredHeight = _title.fontSize;
				GameObject val2 = new GameObject("Grid", new Type[1] { typeof(RectTransform) });
				val2.transform.SetParent(((Component)this).transform, false);
				_gridRoot = (RectTransform)val2.transform;
				ContentSizeFitter obj6 = val2.AddComponent<ContentSizeFitter>();
				obj6.horizontalFit = (FitMode)2;
				obj6.verticalFit = (FitMode)2;
				_grid = val2.AddComponent<GridLayoutGroup>();
				ApplyCellSettings();
				((Component)this).gameObject.SetActive(false);
			}
		}

		private void ApplyCellSettings()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_004d: Expected O, but got Unknown
			int value = Plugin.CfgCellSize.Value;
			_grid.cellSize = new Vector2((float)value, (float)value);
			_grid.spacing = new Vector2(2f, 2f);
			((LayoutGroup)_grid).padding = new RectOffset(0, 0, 0, 0);
			_grid.startCorner = (Corner)0;
			_grid.startAxis = (Axis)0;
			((LayoutGroup)_grid).childAlignment = (TextAnchor)0;
			_grid.constraint = (Constraint)1;
			if (_gridW > 0)
			{
				_grid.constraintCount = _gridW;
			}
		}

		private static Font FindValheimFont()
		{
			Font[] array = Resources.FindObjectsOfTypeAll<Font>();
			Font val = null;
			foreach (Font val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					if (((Object)val2).name.IndexOf("AveriaSerifLibre-Bold", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return val2;
					}
					if ((Object)(object)val == (Object)null)
					{
						val = val2;
					}
				}
			}
			return val;
		}

		private SlotView CreateSlot(int idx)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Slot" + idx, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)_gridRoot, false);
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).color = new Color(1f, 1f, 1f, 0.08f);
			((Graphic)obj).raycastTarget = false;
			GameObject val2 = new GameObject("Icon", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent(val.transform, false);
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			val3.offsetMin = Vector2.zero;
			val3.offsetMax = Vector2.zero;
			Image val4 = val2.AddComponent<Image>();
			((Graphic)val4).raycastTarget = false;
			val4.preserveAspect = true;
			GameObject val5 = new GameObject("Count", new Type[1] { typeof(RectTransform) });
			val5.transform.SetParent(val.transform, false);
			RectTransform val6 = (RectTransform)val5.transform;
			val6.anchorMin = Vector2.zero;
			val6.anchorMax = Vector2.one;
			val6.offsetMin = new Vector2(0f, 0f);
			val6.offsetMax = new Vector2(-2f, 0f);
			Text val7 = val5.AddComponent<Text>();
			((Graphic)val7).raycastTarget = false;
			val7.alignment = (TextAnchor)8;
			val7.font = _font;
			val7.fontSize = 14;
			((Graphic)val7).color = Color.white;
			val7.resizeTextForBestFit = false;
			val7.horizontalOverflow = (HorizontalWrapMode)1;
			val7.verticalOverflow = (VerticalWrapMode)1;
			Outline obj2 = val5.AddComponent<Outline>();
			((Shadow)obj2).effectColor = Color.black;
			((Shadow)obj2).effectDistance = new Vector2(1f, -1f);
			SlotView result = default(SlotView);
			result.Go = val;
			result.Icon = val4;
			result.Count = val7;
			return result;
		}

		public void Hide()
		{
			if (_built)
			{
				if (((Component)this).gameObject.activeSelf)
				{
					((Component)this).gameObject.SetActive(false);
				}
				UnsubscribeCurrent();
			}
		}

		private void UnsubscribeCurrent()
		{
			if (_trackedInventory != null)
			{
				Inventory trackedInventory = _trackedInventory;
				trackedInventory.m_onChanged = (Action)Delegate.Remove(trackedInventory.m_onChanged, new Action(OnInventoryChanged));
				_trackedInventory = null;
			}
			_current = null;
			_dirty = true;
		}

		private void OnInventoryChanged()
		{
			_dirty = true;
		}

		public void Show(Container c)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			if (!_built)
			{
				Build();
			}
			if ((Object)(object)c != (Object)(object)_current)
			{
				UnsubscribeCurrent();
				_current = c;
				_trackedInventory = c.GetInventory();
				if (_trackedInventory != null)
				{
					Inventory trackedInventory = _trackedInventory;
					trackedInventory.m_onChanged = (Action)Delegate.Combine(trackedInventory.m_onChanged, new Action(OnInventoryChanged));
				}
				if ((Object)(object)_title != (Object)null)
				{
					string text = c.m_name ?? string.Empty;
					_title.text = ((Localization.instance != null) ? Localization.instance.Localize(text) : text);
				}
				_dirty = true;
			}
			if (_trackedInventory == null)
			{
				Hide();
				return;
			}
			if ((int)_grid.cellSize.x != Plugin.CfgCellSize.Value)
			{
				ApplyCellSettings();
				_dirty = true;
			}
			int num = Mathf.Max(1, _trackedInventory.GetWidth());
			int num2 = Mathf.Max(1, _trackedInventory.GetHeight());
			if (num != _gridW || num2 != _gridH)
			{
				_gridW = num;
				_gridH = num2;
				_grid.constraintCount = num;
				_dirty = true;
			}
			int value = Plugin.CfgVerticalOffset.Value;
			if ((int)_root.anchoredPosition.y != value)
			{
				_root.anchoredPosition = new Vector2(0f, (float)value);
			}
			bool flag = false;
			if (_dirty)
			{
				Rebuild();
				flag = true;
			}
			if (Plugin.CfgHideWhenEmpty.Value && _trackedInventory.NrOfItems() == 0)
			{
				if (((Component)this).gameObject.activeSelf)
				{
					((Component)this).gameObject.SetActive(false);
				}
				return;
			}
			if (!((Component)this).gameObject.activeSelf)
			{
				((Component)this).gameObject.SetActive(true);
			}
			if (flag)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(_root);
			}
		}

		private void Rebuild()
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			_dirty = false;
			int num = _gridW * _gridH;
			while (_slots.Count < num)
			{
				_slots.Add(CreateSlot(_slots.Count));
			}
			for (int i = 0; i < _slots.Count; i++)
			{
				SlotView slotView = _slots[i];
				if (i < num)
				{
					int num2 = i % _gridW;
					int num3 = i / _gridW;
					ItemData itemAt = _trackedInventory.GetItemAt(num2, num3);
					Sprite val = PickIcon(itemAt);
					slotView.Icon.sprite = val;
					((Behaviour)slotView.Icon).enabled = (Object)(object)val != (Object)null;
					((Graphic)slotView.Icon).color = Color.white;
					int num4 = itemAt?.m_stack ?? 0;
					if (num4 > 1 || (itemAt != null && itemAt.m_shared != null && itemAt.m_shared.m_maxStackSize > 1))
					{
						slotView.Count.text = ((num4 >= 0 && num4 < s_stackCache.Length) ? s_stackCache[num4] : ("x" + num4));
						((Behaviour)slotView.Count).enabled = true;
					}
					else
					{
						((Behaviour)slotView.Count).enabled = false;
					}
					if (!slotView.Go.activeSelf)
					{
						slotView.Go.SetActive(true);
					}
				}
				else if (slotView.Go.activeSelf)
				{
					slotView.Go.SetActive(false);
				}
			}
		}

		private static Sprite PickIcon(ItemData it)
		{
			if (it == null || it.m_shared == null)
			{
				return null;
			}
			Sprite[] icons = it.m_shared.m_icons;
			if (icons == null || icons.Length == 0)
			{
				return null;
			}
			int num = it.m_variant;
			if (num < 0)
			{
				num = 0;
			}
			if (num >= icons.Length)
			{
				num = icons.Length - 1;
			}
			return icons[num];
		}
	}
	[BepInPlugin("cdev.valheim.chestitemshoverdisplay", "CDEV.ChestItemsHoverDisplay", "0.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "cdev.valheim.chestitemshoverdisplay";

		public const string PluginName = "CDEV.ChestItemsHoverDisplay";

		public const string PluginVersion = "0.2.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static HoverInventoryPanel Panel;

		internal static ConfigEntry<bool> CfgEnabled;

		internal static ConfigEntry<int> CfgCellSize;

		internal static ConfigEntry<bool> CfgHideWhenEmpty;

		internal static ConfigEntry<bool> CfgRespectPrivateChests;

		internal static ConfigEntry<KeyCode> CfgHoldKey;

		internal static ConfigEntry<int> CfgVerticalOffset;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Enabled", true, "Master toggle for the hover inventory panel.");
			CfgCellSize = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "CellSize", 40, new ConfigDescription("Pixel size of each grid cell.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(24, 96), Array.Empty<object>()));
			CfgHideWhenEmpty = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "HideWhenEmpty", true, "Hide the panel when the hovered container is empty.");
			CfgRespectPrivateChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "RespectPrivateChests", true, "Hide preview for private chests the local player cannot access, or chests inside wards the local player is not permitted in.");
			CfgHoldKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Display", "HoldKeyToShow", (KeyCode)0, "Optional key that must be held to show the panel. None = always show while hovering.");
			CfgVerticalOffset = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "VerticalOffset", -80, new ConfigDescription("Vertical pixel offset from screen center (negative = below crosshair).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-400, 400), Array.Empty<object>()));
			_harmony = new Harmony("cdev.valheim.chestitemshoverdisplay");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"CDEV.ChestItemsHoverDisplay 0.2.0 loaded.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)Panel != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)Panel).gameObject);
			}
			Panel = null;
		}

		internal static HoverInventoryPanel GetOrCreatePanel()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Panel != (Object)null)
			{
				return Panel;
			}
			if ((Object)(object)Hud.instance == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("CDEV_HoverInventoryPanel", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(((Component)Hud.instance).transform, false);
			Panel = val.AddComponent<HoverInventoryPanel>();
			return Panel;
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
	internal static class HudUpdateCrosshairPatch
	{
		private static readonly Func<Container, long, bool> s_checkAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null), (object)null, true);

		private static void Postfix(Player player)
		{
			//IL_00dd: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			HoverInventoryPanel panel = Plugin.Panel;
			if (!Plugin.CfgEnabled.Value)
			{
				panel?.Hide();
				return;
			}
			if ((Object)(object)player == (Object)null)
			{
				panel?.Hide();
				return;
			}
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if ((Object)(object)hoverObject == (Object)null)
			{
				panel?.Hide();
				return;
			}
			Container componentInParent = hoverObject.GetComponentInParent<Container>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				panel?.Hide();
				return;
			}
			ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				panel?.Hide();
				return;
			}
			if (Plugin.CfgRespectPrivateChests.Value)
			{
				if (s_checkAccess != null && !s_checkAccess(componentInParent, player.GetPlayerID()))
				{
					panel?.Hide();
					return;
				}
				if (!PrivateArea.CheckAccess(((Component)componentInParent).transform.position, 0f, false, false))
				{
					panel?.Hide();
					return;
				}
			}
			if ((int)Plugin.CfgHoldKey.Value != 0 && !Input.GetKey(Plugin.CfgHoldKey.Value))
			{
				panel?.Hide();
			}
			else
			{
				Plugin.GetOrCreatePanel()?.Show(componentInParent);
			}
		}
	}
}