Decompiled source of ChestTag v1.0.1

ChestTag.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.TextCore.LowLevel;
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: AssemblyVersion("0.0.0.0")]
namespace ChestTag;

public enum LabelFace : byte
{
	Front = 1,
	LeftSide,
	RightSide
}
internal static class LabelFaceNames
{
	internal static string Of(LabelFace face)
	{
		return face switch
		{
			LabelFace.Front => "Front", 
			LabelFace.LeftSide => "L Side", 
			LabelFace.RightSide => "R Side", 
			_ => "Front", 
		};
	}
}
internal static class Palette
{
	internal static readonly string[] Names = new string[10] { "Gold", "Cream", "White", "Red", "Orange", "Green", "Teal", "Blue", "Purple", "Pink" };

	private static readonly string[] Hex = new string[10] { "#FFD447", "#FFDE8A", "#FFFFFF", "#FF4F4F", "#F28C28", "#12FF12", "#2EC4B6", "#5CC1FF", "#9A26FF", "#FF4FCA" };

	internal static int Count => Names.Length;

	internal static Color Get(int index)
	{
		//IL_001e: 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)
		Color result = default(Color);
		if (index < 0 || index >= Hex.Length || !ColorUtility.TryParseHtmlString(Hex[index], ref result))
		{
			return Color.white;
		}
		return result;
	}

	internal static byte Step(byte index, int delta)
	{
		int num = (index + delta) % Count;
		if (num < 0)
		{
			num += Count;
		}
		return (byte)num;
	}
}
internal struct TagData
{
	public string Text;

	public LabelFace Face;

	public byte Color;

	public string Icon;

	public bool IsVisible
	{
		get
		{
			if (string.IsNullOrEmpty(Text))
			{
				return !string.IsNullOrEmpty(Icon);
			}
			return true;
		}
	}

	internal static TagData Empty => new TagData
	{
		Text = string.Empty,
		Face = LabelFace.Front,
		Color = 0,
		Icon = string.Empty
	};

	internal int Pack()
	{
		return (int)Face | (Color << 8);
	}

	internal static TagData Unpack(string text, int packed, string icon)
	{
		TagData empty = Empty;
		empty.Text = text;
		empty.Icon = icon ?? string.Empty;
		int num = packed & 0xFF;
		empty.Face = ((num < 1 || num > 3) ? LabelFace.Front : ((LabelFace)num));
		int num2 = (packed >> 8) & 0xFF;
		empty.Color = (byte)((num2 < Palette.Count) ? ((byte)num2) : 0);
		return empty;
	}
}
internal static class ChestData
{
	private const string Key = "ChestTag.v1";

	private const byte Version = 4;

	public static TagData Read(ZDO zdo)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		TagData empty = TagData.Empty;
		if (zdo == null)
		{
			return empty;
		}
		byte[] byteArray = zdo.GetByteArray("ChestTag.v1", (byte[])null);
		if (byteArray == null || byteArray.Length == 0)
		{
			return empty;
		}
		try
		{
			ZPackage val = new ZPackage(byteArray);
			byte b = val.ReadByte();
			if (b < 1 || b > 4)
			{
				return empty;
			}
			empty.Text = val.ReadString();
			if (b >= 2)
			{
				byte b2 = val.ReadByte();
				empty.Face = (LabelFace)((b2 < 1 || b2 > 3) ? 1 : b2);
			}
			if (b >= 3)
			{
				byte b3 = val.ReadByte();
				empty.Color = (byte)((b3 < Palette.Count) ? b3 : 0);
				val.ReadByte();
			}
			if (b >= 4)
			{
				empty.Icon = SanitizeIcon(val.ReadString());
			}
			return empty;
		}
		catch
		{
			return TagData.Empty;
		}
	}

	public static void Write(ZDO zdo, TagData data)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		ZPackage val = new ZPackage();
		val.Write((byte)4);
		val.Write(data.Text ?? string.Empty);
		val.Write((byte)data.Face);
		val.Write(data.Color);
		val.Write((byte)0);
		val.Write(data.Icon ?? string.Empty);
		zdo.Set("ChestTag.v1", val.GetArray());
	}

	public static string SanitizeIcon(string raw)
	{
		if (string.IsNullOrEmpty(raw) || raw.Length > 64)
		{
			return string.Empty;
		}
		foreach (char c in raw)
		{
			if (!char.IsLetterOrDigit(c) && c != '_' && c != '-')
			{
				return string.Empty;
			}
		}
		return raw;
	}

	public static string Sanitize(string raw, int maxLength)
	{
		if (string.IsNullOrEmpty(raw))
		{
			return string.Empty;
		}
		StringBuilder stringBuilder = new StringBuilder(raw.Length);
		foreach (char c in raw)
		{
			if (c != '<' && c != '>' && c != '\r' && c != '\n' && c != '\t')
			{
				stringBuilder.Append(c);
			}
		}
		string text = stringBuilder.ToString().Trim();
		if (text.Length > maxLength)
		{
			text = text.Substring(0, maxLength);
		}
		return text;
	}
}
internal class ChestLabel : MonoBehaviour
{
	private const int PerFrame = 8;

	private const string LabelObjectName = "ChestTag_Label";

	private const string IconObjectName = "ChestTag_Icon";

	private const string PreferredFont = "Valheim-AveriaSerifLibre";

	private static readonly List<ChestLabel> Registry = new List<ChestLabel>();

	private static int _cursor;

	private static TMP_FontAsset _gameFont;

	private static TMP_FontAsset _customFont;

	private static string _customFontName;

	private static bool _fontWarned;

	internal static int ConfigVersion;

	private Container _container;

	private ZNetView _nview;

	private GameObject _labelGo;

	private TextMeshPro _tmp;

	private GameObject _iconGo;

	private SpriteRenderer _iconRenderer;

	private string _iconName = string.Empty;

	private uint _lastRevision = uint.MaxValue;

	private int _appliedConfigVersion = -1;

	private TagData _data;

	private Bounds _bounds;

	private bool _hasBounds;

	private static Material _outlineMaterial;

	private static TMP_FontAsset _outlineFont;

	private static int _outlineVersion = -1;

	private const float OutlineWidthUnit = 0.2f;

	internal static void Attach(Container container)
	{
		if ((Object)(object)((Component)container).GetComponent<ChestLabel>() == (Object)null)
		{
			((Component)container).gameObject.AddComponent<ChestLabel>()._container = container;
		}
	}

	private void OnEnable()
	{
		Registry.Add(this);
	}

	private void OnDisable()
	{
		Registry.Remove(this);
	}

	internal static void Tick()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Invalid comparison between Unknown and I4
		if (Registry.Count == 0 || (int)SystemInfo.graphicsDeviceType == 4)
		{
			return;
		}
		int num = Mathf.Min(8, Registry.Count);
		for (int i = 0; i < num; i++)
		{
			if (_cursor >= Registry.Count)
			{
				_cursor = 0;
			}
			Registry[_cursor].Process();
			_cursor++;
		}
	}

	internal static void DestroyAll()
	{
		ChestLabel[] array = Registry.ToArray();
		foreach (ChestLabel chestLabel in array)
		{
			if ((Object)(object)chestLabel._labelGo != (Object)null)
			{
				Object.Destroy((Object)(object)chestLabel._labelGo);
			}
			if ((Object)(object)chestLabel._iconGo != (Object)null)
			{
				Object.Destroy((Object)(object)chestLabel._iconGo);
			}
			Object.Destroy((Object)(object)chestLabel);
		}
		Registry.Clear();
	}

	private void Process()
	{
		if ((Object)(object)_container == (Object)null)
		{
			_container = ((Component)this).GetComponent<Container>();
		}
		if ((Object)(object)_nview == (Object)null)
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
		}
		if ((Object)(object)_container == (Object)null || (Object)(object)_nview == (Object)null || !_nview.IsValid())
		{
			return;
		}
		ZDO zDO = _nview.GetZDO();
		if (zDO != null)
		{
			uint dataRevision = zDO.DataRevision;
			if (dataRevision != _lastRevision)
			{
				_lastRevision = dataRevision;
				ApplyData(ChestData.Read(zDO));
			}
			if ((Object)(object)_labelGo != (Object)null && _appliedConfigVersion != ConfigVersion)
			{
				ApplyLayout();
			}
			UpdateDistance();
		}
	}

	private void UpdateDistance()
	{
		//IL_0037: 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)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_labelGo == (Object)null))
		{
			float value = ChestTagPlugin.MaxDistance.Value;
			Player localPlayer = Player.m_localPlayer;
			int num;
			if (!(value <= 0f) && !((Object)(object)localPlayer == (Object)null))
			{
				Vector3 val = ((Component)localPlayer).transform.position - ((Component)this).transform.position;
				num = ((((Vector3)(ref val)).sqrMagnitude <= value * value) ? 1 : 0);
			}
			else
			{
				num = 1;
			}
			bool flag = (byte)num != 0;
			MeshRenderer component = _labelGo.GetComponent<MeshRenderer>();
			if ((Object)(object)component != (Object)null && ((Renderer)component).enabled != flag)
			{
				((Renderer)component).enabled = flag;
			}
			if ((Object)(object)_iconRenderer != (Object)null && ((Renderer)_iconRenderer).enabled != flag)
			{
				((Renderer)_iconRenderer).enabled = flag;
			}
		}
	}

	internal void RefreshNow()
	{
		if (!((Object)(object)_nview == (Object)null) && _nview.IsValid())
		{
			ZDO zDO = _nview.GetZDO();
			if (zDO != null)
			{
				_lastRevision = zDO.DataRevision;
				ApplyData(ChestData.Read(zDO));
			}
		}
	}

	private void ApplyData(TagData data)
	{
		_data = data;
		if (!data.IsVisible)
		{
			if ((Object)(object)_labelGo != (Object)null)
			{
				_labelGo.SetActive(false);
			}
			SetIcon(string.Empty);
			return;
		}
		if ((Object)(object)_labelGo == (Object)null && !Build())
		{
			_lastRevision = uint.MaxValue;
			return;
		}
		((TMP_Text)_tmp).text = data.Text ?? string.Empty;
		_labelGo.SetActive(true);
		if (!SetIcon(data.Icon))
		{
			_lastRevision = uint.MaxValue;
		}
		ApplyLayout();
		UpdateDistance();
	}

	private bool SetIcon(string prefab)
	{
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Expected O, but got Unknown
		prefab = prefab ?? string.Empty;
		if (prefab == _iconName && (prefab.Length == 0 || (Object)(object)_iconGo != (Object)null))
		{
			return true;
		}
		_iconName = prefab;
		Sprite val = null;
		if (prefab.Length > 0)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				_iconName = string.Empty;
				return false;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
			ItemDrop val2 = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			Sprite[] array = (((Object)(object)val2 != (Object)null) ? val2.m_itemData.m_shared.m_icons : null);
			val = ((array != null && array.Length != 0) ? array[0] : null);
		}
		if ((Object)(object)val == (Object)null)
		{
			if ((Object)(object)_iconGo != (Object)null)
			{
				_iconGo.SetActive(false);
			}
			return true;
		}
		if ((Object)(object)_iconGo == (Object)null)
		{
			_iconGo = new GameObject("ChestTag_Icon");
			_iconGo.transform.SetParent(((Component)this).transform, false);
			_iconRenderer = _iconGo.AddComponent<SpriteRenderer>();
		}
		_iconRenderer.sprite = val;
		_iconGo.SetActive(true);
		return true;
	}

	private bool Build()
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		TMP_FontAsset font = GetFont();
		if ((Object)(object)font == (Object)null)
		{
			return false;
		}
		if (!_hasBounds)
		{
			_hasBounds = TryComputeBounds(out _bounds);
		}
		if (!_hasBounds)
		{
			return false;
		}
		GameObject val = new GameObject("ChestTag_Label");
		val.SetActive(false);
		val.transform.SetParent(((Component)this).transform, false);
		TextMeshPro val2 = val.AddComponent<TextMeshPro>();
		((TMP_Text)val2).font = font;
		((TMP_Text)val2).fontSharedMaterial = GetOutlineMaterial(font);
		((TMP_Text)val2).alignment = (TextAlignmentOptions)514;
		((TMP_Text)val2).textWrappingMode = (TextWrappingModes)1;
		((TMP_Text)val2).enableAutoSizing = true;
		((TMP_Text)val2).fontSizeMin = 0.1f;
		((TMP_Text)val2).richText = false;
		((Graphic)val2).raycastTarget = false;
		MeshRenderer component = val.GetComponent<MeshRenderer>();
		if ((Object)(object)component != (Object)null)
		{
			((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)component).receiveShadows = false;
		}
		_labelGo = val;
		_tmp = val2;
		ApplyLayout();
		return true;
	}

	private void ApplyLayout()
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: 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_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0394: Unknown result type (might be due to invalid IL or missing references)
		//IL_0399: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0402: Unknown result type (might be due to invalid IL or missing references)
		//IL_0407: Unknown result type (might be due to invalid IL or missing references)
		//IL_0411: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0292: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02be: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0437: Unknown result type (might be due to invalid IL or missing references)
		//IL_043c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0440: Unknown result type (might be due to invalid IL or missing references)
		//IL_0445: Unknown result type (might be due to invalid IL or missing references)
		//IL_0451: Unknown result type (might be due to invalid IL or missing references)
		//IL_045b: Unknown result type (might be due to invalid IL or missing references)
		//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_04be: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04de: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_050b: Unknown result type (might be due to invalid IL or missing references)
		//IL_057f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0584: Unknown result type (might be due to invalid IL or missing references)
		//IL_0595: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_05da: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_05de: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f1: Unknown result type (might be due to invalid IL or missing references)
		_appliedConfigVersion = ConfigVersion;
		if ((Object)(object)_labelGo == (Object)null || (Object)(object)_tmp == (Object)null || !_hasBounds)
		{
			return;
		}
		TypeSettings typeSettings = ChestTagPlugin.GetTypeSettings(ChestRules.PrefabName(((Component)this).gameObject));
		Vector3 val = (typeSettings.FrontFlipped.Value ? Vector3.back : Vector3.forward);
		Vector3 val2 = Vector3.Cross(Vector3.up, -val);
		Vector3 val3 = val;
		switch (_data.Face)
		{
		case LabelFace.LeftSide:
			val3 = -val2;
			break;
		case LabelFace.RightSide:
			val3 = val2;
			break;
		}
		Vector3 val4 = Vector3.Cross(Vector3.up, -val3);
		Vector3 extents = ((Bounds)(ref _bounds)).extents;
		bool num = Mathf.Abs(val3.z) > 0.5f;
		float num2 = (num ? extents.z : extents.x);
		float num3 = (num ? extents.x : extents.z) * 2f;
		float num4 = extents.y * 2f;
		float num5 = num3 * 0.8f;
		float num6 = num4 * 0.5f;
		float num7 = Mathf.Clamp(typeSettings.OffsetX.Value, -0.2f, 0.2f) * num3;
		float num8 = Mathf.Clamp(typeSettings.OffsetY.Value, -0.3f, 0.4f) * num4;
		bool flag = !string.IsNullOrEmpty(_data.Text);
		bool flag2 = (Object)(object)_iconGo != (Object)null && _iconGo.activeSelf && (Object)(object)_iconRenderer != (Object)null && (Object)(object)_iconRenderer.sprite != (Object)null;
		float num9 = (flag2 ? (Mathf.Clamp(typeSettings.IconSize.Value, 0.2f, 0.9f) * num4) : 0f);
		float num10 = ((flag2 && flag) ? (num9 * 0.15f) : 0f);
		IconPosition value = ChestTagPlugin.IconPlacement.Value;
		bool flag3 = value == IconPosition.Left || value == IconPosition.Right;
		bool num11 = flag && flag2;
		float num12 = num5;
		float num13 = num6;
		((TMP_Text)_tmp).rectTransform.sizeDelta = new Vector2(num12, num13);
		((TMP_Text)_tmp).fontSizeMax = typeSettings.MaxTextSize.Value;
		((TMP_Text)_tmp).fontSize = typeSettings.MaxTextSize.Value;
		((Behaviour)_tmp).enabled = flag;
		float num14 = num12;
		float num15 = num13;
		Bounds val5;
		if (num11 && _labelGo.activeInHierarchy)
		{
			((TMP_Text)_tmp).ForceMeshUpdate(false, false);
			val5 = ((TMP_Text)_tmp).textBounds;
			num14 = Mathf.Min(Mathf.Max(((Bounds)(ref val5)).size.x, 0.01f), num12);
			val5 = ((TMP_Text)_tmp).textBounds;
			num15 = Mathf.Min(Mathf.Max(((Bounds)(ref val5)).size.y, 0.01f), num13);
		}
		float num16 = 0f;
		float num17 = 0f;
		float num18 = 0f;
		float num19 = 0f;
		if (num11)
		{
			if (flag3)
			{
				float num20 = (0f - (num9 + num10 + num14)) * 0.5f;
				float num21 = num20 + num9 * 0.5f;
				float num22 = num20 + num9 + num10 + num14 * 0.5f;
				if (value == IconPosition.Left)
				{
					num16 = num21;
					num18 = num22;
				}
				else
				{
					num16 = 0f - num21;
					num18 = 0f - num22;
				}
			}
			else
			{
				float num23 = (num9 + num10 + num15) * 0.5f;
				float num24 = num23 - num9 * 0.5f;
				float num25 = num23 - num9 - num10 - num15 * 0.5f;
				if (value == IconPosition.Above)
				{
					num17 = num24;
					num19 = num25;
				}
				else
				{
					num17 = 0f - num24;
					num19 = 0f - num25;
				}
			}
		}
		Vector3 val6 = ((Bounds)(ref _bounds)).center + val3 * (num2 + 0.01f) + val4 * num7 + Vector3.up * num8;
		Quaternion localRotation = Quaternion.LookRotation(-val3, Vector3.up);
		Transform transform = _labelGo.transform;
		transform.localPosition = val6 + val4 * num18 + Vector3.up * num19;
		transform.localRotation = localRotation;
		if ((Object)(object)_iconGo != (Object)null && flag2)
		{
			val5 = _iconRenderer.sprite.bounds;
			Vector3 size = ((Bounds)(ref val5)).size;
			float num26 = num9 / Mathf.Max(new float[3] { size.x, size.y, 0.0001f });
			float num27 = Mathf.Clamp(typeSettings.IconOffsetX.Value, -0.5f, 0.5f) * num3;
			float num28 = Mathf.Clamp(typeSettings.IconOffsetY.Value, -0.5f, 0.5f) * num4;
			_iconGo.transform.localPosition = val6 + val4 * (num16 + num27) + Vector3.up * (num17 + num28);
			_iconGo.transform.localRotation = localRotation;
			_iconGo.transform.localScale = new Vector3(num26, num26, num26);
		}
		TMP_FontAsset font = GetFont();
		if ((Object)(object)font != (Object)null)
		{
			if ((Object)(object)((TMP_Text)_tmp).font != (Object)(object)font)
			{
				((TMP_Text)_tmp).font = font;
			}
			((TMP_Text)_tmp).fontSharedMaterial = GetOutlineMaterial(font);
		}
		float num29 = Mathf.Clamp(ChestTagPlugin.Opacity.Value, 0.1f, 1f);
		Color color = Palette.Get(_data.Color);
		color.a = num29;
		((Graphic)_tmp).color = color;
		if ((Object)(object)_iconRenderer != (Object)null)
		{
			_iconRenderer.color = new Color(1f, 1f, 1f, num29);
		}
		FontStyles val7 = (FontStyles)0;
		if (ChestTagPlugin.BoldText.Value)
		{
			val7 = (FontStyles)(val7 | 1);
		}
		if (ChestTagPlugin.SmallCapsText.Value)
		{
			val7 = (FontStyles)(val7 | 0x20);
		}
		((TMP_Text)_tmp).fontStyle = val7;
		UpdateOutlineMaterial();
	}

	private static Material GetOutlineMaterial(TMP_FontAsset font)
	{
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Expected O, but got Unknown
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Expected O, but got Unknown
		if ((Object)(object)_outlineMaterial == (Object)null || (Object)(object)_outlineFont != (Object)(object)font)
		{
			_outlineFont = font;
			TMP_FontAsset gameFont = GetGameFont();
			if ((Object)(object)font != (Object)(object)gameFont && (Object)(object)gameFont != (Object)null && (Object)(object)((TMP_Asset)gameFont).material != (Object)null && (Object)(object)((TMP_Asset)font).material != (Object)null)
			{
				Material material = ((TMP_Asset)font).material;
				_outlineMaterial = new Material(((TMP_Asset)gameFont).material);
				_outlineMaterial.SetTexture(ShaderUtilities.ID_MainTex, material.GetTexture(ShaderUtilities.ID_MainTex));
				_outlineMaterial.SetFloat(ShaderUtilities.ID_GradientScale, material.GetFloat(ShaderUtilities.ID_GradientScale));
				_outlineMaterial.SetFloat(ShaderUtilities.ID_TextureWidth, material.GetFloat(ShaderUtilities.ID_TextureWidth));
				_outlineMaterial.SetFloat(ShaderUtilities.ID_TextureHeight, material.GetFloat(ShaderUtilities.ID_TextureHeight));
				_outlineMaterial.SetFloat(ShaderUtilities.ID_WeightNormal, material.GetFloat(ShaderUtilities.ID_WeightNormal));
				_outlineMaterial.SetFloat(ShaderUtilities.ID_WeightBold, material.GetFloat(ShaderUtilities.ID_WeightBold));
			}
			else
			{
				_outlineMaterial = new Material(((TMP_Asset)font).material);
			}
			((Object)_outlineMaterial).name = "ChestTag_Outline";
			_outlineVersion = -1;
			UpdateOutlineMaterial();
		}
		return _outlineMaterial;
	}

	private static void UpdateOutlineMaterial()
	{
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_outlineMaterial == (Object)null) && _outlineVersion != ConfigVersion)
		{
			_outlineVersion = ConfigVersion;
			float num = Mathf.Clamp(ChestTagPlugin.OutlineThickness.Value, 0f, 2.8f) * 0.2f;
			if (num > 0f)
			{
				_outlineMaterial.EnableKeyword(ShaderUtilities.Keyword_Outline);
			}
			else
			{
				_outlineMaterial.DisableKeyword(ShaderUtilities.Keyword_Outline);
			}
			_outlineMaterial.SetColor(ShaderUtilities.ID_OutlineColor, new Color(0f, 0f, 0f, Mathf.Clamp(ChestTagPlugin.Opacity.Value, 0.1f, 1f)));
			_outlineMaterial.SetFloat(ShaderUtilities.ID_OutlineWidth, num);
			_outlineMaterial.SetFloat(ShaderUtilities.ID_FaceDilate, num);
			_outlineMaterial.SetFloat(ShaderUtilities.ID_OutlineSoftness, 0f);
			ShaderUtilities.GetShaderPropertyIDs();
			ShaderUtilities.UpdateShaderRatios(_outlineMaterial);
		}
	}

	private static TMP_FontAsset GetFont()
	{
		string value = ChestTagPlugin.FontName.Value;
		if (string.IsNullOrEmpty(value) || value == "Game font")
		{
			return GetGameFont();
		}
		if ((Object)(object)_customFont != (Object)null && _customFontName == value)
		{
			return _customFont;
		}
		if (_customFontName == value)
		{
			return GetGameFont();
		}
		_customFontName = value;
		_customFont = LoadCustomFont(value);
		if (!((Object)(object)_customFont != (Object)null))
		{
			return GetGameFont();
		}
		return _customFont;
	}

	private static TMP_FontAsset LoadCustomFont(string name)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Expected O, but got Unknown
		string text = ChestTagPlugin.FindFontFile(name);
		if (text == null)
		{
			ChestTagPlugin.Log.LogWarning((object)("Font '" + name + "' was not found in " + ChestTagPlugin.FontsDir + "; using the default font."));
			return null;
		}
		try
		{
			TMP_FontAsset val = TMP_FontAsset.CreateFontAsset(new Font(text), 90, 9, (GlyphRenderMode)4165, 1024, 1024, (AtlasPopulationMode)1, true);
			if ((Object)(object)val == (Object)null || (Object)(object)((TMP_Asset)val).material == (Object)null)
			{
				ChestTagPlugin.Log.LogWarning((object)("Could not create a font from '" + text + "'; using the default font."));
				return null;
			}
			((Object)val).name = "ChestTag_" + name;
			TMP_FontAsset gameFont = GetGameFont();
			if ((Object)(object)gameFont != (Object)null)
			{
				val.fallbackFontAssetTable = new List<TMP_FontAsset> { gameFont };
			}
			return val;
		}
		catch (Exception ex)
		{
			ChestTagPlugin.Log.LogWarning((object)("Could not load font '" + text + "': " + ex.Message + ". Using the default font."));
			return null;
		}
	}

	private static TMP_FontAsset GetGameFont()
	{
		if ((Object)(object)_gameFont != (Object)null)
		{
			return _gameFont;
		}
		TMP_FontAsset val = null;
		TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
		foreach (TMP_FontAsset val2 in array)
		{
			if (!((Object)(object)val2 == (Object)null))
			{
				if (((Object)val2).name == "Valheim-AveriaSerifLibre")
				{
					_gameFont = val2;
					return _gameFont;
				}
				if ((Object)(object)val == (Object)null && ((Object)val2).name.Contains("Averia"))
				{
					val = val2;
				}
			}
		}
		_gameFont = val;
		if ((Object)(object)_gameFont == (Object)null && !_fontWarned)
		{
			_fontWarned = true;
			ChestTagPlugin.Log.LogWarning((object)"No Valheim TMP font found (Valheim-AveriaSerifLibre); labels will not be shown.");
		}
		return _gameFont;
	}

	private bool TryComputeBounds(out Bounds result)
	{
		//IL_0001: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: 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_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: 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_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: 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_0154: 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)
		result = default(Bounds);
		bool flag = false;
		GameObject val = (((Object)(object)_container != (Object)null) ? _container.m_open : null);
		MeshFilter[] componentsInChildren = ((Component)this).GetComponentsInChildren<MeshFilter>(false);
		foreach (MeshFilter val2 in componentsInChildren)
		{
			if ((Object)(object)val2.sharedMesh == (Object)null || ((Object)((Component)val2).gameObject).name == "ChestTag_Label" || ((Object)((Component)val2).gameObject).name == "ChestTag_Icon" || ((Object)(object)val != (Object)null && ((Component)val2).transform.IsChildOf(val.transform)))
			{
				continue;
			}
			Bounds bounds = val2.sharedMesh.bounds;
			for (int j = 0; j < 8; j++)
			{
				Vector3 val3 = ((Bounds)(ref bounds)).center + new Vector3(((j & 1) == 0) ? (0f - ((Bounds)(ref bounds)).extents.x) : ((Bounds)(ref bounds)).extents.x, ((j & 2) == 0) ? (0f - ((Bounds)(ref bounds)).extents.y) : ((Bounds)(ref bounds)).extents.y, ((j & 4) == 0) ? (0f - ((Bounds)(ref bounds)).extents.z) : ((Bounds)(ref bounds)).extents.z);
				Vector3 val4 = ((Component)this).transform.InverseTransformPoint(((Component)val2).transform.TransformPoint(val3));
				if (!flag)
				{
					result = new Bounds(val4, Vector3.zero);
					flag = true;
				}
				else
				{
					((Bounds)(ref result)).Encapsulate(val4);
				}
			}
		}
		return flag;
	}
}
internal static class ChestRules
{
	private static readonly HashSet<string> Buildable = new HashSet<string>();

	private static bool _buildableReady;

	internal static string PrefabName(GameObject go)
	{
		return ((Object)go).name.Replace("(Clone)", string.Empty).Trim();
	}

	internal static bool IsPlayerChest(Container container)
	{
		if ((Object)(object)container == (Object)null || (Object)(object)((Component)container).GetComponent<Piece>() == (Object)null)
		{
			return false;
		}
		if ((Object)(object)((Component)container).GetComponent<TombStone>() != (Object)null)
		{
			return false;
		}
		if ((Object)(object)container.m_wagon != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null)
		{
			return false;
		}
		string text = PrefabName(((Component)container).gameObject);
		if (ChestTagPlugin.GetTypeSettings(text) != ChestTagPlugin.OtherSettings)
		{
			return true;
		}
		EnsureBuildable();
		return Buildable.Contains(text);
	}

	private static void EnsureBuildable()
	{
		if (_buildableReady || (Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items.Count == 0)
		{
			return;
		}
		foreach (GameObject item in ObjectDB.instance.m_items)
		{
			ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			PieceTable val2 = (((Object)(object)val != (Object)null) ? val.m_itemData.m_shared.m_buildPieces : null);
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			foreach (GameObject piece in val2.m_pieces)
			{
				if ((Object)(object)piece != (Object)null)
				{
					Buildable.Add(((Object)piece).name);
				}
			}
		}
		_buildableReady = true;
	}
}
internal static class ChestPatches
{
	private enum Action
	{
		None,
		Edit,
		Face,
		ColorNext,
		ColorPrevious,
		RemoveIcon
	}

	private static readonly MethodInfo CheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null);

	private static readonly MethodInfo TakeInput = AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null);

	internal const string SetRpc = "ChestTag_Set";

	private static readonly FieldInfo CurrentContainer = AccessTools.Field(typeof(InventoryGui), "m_currentContainer");

	private static readonly FieldInfo ContainerGrid = AccessTools.Field(typeof(InventoryGui), "m_containerGrid");

	internal static bool ScrollReserved;

	internal static bool HasAccess(Container container, Player player)
	{
		if (CheckAccess == null)
		{
			return true;
		}
		return (bool)CheckAccess.Invoke(container, new object[1] { player.GetPlayerID() });
	}

	internal static void Write(Container container, ChestLabel label, TagData data)
	{
		ZNetView component = ((Component)container).GetComponent<ZNetView>();
		if (!((Object)(object)component == (Object)null) && component.IsValid())
		{
			ZDO zDO = component.GetZDO();
			if (component.IsOwner())
			{
				ChestData.Write(zDO, data);
				label.RefreshNow();
			}
			else if (zDO.GetOwner() == 0L)
			{
				component.ClaimOwnership();
				ChestData.Write(zDO, data);
				label.RefreshNow();
			}
			else
			{
				component.InvokeRPC("ChestTag_Set", new object[3]
				{
					data.Text ?? string.Empty,
					data.Pack(),
					data.Icon ?? string.Empty
				});
			}
		}
	}

	internal static void OnSetRpc(Container container, long sender, string text, int packed, string icon)
	{
		ZNetView val = (((Object)(object)container != (Object)null) ? ((Component)container).GetComponent<ZNetView>() : null);
		if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && (!(CheckAccess != null) || (bool)CheckAccess.Invoke(container, new object[1] { sender })))
		{
			icon = ChestData.SanitizeIcon(icon);
			if (icon.Length > 0 && ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ObjectDB.instance.GetItemPrefab(icon) == (Object)null))
			{
				icon = string.Empty;
			}
			ChestData.Write(val.GetZDO(), TagData.Unpack(ChestData.Sanitize(text, ChestTagPlugin.MaxLength.Value), packed, icon));
		}
	}

	internal static LabelFace NextFace(LabelFace current)
	{
		return current switch
		{
			LabelFace.Front => LabelFace.LeftSide, 
			LabelFace.LeftSide => LabelFace.RightSide, 
			_ => LabelFace.Front, 
		};
	}

	internal static Container OpenChest()
	{
		if (CurrentContainer == null || (Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible())
		{
			return null;
		}
		object? value = CurrentContainer.GetValue(InventoryGui.instance);
		Container val = (Container)((value is Container) ? value : null);
		if (!((Object)(object)val != (Object)null) || !((Object)(object)((Component)val).GetComponent<ChestLabel>() != (Object)null))
		{
			return null;
		}
		return val;
	}

	private static ItemData HoveredItem()
	{
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		InventoryGui instance = InventoryGui.instance;
		InventoryGrid val = (InventoryGrid)((ContainerGrid != null) ? /*isinst with value type is only supported in some contexts*/: null);
		InventoryGrid[] array = (InventoryGrid[])(object)new InventoryGrid[2] { instance.m_playerGrid, val };
		foreach (InventoryGrid val2 in array)
		{
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.m_gridRoot == (Object)null || val2.GetInventory() == null)
			{
				continue;
			}
			InventoryElement[] componentsInChildren = ((Component)val2.m_gridRoot).GetComponentsInChildren<InventoryElement>(false);
			foreach (InventoryElement val3 in componentsInChildren)
			{
				Transform transform = ((Component)val3).transform;
				RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				if ((Object)(object)val4 == (Object)null)
				{
					continue;
				}
				Canvas componentInParent = ((Component)val3).GetComponentInParent<Canvas>();
				Camera val5 = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
				if (RectTransformUtility.RectangleContainsScreenPoint(val4, Vector2.op_Implicit(Input.mousePosition), val5))
				{
					Vector2i position = val3.Position;
					ItemData itemAt = val2.GetInventory().GetItemAt(position.x, position.y);
					if (itemAt != null)
					{
						return itemAt;
					}
				}
			}
		}
		return null;
	}

	private static void RemoveIcon(Container container, ChestLabel label, Player player)
	{
		TagData data = ChestData.Read(((Component)container).GetComponent<ZNetView>().GetZDO());
		if (string.IsNullOrEmpty(data.Icon))
		{
			((Character)player).Message((MessageType)1, "This chest has no icon", 0, (Sprite)null, false);
			return;
		}
		data.Icon = string.Empty;
		Write(container, label, data);
		((Character)player).Message((MessageType)1, "Chest icon removed", 0, (Sprite)null, false);
	}

	internal static void CheckIconKey()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || !Input.GetKeyDown(ChestTagPlugin.IconKey.Value) || TextInput.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()))
		{
			return;
		}
		Container val = OpenChest();
		ChestLabel chestLabel = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ChestLabel>() : null);
		ZNetView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null);
		if ((Object)(object)chestLabel == (Object)null || (Object)(object)val2 == (Object)null || !val2.IsValid() || !HasAccess(val, localPlayer))
		{
			return;
		}
		if (Input.GetKey(ChestTagPlugin.ModifierKey.Value))
		{
			RemoveIcon(val, chestLabel, localPlayer);
			return;
		}
		ItemData val3 = HoveredItem();
		if (val3 == null || (Object)(object)val3.m_dropPrefab == (Object)null)
		{
			return;
		}
		string text = ChestData.SanitizeIcon(ChestRules.PrefabName(val3.m_dropPrefab));
		if (text.Length != 0)
		{
			TagData data = ChestData.Read(val2.GetZDO());
			string text2;
			if (data.Icon == text)
			{
				data.Icon = string.Empty;
				text2 = "Chest icon removed";
			}
			else
			{
				data.Icon = text;
				text2 = "Chest icon: " + Localization.instance.Localize(val3.m_shared.m_name);
			}
			Write(val, chestLabel, data);
			((Character)localPlayer).Message((MessageType)1, text2, 0, (Sprite)null, false);
		}
	}

	internal static void CheckKeys()
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d4: 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)
		ScrollReserved = false;
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || !Input.GetKey(ChestTagPlugin.ModifierKey.Value))
		{
			return;
		}
		GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
		Container val = (((Object)(object)hoverObject != (Object)null) ? hoverObject.GetComponentInParent<Container>() : null);
		ChestLabel chestLabel = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ChestLabel>() : null);
		if ((Object)(object)chestLabel == (Object)null)
		{
			return;
		}
		float num = (ChestTagPlugin.UseMouseWheel.Value ? ZInput.GetMouseScrollWheel() : 0f);
		ScrollReserved = ChestTagPlugin.UseMouseWheel.Value;
		Action action = Action.None;
		if (Input.GetKeyDown(ChestTagPlugin.EditKey.Value))
		{
			action = Action.Edit;
		}
		else if (Input.GetKeyDown(ChestTagPlugin.FaceKey.Value))
		{
			action = Action.Face;
		}
		else if (Input.GetKeyDown(ChestTagPlugin.IconKey.Value))
		{
			action = Action.RemoveIcon;
		}
		else if (num > 0f)
		{
			action = Action.ColorNext;
		}
		else if (num < 0f)
		{
			action = Action.ColorPrevious;
		}
		if (action == Action.None || (TakeInput != null && !(bool)TakeInput.Invoke(localPlayer, null)))
		{
			return;
		}
		ZNetView component = ((Component)val).GetComponent<ZNetView>();
		if ((Object)(object)component == (Object)null || !component.IsValid())
		{
			return;
		}
		if (!HasAccess(val, localPlayer))
		{
			((Character)localPlayer).Message((MessageType)2, "$msg_cantopen", 0, (Sprite)null, false);
			return;
		}
		switch (action)
		{
		case Action.Edit:
			if ((Object)(object)TextInput.instance != (Object)null)
			{
				TextInput.instance.RequestText((TextReceiver)(object)new LabelReceiver(val, chestLabel), "Chest label", ChestTagPlugin.MaxLength.Value);
			}
			return;
		case Action.RemoveIcon:
			RemoveIcon(val, chestLabel, localPlayer);
			return;
		}
		TagData data = ChestData.Read(component.GetZDO());
		if (!data.IsVisible)
		{
			((Character)localPlayer).Message((MessageType)1, "Name the chest first (" + ((object)ChestTagPlugin.ModifierKey.Value/*cast due to .constrained prefix*/).ToString() + "+" + ((object)ChestTagPlugin.EditKey.Value/*cast due to .constrained prefix*/).ToString() + ")", 0, (Sprite)null, false);
			return;
		}
		string text;
		switch (action)
		{
		default:
			return;
		case Action.Face:
			data.Face = NextFace(data.Face);
			text = "Label face: " + LabelFaceNames.Of(data.Face);
			break;
		case Action.ColorNext:
			data.Color = Palette.Step(data.Color, 1);
			text = "Label color: " + Palette.Names[data.Color];
			break;
		case Action.ColorPrevious:
			data.Color = Palette.Step(data.Color, -1);
			text = "Label color: " + Palette.Names[data.Color];
			break;
		}
		if (action != Action.Face)
		{
			ChestTagPlugin.LastColor.Value = Palette.Names[data.Color];
		}
		Write(val, chestLabel, data);
		((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
	}
}
[HarmonyPatch(typeof(Container), "Awake")]
internal static class Container_Awake_Patch
{
	private static void Postfix(Container __instance)
	{
		if (!ChestRules.IsPlayerChest(__instance))
		{
			return;
		}
		ChestLabel.Attach(__instance);
		ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
		if ((Object)(object)component != (Object)null && component.GetZDO() != null)
		{
			Container container = __instance;
			component.Register<string, int, string>("ChestTag_Set", (Action<long, string, int, string>)delegate(long sender, string text, int packed, string icon)
			{
				ChestPatches.OnSetRpc(container, sender, text, packed, icon);
			});
		}
	}
}
[HarmonyPatch(typeof(Container), "Interact")]
internal static class Container_Interact_Patch
{
	private static bool Prefix(Container __instance, Humanoid character, bool hold, ref bool __result)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		if (hold || (Object)(object)character == (Object)null || (Object)(object)character != (Object)(object)Player.m_localPlayer)
		{
			return true;
		}
		if (!Input.GetKey(ChestTagPlugin.ModifierKey.Value) || (Object)(object)((Component)__instance).GetComponent<ChestLabel>() == (Object)null)
		{
			return true;
		}
		__result = true;
		return false;
	}
}
[HarmonyPatch(typeof(Container), "GetHoverText")]
internal static class Container_GetHoverText_Patch
{
	private static void Postfix(Container __instance, ref string __result)
	{
		if (string.IsNullOrEmpty(__result) || (Object)(object)((Component)__instance).GetComponent<ChestLabel>() == (Object)null)
		{
			return;
		}
		string[] array = __result.Split(new char[1] { '\n' });
		string value = array[0];
		ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
		if ((Object)(object)component != (Object)null && component.IsValid())
		{
			string text = ChestData.Read(component.GetZDO()).Text;
			if (!string.IsNullOrEmpty(text))
			{
				value = text;
			}
		}
		StringBuilder stringBuilder = new StringBuilder(value);
		for (int i = 1; i < array.Length; i++)
		{
			if (array[i].Length > 0 && array[i].IndexOf("<color=yellow>", StringComparison.Ordinal) < 0)
			{
				stringBuilder.Append('\n').Append(array[i]);
			}
		}
		__result = stringBuilder.ToString();
	}
}
internal class LabelReceiver : TextReceiver
{
	private readonly Container _container;

	private readonly ChestLabel _label;

	internal LabelReceiver(Container container, ChestLabel label)
	{
		_container = container;
		_label = label;
	}

	private ZDO Zdo()
	{
		ZNetView val = (((Object)(object)_container != (Object)null) ? ((Component)_container).GetComponent<ZNetView>() : null);
		if (!((Object)(object)val != (Object)null) || !val.IsValid())
		{
			return null;
		}
		return val.GetZDO();
	}

	public string GetText()
	{
		return ChestData.Read(Zdo()).Text;
	}

	public void SetText(string text)
	{
		ZDO val = Zdo();
		if (val != null)
		{
			TagData data = ChestData.Read(val);
			if (string.IsNullOrEmpty(data.Text))
			{
				data.Color = (byte)Mathf.Max(0, Array.IndexOf(Palette.Names, ChestTagPlugin.LastColor.Value));
			}
			data.Text = ChestData.Sanitize(text, ChestTagPlugin.MaxLength.Value);
			ChestPatches.Write(_container, _label, data);
		}
	}
}
[HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")]
internal static class ZInput_GetMouseScrollWheel_Patch
{
	private static void Postfix(ref float __result)
	{
		if (ChestPatches.ScrollReserved)
		{
			__result = 0f;
		}
	}
}
public enum IconPosition
{
	Left,
	Right,
	Above,
	Below
}
internal class TypeSettings
{
	public ConfigEntry<bool> FrontFlipped;

	public ConfigEntry<float> MaxTextSize;

	public ConfigEntry<float> OffsetX;

	public ConfigEntry<float> OffsetY;

	public ConfigEntry<float> IconSize;

	public ConfigEntry<float> IconOffsetX;

	public ConfigEntry<float> IconOffsetY;
}
[BepInPlugin("DarthVladi.ChestTag", "Chest Tag", "1.0.0")]
[BepInProcess("valheim.exe")]
public class ChestTagPlugin : BaseUnityPlugin
{
	public const string ModGuid = "DarthVladi.ChestTag";

	public const string ModName = "Chest Tag";

	public const string ModVersion = "1.0.0";

	internal const float MaxOffset = 0.2f;

	internal const float MaxIconOffset = 0.5f;

	internal const float MinOffsetY = -0.3f;

	internal const float MaxOffsetY = 0.4f;

	internal const string GameFont = "Game font";

	internal const string DefaultFont = "Economica-Regular";

	private static readonly string[] BundledFiles = new string[4] { "Economica-Regular.ttf", "OFL-Economica.txt", "RussoOne-Regular.ttf", "OFL-RussoOne.txt" };

	internal static string FontsDir;

	internal static ChestTagPlugin Instance;

	internal static ManualLogSource Log;

	internal static ConfigEntry<KeyCode> ModifierKey;

	internal static ConfigEntry<KeyCode> EditKey;

	internal static ConfigEntry<KeyCode> FaceKey;

	internal static ConfigEntry<int> MaxLength;

	internal static ConfigEntry<KeyCode> IconKey;

	internal static ConfigEntry<bool> BoldText;

	internal static ConfigEntry<bool> SmallCapsText;

	internal static ConfigEntry<bool> UseMouseWheel;

	internal static ConfigEntry<float> OutlineThickness;

	internal static ConfigEntry<float> Opacity;

	internal static ConfigEntry<float> MaxDistance;

	internal static ConfigEntry<string> LastColor;

	internal const float MaxOutline = 2.8f;

	internal static ConfigEntry<IconPosition> IconPlacement;

	internal static ConfigEntry<string> FontName;

	private static readonly string[][] KnownTypes = new string[7][]
	{
		new string[6] { "piece_chest_wood", "Wood chest", "false", "1.2", "0", "0.47" },
		new string[6] { "piece_chest", "Reinforced chest", "false", "1.5", "0.055", "0.3" },
		new string[6] { "piece_chest_private", "Private chest", "false", "1.0", "0", "0.386" },
		new string[6] { "piece_chest_blackmetal", "Black metal chest", "false", "1.5", "0", "0.5" },
		new string[6] { "piece_chest_barrel", "Barrel", "false", "1.2", "0", "0.402" },
		new string[6] { "piece_chest_grausten", "Grausten chest", "false", "1.5", "0", "0.5" },
		new string[6] { "piece_chest_warderobe", "Wardrobe", "true", "1.5", "0", "0.5" }
	};

	private static readonly Dictionary<string, TypeSettings> Types = new Dictionary<string, TypeSettings>();

	private static TypeSettings _other;

	private Harmony _harmony;

	internal static TypeSettings OtherSettings => _other;

	private void Awake()
	{
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Expected O, but got Unknown
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Expected O, but got Unknown
		//IL_025c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0266: Expected O, but got Unknown
		//IL_0299: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: Expected O, but got Unknown
		//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e0: Expected O, but got Unknown
		//IL_0313: Unknown result type (might be due to invalid IL or missing references)
		//IL_031d: Expected O, but got Unknown
		//IL_0476: Unknown result type (might be due to invalid IL or missing references)
		//IL_0480: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		ModifierKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("00-General", "modifierKey", (KeyCode)308, "Hold this key while looking at a chest, then press the edit key or the face key.");
		EditKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("00-General", "editKey", (KeyCode)101, "Modifier + this key opens the text box to name the chest.");
		FaceKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("00-General", "faceKey", (KeyCode)113, "Modifier + this key cycles the label face: Front, L Side, R Side.");
		IconKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("00-General", "iconKey", (KeyCode)103, "With a chest open, hover an item (in the chest or in your inventory) and press this key to use it as the chest icon. Press it again on the same item to remove the icon.");
		UseMouseWheel = ((BaseUnityPlugin)this).Config.Bind<bool>("00-General", "useMouseWheel", true, "Modifier + mouse wheel while looking at a chest changes the label color. While it is active the camera zoom is disabled so the wheel does not do both. Turn it off and the color cannot be changed.");
		LastColor = ((BaseUnityPlugin)this).Config.Bind<string>("00-General", "lastColor", Palette.Names[0], new ConfigDescription("Color given to chests you label for the first time. It updates by itself whenever you change a chest's color.", (AcceptableValueBase)(object)new AcceptableValueList<string>(Palette.Names), Array.Empty<object>()));
		MaxLength = ((BaseUnityPlugin)this).Config.Bind<int>("00-General", "maxLabelLength", 32, new ConfigDescription("Maximum label length.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(4, 64), Array.Empty<object>()));
		BoldText = ((BaseUnityPlugin)this).Config.Bind<bool>("01-Display", "bold", false, "Bold label text. Applies to every chest.");
		SmallCapsText = ((BaseUnityPlugin)this).Config.Bind<bool>("01-Display", "smallCaps", true, "Small caps label text. Applies to every chest.");
		FontsDir = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "fonts");
		List<string> list = new List<string> { "Economica-Regular", "Game font" };
		try
		{
			Directory.CreateDirectory(FontsDir);
			ExtractBundledFiles();
			string[] files = Directory.GetFiles(FontsDir);
			foreach (string path in files)
			{
				string text = Path.GetExtension(path).ToLowerInvariant();
				if (text == ".ttf" || text == ".otf")
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
					if (!list.Contains(fileNameWithoutExtension))
					{
						list.Add(fileNameWithoutExtension);
					}
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not read the fonts folder: " + ex.Message));
		}
		FontName = ((BaseUnityPlugin)this).Config.Bind<string>("01-Display", "font", "Economica-Regular", new ConfigDescription("Label font, the same for every chest. 'Economica-Regular' (default) and 'RussoOne-Regular' are shipped with the mod and 'Game font' is the one Valheim uses. To add your own, put .ttf or .otf files in the 'fonts' folder next to ChestTag.dll and restart the game.", (AcceptableValueBase)(object)new AcceptableValueList<string>(list.ToArray()), Array.Empty<object>()));
		OutlineThickness = ((BaseUnityPlugin)this).Config.Bind<float>("01-Display", "outlineThickness", 2.8f, new ConfigDescription("Thickness of the black outline around the label text. 0 turns the outline off, 2.8 is the thickest. Applies to every chest.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2.8f), Array.Empty<object>()));
		Opacity = ((BaseUnityPlugin)this).Config.Bind<float>("01-Display", "opacity", 1f, new ConfigDescription("Opacity of the label (text, outline and icon): 1 is solid, lower is more transparent. Applies to every chest.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
		MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("01-Display", "maxDistance", 30f, new ConfigDescription("Labels farther than this many meters from you are hidden (saves performance in big bases). 0 = always visible.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
		MaxDistance.SettingChanged += OnVisualSettingChanged;
		IconPlacement = ((BaseUnityPlugin)this).Config.Bind<IconPosition>("01-Display", "iconPosition", IconPosition.Below, "Where the icon goes relative to the text: Left, Right, Above or Below. Applies to every chest. With no text, the icon is centered.");
		IconPlacement.SettingChanged += OnVisualSettingChanged;
		string[][] knownTypes = KnownTypes;
		foreach (string[] array in knownTypes)
		{
			Types[array[0]] = BindType("Type: " + array[1], array[2] == "true", float.Parse(array[3], CultureInfo.InvariantCulture), float.Parse(array[4], CultureInfo.InvariantCulture), float.Parse(array[5], CultureInfo.InvariantCulture));
		}
		_other = BindType("Type: Other (unknown or modded chests)", flipped: false, 1.2f, 0f, 0.5f);
		BoldText.SettingChanged += OnVisualSettingChanged;
		SmallCapsText.SettingChanged += OnVisualSettingChanged;
		OutlineThickness.SettingChanged += OnVisualSettingChanged;
		Opacity.SettingChanged += OnVisualSettingChanged;
		FontName.SettingChanged += OnVisualSettingChanged;
		try
		{
			_harmony = new Harmony("DarthVladi.ChestTag");
			_harmony.PatchAll(typeof(ChestTagPlugin).Assembly);
		}
		catch (Exception ex2)
		{
			Log.LogError((object)("Harmony patching failed - Chest Tag is inactive:\n" + ex2));
			return;
		}
		if (Chainloader.PluginInfos.ContainsKey("ChamberLand.chest_label"))
		{
			Log.LogWarning((object)"The 'Chest Label' mod is installed: both mods will draw labels. Disable one of them.");
		}
	}

	private static TypeSettings BindType(string section, bool flipped, float textSize, float offsetY, float iconSize)
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Expected O, but got Unknown
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Expected O, but got Unknown
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Expected O, but got Unknown
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Expected O, but got Unknown
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Expected O, but got Unknown
		ConfigFile config = ((BaseUnityPlugin)Instance).Config;
		TypeSettings typeSettings = new TypeSettings();
		typeSettings.FrontFlipped = config.Bind<bool>(section, "frontIsFlipped", flipped, "Calibration setting. Turn it on if the label shows up on the back of this chest type (the Wardrobe model is built facing the other way). The face names Front, L Side and R Side always refer to the real front.");
		typeSettings.MaxTextSize = config.Bind<float>(section, "maxTextSize", textSize, new ConfigDescription("Maximum text size for this chest type. The text shrinks by itself to fit the face, so lower this on small chests and raise it on big ones.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 4f), Array.Empty<object>()));
		typeSettings.OffsetX = config.Bind<float>(section, "offsetX", 0f, new ConfigDescription("Horizontal label offset as a fraction of the face width (positive = to the right, as seen facing the face).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.2f, 0.2f), Array.Empty<object>()));
		typeSettings.OffsetY = config.Bind<float>(section, "offsetY", offsetY, new ConfigDescription("Vertical label offset as a fraction of the face height (positive = up, -0.3 to 0.4).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.3f, 0.4f), Array.Empty<object>()));
		typeSettings.IconSize = config.Bind<float>(section, "iconSize", iconSize, new ConfigDescription("Icon size for this chest type, as a fraction of the face height.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 0.9f), Array.Empty<object>()));
		typeSettings.IconOffsetX = config.Bind<float>(section, "iconOffsetX", 0f, new ConfigDescription("Moves the icon (only the icon, the text stays) horizontally, as a fraction of the face width (positive = to the right, as seen facing the face).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 0.5f), Array.Empty<object>()));
		typeSettings.IconOffsetY = config.Bind<float>(section, "iconOffsetY", 0f, new ConfigDescription("Moves the icon (only the icon, the text stays) vertically, as a fraction of the face height (positive = up).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 0.5f), Array.Empty<object>()));
		typeSettings.IconSize.SettingChanged += OnVisualSettingChanged;
		typeSettings.IconOffsetX.SettingChanged += OnVisualSettingChanged;
		typeSettings.IconOffsetY.SettingChanged += OnVisualSettingChanged;
		typeSettings.MaxTextSize.SettingChanged += OnVisualSettingChanged;
		typeSettings.FrontFlipped.SettingChanged += OnVisualSettingChanged;
		typeSettings.OffsetX.SettingChanged += OnVisualSettingChanged;
		typeSettings.OffsetY.SettingChanged += OnVisualSettingChanged;
		return typeSettings;
	}

	private static void ExtractBundledFiles()
	{
		Assembly assembly = typeof(ChestTagPlugin).Assembly;
		string[] bundledFiles = BundledFiles;
		foreach (string text in bundledFiles)
		{
			string path = Path.Combine(FontsDir, text);
			if (File.Exists(path))
			{
				continue;
			}
			string[] manifestResourceNames = assembly.GetManifestResourceNames();
			foreach (string text2 in manifestResourceNames)
			{
				if (!text2.EndsWith(text, StringComparison.Ordinal))
				{
					continue;
				}
				using (Stream stream = assembly.GetManifestResourceStream(text2))
				{
					using FileStream destination = File.Create(path);
					stream.CopyTo(destination);
				}
				break;
			}
		}
	}

	internal static string FindFontFile(string name)
	{
		string[] array = new string[4] { ".ttf", ".otf", ".TTF", ".OTF" };
		foreach (string text in array)
		{
			string text2 = Path.Combine(FontsDir, name + text);
			if (File.Exists(text2))
			{
				return text2;
			}
		}
		return null;
	}

	internal static TypeSettings GetTypeSettings(string prefabName)
	{
		if (!Types.TryGetValue(prefabName, out var value))
		{
			return _other;
		}
		return value;
	}

	private static void OnVisualSettingChanged(object sender, EventArgs e)
	{
		ChestLabel.ConfigVersion++;
	}

	private void Update()
	{
		ChestLabel.Tick();
		ChestPatches.CheckKeys();
		ChestPatches.CheckIconKey();
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
		ChestLabel.DestroyAll();
	}
}