Decompiled source of NavCompass v1.0.3

NavCompass.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NavCompass
{
	[BepInPlugin("com.michal.valheim.navcompass", "Nav Compass", "1.0.3")]
	public class NavCompassPlugin : BaseUnityPlugin
	{
		private enum MarkState
		{
			None,
			Strikethrough,
			Circled
		}

		private class PinMarker
		{
			public RectTransform Root;

			public TextMeshProUGUI DistanceText;
		}

		[Serializable]
		private class TrackedPinsSaveData
		{
			public List<Vector3> positions = new List<Vector3>();
		}

		[HarmonyPatch(typeof(Minimap), "OnMapLeftClick")]
		private static class Minimap_OnMapLeftClick_Patch
		{
			private static void Postfix(Minimap __instance)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					Vector3 pointerPosition = ZInput.pointerPosition;
					Vector3 pos = (Vector3)ScreenToWorldPointMethod.Invoke(__instance, new object[1] { pointerPosition });
					float radius = (float)PinInteractRadiusProp.GetValue(__instance);
					PinData val = FindClosestPinAnySave(pos, radius);
					if (val != null)
					{
						_instance?.CycleState(val);
					}
				}
				catch (Exception arg)
				{
					Log.LogError((object)$"Blad przy wykrywaniu kliknietego pinu: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "RemovePin", new Type[]
		{
			typeof(Vector3),
			typeof(float)
		})]
		private static class Minimap_RemovePinAt_Patch
		{
			private static void Prefix()
			{
				_userRemovingPin = true;
			}

			private static void Finalizer()
			{
				_userRemovingPin = false;
			}
		}

		[HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(PinData) })]
		private static class Minimap_RemovePin_Patch
		{
			private static void Prefix(PinData pin)
			{
				if (_userRemovingPin && pin != null)
				{
					_instance?.ForgetPin(pin);
				}
			}
		}

		private class CardinalTag : MonoBehaviour
		{
			public float Bearing;
		}

		public const string PluginGUID = "com.michal.valheim.navcompass";

		public const string PluginName = "Nav Compass";

		public const string PluginVersion = "1.0.3";

		private const float StripWidth = 480f;

		private const float StripHeight = 36f;

		private const float MarkerIconSize = 18f;

		private const float MarkerLabelMaxWidth = 140f;

		private const float StripHalfFovDeg = 90f;

		private const float FramePadding = 6f;

		private static readonly Color ValheimOrange = new Color(1f, 0.631f, 0.235f, 1f);

		private static readonly Color ValheimBeige = new Color(0.8529f, 0.725f, 0.5331f, 1f);

		private const float PositionMatchTolerance = 1f;

		private const float PendingResolveInterval = 1f;

		private static readonly FieldInfo PinsField = AccessTools.Field(typeof(Minimap), "m_pins");

		private static readonly MethodInfo ScreenToWorldPointMethod = AccessTools.Method(typeof(Minimap), "ScreenToWorldPoint", (Type[])null, (Type[])null);

		private static readonly PropertyInfo PinInteractRadiusProp = AccessTools.Property(typeof(Minimap), "PinInteractRadius");

		internal static ManualLogSource Log;

		private static NavCompassPlugin _instance;

		private readonly Dictionary<PinData, MarkState> _pinStates = new Dictionary<PinData, MarkState>();

		private readonly Dictionary<PinData, GameObject> _overlayByPin = new Dictionary<PinData, GameObject>();

		private readonly Dictionary<PinData, PinMarker> _compassMarkers = new Dictionary<PinData, PinMarker>();

		private readonly List<Vector3> _pendingCircled = new List<Vector3>();

		private float _nextPendingResolve;

		private static bool _userRemovingPin;

		private GameObject _rootGo;

		private RectTransform _stripRect;

		private readonly Dictionary<string, RectTransform> _cardinalMarkers = new Dictionary<string, RectTransform>();

		private TMP_FontAsset _font;

		private Sprite _ringSprite;

		private bool _uiBuilt;

		private bool _faulted;

		private bool _savedStateLoaded;

		private string _currentWorldName;

		private static string _saveDir;

		private string _savePath;

		private const string LegacyPluginFolder = "Mod6-NavCompass";

		private Material _woodLetterMaterial;

		private bool _woodLetterMaterialTried;

		private const string AutoWaypointsGuid = "com.michal.valheim.autowaypoints";

		private Func<PinData, bool> _isPinLabelVisible;

		private bool _labelVisibilityResolved;

		private IEnumerable<PinData> CircledPins => from kv in _pinStates
			where kv.Value == MarkState.Circled
			select kv.Key;

		private static string SaveDir => _saveDir ?? (_saveDir = Directory.CreateDirectory(Path.Combine(Paths.ConfigPath, "NavCompass")).FullName);

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Game.isModded = true;
			_instance = this;
			new Harmony("com.michal.valheim.navcompass").PatchAll(typeof(NavCompassPlugin).Assembly);
		}

		private void Update()
		{
			if (_faulted)
			{
				return;
			}
			try
			{
				RunUpdate();
			}
			catch (Exception arg)
			{
				_faulted = true;
				if ((Object)(object)_rootGo != (Object)null)
				{
					_rootGo.SetActive(false);
				}
				Log.LogError((object)$"Nav Compass wylaczony po nieoczekiwanym bledzie (zeby nie zapychac logu/FPS): {arg}");
			}
		}

		private void RunUpdate()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Invalid comparison between Unknown and I4
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				if ((Object)(object)_rootGo != (Object)null)
				{
					_rootGo.SetActive(false);
				}
				_savedStateLoaded = false;
				return;
			}
			if (!_uiBuilt)
			{
				_ringSprite = CreateRingSprite();
				BuildUi();
				_uiBuilt = true;
			}
			if (!_savedStateLoaded)
			{
				TryLoadTrackedPins();
			}
			if ((Object)(object)Minimap.instance != (Object)null && (int)Minimap.instance.m_mode == 2)
			{
				ResyncOverlays();
			}
			UpdateCompass();
		}

		private TMP_FontAsset GetFont()
		{
			if ((Object)(object)_font != (Object)null)
			{
				return _font;
			}
			TextMeshProUGUI val = Object.FindObjectOfType<TextMeshProUGUI>();
			if ((Object)(object)val != (Object)null && (Object)(object)((TMP_Text)val).font != (Object)null)
			{
				_font = ((TMP_Text)val).font;
				return _font;
			}
			if ((Object)(object)TMP_Settings.defaultFontAsset != (Object)null)
			{
				_font = TMP_Settings.defaultFontAsset;
				return _font;
			}
			_font = Resources.FindObjectsOfTypeAll<TMP_FontAsset>().FirstOrDefault();
			return _font;
		}

		private static PinData FindClosestPinAnySave(Vector3 pos, float radius)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!(PinsField.GetValue(Minimap.instance) is List<PinData> list))
			{
				return null;
			}
			PinData result = null;
			float num = radius;
			foreach (PinData item in list)
			{
				if (!((Object)(object)item.m_uiElement == (Object)null) && ((Component)item.m_uiElement).gameObject.activeInHierarchy)
				{
					float num2 = pos.x - item.m_pos.x;
					float num3 = pos.z - item.m_pos.z;
					float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3);
					if (num4 < num)
					{
						result = item;
						num = num4;
					}
				}
			}
			return result;
		}

		private void CycleState(PinData pin)
		{
			_pinStates.TryGetValue(pin, out var value);
			MarkState markState = (MarkState)((int)(value + 1) % 3);
			if (markState == MarkState.None)
			{
				_pinStates.Remove(pin);
			}
			else
			{
				_pinStates[pin] = markState;
			}
			pin.m_checked = markState == MarkState.Strikethrough;
			if (_overlayByPin.TryGetValue(pin, out var value2))
			{
				if ((Object)(object)value2 != (Object)null)
				{
					Object.Destroy((Object)(object)value2);
				}
				_overlayByPin.Remove(pin);
			}
			if (markState == MarkState.Circled)
			{
				GameObject val = CreateRingOverlay(pin);
				if ((Object)(object)val != (Object)null)
				{
					_overlayByPin[pin] = val;
				}
			}
			Log.LogInfo((object)$"Pin '{pin.m_name}': {markState}");
			SaveTrackedPins();
		}

		private GameObject CreateRingOverlay(PinData pin)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0095: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			if ((Object)(object)pin.m_uiElement == (Object)null || (Object)(object)_ringSprite == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("MarkRing", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)pin.m_uiElement, false);
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).raycastTarget = false;
			obj.sprite = _ringSprite;
			((Graphic)obj).color = new Color(0.45f, 0.8f, 1f, 0.95f);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(36f, 36f);
			val.transform.SetAsFirstSibling();
			return val;
		}

		private void RemoveDeletedPins()
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if (_pinStates.Count == 0)
			{
				return;
			}
			List<PinData> list = PinsField.GetValue(Minimap.instance) as List<PinData>;
			HashSet<PinData> alive = ((list != null) ? new HashSet<PinData>(list) : new HashSet<PinData>());
			foreach (PinData item in _pinStates.Keys.Where((PinData p) => !alive.Contains(p)).ToList())
			{
				if (_pinStates[item] == MarkState.Circled)
				{
					_pendingCircled.Add(item.m_pos);
				}
				DropPinState(item);
			}
		}

		private void ForgetPin(PinData pin)
		{
			if (_pinStates.TryGetValue(pin, out var value))
			{
				DropPinState(pin);
				if (value == MarkState.Circled)
				{
					SaveTrackedPins();
				}
			}
		}

		private void DropPinState(PinData pin)
		{
			_pinStates.Remove(pin);
			if (_overlayByPin.TryGetValue(pin, out var value))
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
				_overlayByPin.Remove(pin);
			}
		}

		private void MarkCircled(PinData pin)
		{
			if (!_pinStates.TryGetValue(pin, out var value) || value != MarkState.Circled)
			{
				_pinStates[pin] = MarkState.Circled;
				pin.m_checked = false;
				GameObject val = CreateRingOverlay(pin);
				if ((Object)(object)val != (Object)null)
				{
					_overlayByPin[pin] = val;
				}
			}
		}

		private void ResolvePendingPins()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (_pendingCircled.Count == 0 || Time.time < _nextPendingResolve)
			{
				return;
			}
			_nextPendingResolve = Time.time + 1f;
			if (!(PinsField.GetValue(Minimap.instance) is List<PinData> source))
			{
				return;
			}
			for (int num = _pendingCircled.Count - 1; num >= 0; num--)
			{
				Vector3 pos = _pendingCircled[num];
				PinData val = ((IEnumerable<PinData>)source).FirstOrDefault((Func<PinData, bool>)((PinData p) => Vector3.Distance(p.m_pos, pos) < 1f));
				if (val != null)
				{
					_pendingCircled.RemoveAt(num);
					MarkCircled(val);
					Log.LogInfo((object)("Oznaczony pin '" + val.m_name + "' jest na mapie."));
				}
			}
		}

		private void ResyncOverlays()
		{
			foreach (PinData item in CircledPins.ToList())
			{
				if (!_overlayByPin.TryGetValue(item, out var value) || (Object)(object)value == (Object)null || (Object)(object)value.transform.parent != (Object)(object)item.m_uiElement)
				{
					if ((Object)(object)value != (Object)null)
					{
						Object.Destroy((Object)(object)value);
					}
					_overlayByPin.Remove(item);
					GameObject val = CreateRingOverlay(item);
					if ((Object)(object)val != (Object)null)
					{
						_overlayByPin[item] = val;
					}
				}
			}
		}

		private static Sprite CreateRingSprite()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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)
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(32f, 32f);
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					float num = Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), val2);
					float num2 = ((num <= 28f && num >= 25f) ? 1f : 0f);
					if (num > 27f && num < 29f)
					{
						num2 = Mathf.Clamp01(28f - num + 0.5f);
					}
					if (num > 24f && num < 26f)
					{
						num2 = Mathf.Clamp01(num - 25f + 0.5f);
					}
					val.SetPixel(j, i, new Color(1f, 1f, 1f, num2));
				}
			}
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
		}

		private static string SafeFileName(string name)
		{
			return string.Join("_", name.Split(Path.GetInvalidFileNameChars()));
		}

		private static string CurrentCharacter()
		{
			PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null);
			if (val == null)
			{
				return null;
			}
			if (string.IsNullOrEmpty(val.m_filename))
			{
				return val.GetName();
			}
			return val.m_filename;
		}

		private static string SaveFilePath(string worldName, string character)
		{
			string text = Path.Combine(SaveDir, "tracked_" + SafeFileName(worldName) + "_" + SafeFileName(character) + ".json");
			if (!File.Exists(text))
			{
				TakeOverWorldFile(worldName, text);
			}
			return text;
		}

		private void SaveTrackedPins()
		{
			try
			{
				if (_savePath != null)
				{
					TrackedPinsSaveData trackedPinsSaveData = new TrackedPinsSaveData
					{
						positions = CircledPins.Select((PinData p) => p.m_pos).Concat(_pendingCircled).ToList()
					};
					File.WriteAllText(_savePath, JsonUtility.ToJson((object)trackedPinsSaveData));
				}
			}
			catch (Exception arg)
			{
				Log.LogWarning((object)$"Nie udalo sie zapisac oznaczonych pinow: {arg}");
			}
		}

		private static IEnumerable<string> LegacySaveDirs()
		{
			yield return SaveDir;
			yield return Path.GetDirectoryName(typeof(NavCompassPlugin).Assembly.Location);
			yield return Path.Combine(Paths.PluginPath, "Mod6-NavCompass");
		}

		private static void TakeOverWorldFile(string worldName, string path)
		{
			string fileName = "tracked_" + SafeFileName(worldName) + ".json";
			List<string> list = (from dir in LegacySaveDirs()
				select Path.Combine(dir, fileName)).Where(File.Exists).ToList();
			if (list.Count == 0)
			{
				return;
			}
			try
			{
				File.Copy(list[0], path);
				foreach (string item in list)
				{
					string text = item + ".migrated";
					if (File.Exists(text))
					{
						File.Delete(text);
					}
					File.Move(item, text);
				}
				Log.LogInfo((object)("Oznaczenia wspolne dla swiata przejete przez postac: " + list[0] + " -> " + path));
			}
			catch (Exception arg)
			{
				Log.LogWarning((object)$"Nie udalo sie przejac wspolnych oznaczen swiata ({list[0]}): {arg}");
			}
		}

		private void TryLoadTrackedPins()
		{
			ZNet instance = ZNet.instance;
			string text = ((instance != null) ? instance.GetWorldName() : null);
			string text2 = CurrentCharacter();
			if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2))
			{
				return;
			}
			_currentWorldName = text;
			_savedStateLoaded = true;
			foreach (PinData item in _pinStates.Keys.ToList())
			{
				DropPinState(item);
			}
			_pendingCircled.Clear();
			string path = (_savePath = SaveFilePath(text, text2));
			if (!File.Exists(path))
			{
				return;
			}
			try
			{
				TrackedPinsSaveData trackedPinsSaveData = JsonUtility.FromJson<TrackedPinsSaveData>(File.ReadAllText(path));
				if (trackedPinsSaveData?.positions != null)
				{
					_pendingCircled.AddRange(trackedPinsSaveData.positions);
					_nextPendingResolve = 0f;
					ResolvePendingPins();
					Log.LogInfo((object)($"Wczytano {trackedPinsSaveData.positions.Count} oznaczonych pinow dla swiata '{text}' " + $"({_pendingCircled.Count} czeka na swoj pin na mapie)."));
				}
			}
			catch (Exception arg)
			{
				Log.LogWarning((object)$"Nie udalo sie wczytac oznaczonych pinow: {arg}");
			}
		}

		private void BuildUi()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: 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_0427: Unknown result type (might be due to invalid IL or missing references)
			//IL_043d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			_rootGo = new GameObject("NavCompassRose");
			Object.DontDestroyOnLoad((Object)(object)_rootGo);
			Canvas obj = _rootGo.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 100;
			CanvasScaler obj2 = _rootGo.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			_rootGo.AddComponent<GraphicRaycaster>();
			GameObject val = new GameObject("StripFrame", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(_rootGo.transform, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 1f);
			component.anchorMax = new Vector2(0.5f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = new Vector2(0f, -10f);
			component.sizeDelta = new Vector2(492f, 48f);
			ApplyWoodFrameStyle(val.AddComponent<Image>(), component.sizeDelta.y);
			GameObject val2 = new GameObject("StripBg", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent((Transform)(object)component, false);
			_stripRect = val2.GetComponent<RectTransform>();
			_stripRect.anchorMin = new Vector2(0.5f, 0.5f);
			_stripRect.anchorMax = new Vector2(0.5f, 0.5f);
			_stripRect.pivot = new Vector2(0.5f, 0.5f);
			_stripRect.anchoredPosition = Vector2.zero;
			_stripRect.sizeDelta = new Vector2(480f, 36f);
			val2.AddComponent<RectMask2D>();
			GameObject val3 = new GameObject("CenterTick");
			val3.transform.SetParent((Transform)(object)_stripRect, false);
			((Graphic)val3.AddComponent<Image>()).color = ValheimOrange;
			RectTransform component2 = val3.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0.5f, 0f);
			component2.anchorMax = new Vector2(0.5f, 1f);
			component2.pivot = new Vector2(0.5f, 0.5f);
			component2.sizeDelta = new Vector2(2f, 0f);
			component2.anchoredPosition = Vector2.zero;
			(string, float)[] array = new(string, float)[8]
			{
				("N", 0f),
				("NE", 45f),
				("E", 90f),
				("SE", 135f),
				("S", 180f),
				("SW", 225f),
				("W", 270f),
				("NW", 315f)
			};
			for (int i = 0; i < array.Length; i++)
			{
				(string, float) tuple = array[i];
				string item = tuple.Item1;
				float item2 = tuple.Item2;
				GameObject val4 = new GameObject("Cardinal_" + item);
				val4.transform.SetParent((Transform)(object)_stripRect, false);
				TextMeshProUGUI val5 = val4.AddComponent<TextMeshProUGUI>();
				TMP_FontAsset font = GetFont();
				if ((Object)(object)font != (Object)null)
				{
					((TMP_Text)val5).font = font;
				}
				((TMP_Text)val5).text = item;
				((TMP_Text)val5).fontSize = ((item.Length == 1) ? 15f : 11f);
				((TMP_Text)val5).alignment = (TextAlignmentOptions)514;
				((Graphic)val5).color = (Color)((item == "N") ? new Color(1f, 0.3f, 0.3f) : ValheimBeige);
				if (item.Length == 1)
				{
					StyleAsWoodLetter(val5, item == "N");
				}
				RectTransform component3 = val4.GetComponent<RectTransform>();
				component3.anchorMin = new Vector2(0.5f, 0.5f);
				component3.anchorMax = new Vector2(0.5f, 0.5f);
				component3.pivot = new Vector2(0.5f, 0.5f);
				component3.sizeDelta = new Vector2(40f, 36f);
				_cardinalMarkers[item] = component3;
				((Component)component3).gameObject.AddComponent<CardinalTag>().Bearing = item2;
			}
		}

		private static void ApplyWoodFrameStyle(Image image, float frameHeight)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			Sprite val = ((IEnumerable<Sprite>)Resources.FindObjectsOfTypeAll<Sprite>()).FirstOrDefault((Func<Sprite, bool>)((Sprite s) => ((Object)s).name == "woodpanel_trophys"));
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)"Nie znaleziono grafiki 'woodpanel_trophys' w zasobach gry - kompas zostaje na zwyklym, polprzezroczystym tle.");
				((Graphic)image).color = new Color(0f, 0f, 0f, 0.25f);
				return;
			}
			image.sprite = val;
			image.type = (Type)1;
			((Graphic)image).color = Color.white;
			Material val2 = ((IEnumerable<Material>)Resources.FindObjectsOfTypeAll<Material>()).FirstOrDefault((Func<Material, bool>)((Material m) => ((Object)m).name == "litpanel"));
			if ((Object)(object)val2 != (Object)null)
			{
				((Graphic)image).material = val2;
			}
			float num = val.border.y + val.border.w;
			if (num > 0f)
			{
				float num2 = num * 100f / (val.pixelsPerUnit * 0.5f * frameHeight);
				image.pixelsPerUnitMultiplier = Mathf.Max(1f, num2);
			}
		}

		private void StyleAsWoodLetter(TextMeshProUGUI txt, bool north)
		{
			//IL_00a8: 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)
			TMP_FontAsset val = ((IEnumerable<TMP_FontAsset>)(from f in Resources.FindObjectsOfTypeAll<TMP_FontAsset>()
				orderby ((Object)f).name.IndexOf("Norsebold", StringComparison.OrdinalIgnoreCase) >= 0 descending
				select f)).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => ((Object)f).name.IndexOf("Norse", StringComparison.OrdinalIgnoreCase) >= 0));
			if ((Object)(object)val != (Object)null)
			{
				((TMP_Text)txt).font = val;
			}
			Material woodLetterMaterial = GetWoodLetterMaterial(((TMP_Text)txt).font);
			if (!((Object)(object)woodLetterMaterial == (Object)null))
			{
				((TMP_Text)txt).fontSharedMaterial = woodLetterMaterial;
				((TMP_Text)txt).fontSize = 20f;
				((TMP_Text)txt).extraPadding = true;
				((Graphic)txt).color = (Color)(north ? new Color(1f, 0.55f, 0.45f) : Color.white);
			}
		}

		private Material GetWoodLetterMaterial(TMP_FontAsset font)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			if (_woodLetterMaterialTried)
			{
				return _woodLetterMaterial;
			}
			_woodLetterMaterialTried = true;
			Shader val = Shader.Find("TextMeshPro/Distance Field");
			if ((Object)(object)font == (Object)null || (Object)(object)((TMP_Asset)font).material == (Object)null || (Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)"Kompas: brak czcionki albo shadera 'TextMeshPro/Distance Field' - litery N/E/S/W bez drewna.");
				return null;
			}
			Material val2 = new Material(((TMP_Asset)font).material)
			{
				name = "NavCompassWoodLetters",
				shader = val
			};
			string text = ApplyWoodFaceTexture(val2);
			val2.SetColor("_FaceColor", Color.white);
			val2.SetFloat("_FaceDilate", 0.1f);
			val2.SetFloat("_OutlineWidth", 0.25f);
			val2.SetColor("_OutlineColor", new Color(0.16f, 0.09f, 0.04f, 1f));
			val2.EnableKeyword("UNDERLAY_ON");
			val2.SetColor("_UnderlayColor", new Color(0f, 0f, 0f, 0.6f));
			val2.SetFloat("_UnderlayOffsetX", 0.4f);
			val2.SetFloat("_UnderlayOffsetY", -0.4f);
			val2.SetFloat("_UnderlaySoftness", 0.3f);
			ShaderUtilities.UpdateShaderRatios(val2);
			Log.LogInfo((object)("Kompas: drewniane litery N/E/S/W - czcionka '" + ((Object)font).name + "', drewno: " + text + "."));
			_woodLetterMaterial = val2;
			return val2;
		}

		private static string ApplyWoodFaceTexture(Material material)
		{
			//IL_004f: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00c3: 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_00ee: 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)
			//IL_010b: 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_0152: 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_016d: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = ((IEnumerable<Texture2D>)Resources.FindObjectsOfTypeAll<Texture2D>()).FirstOrDefault((Func<Texture2D, bool>)((Texture2D t) => ((Object)t).name == "Planks1c"));
			if ((Object)(object)val != (Object)null)
			{
				material.SetTexture("_FaceTex", (Texture)(object)val);
				material.SetTextureScale("_FaceTex", new Vector2(1f, 0.5f));
				material.SetTextureOffset("_FaceTex", Vector2.zero);
				return "Planks1c";
			}
			Sprite val2 = ((IEnumerable<Sprite>)Resources.FindObjectsOfTypeAll<Sprite>()).FirstOrDefault((Func<Sprite, bool>)((Sprite s) => ((Object)s).name == "woodpanel_trophys"));
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.texture != (Object)null)
			{
				Rect textureRect = val2.textureRect;
				Vector4 border = val2.border;
				float num = ((Texture)val2.texture).width;
				float num2 = ((Texture)val2.texture).height;
				float num3 = (((Rect)(ref textureRect)).width - border.x - border.z) * 0.3f;
				float num4 = (((Rect)(ref textureRect)).height - border.y - border.w) * 0.3f;
				material.SetTexture("_FaceTex", (Texture)(object)val2.texture);
				material.SetTextureScale("_FaceTex", new Vector2(num3 / num, num4 / num2));
				material.SetTextureOffset("_FaceTex", new Vector2((((Rect)(ref textureRect)).x + border.x) / num, (((Rect)(ref textureRect)).y + border.y) / num2));
				return "woodpanel_trophys (Planks1c niedostepne)";
			}
			return "BRAK (ani Planks1c, ani woodpanel_trophys) - litery w kolorze drewna bez slojow";
		}

		private void UpdateCompass()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_rootGo == (Object)null)
			{
				return;
			}
			_rootGo.SetActive(true);
			Vector3 position = ((Component)Player.m_localPlayer).transform.position;
			Camera val = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).GetComponent<Camera>() : null);
			Vector3 val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform.forward : ((Component)Player.m_localPlayer).transform.forward);
			float playerYawDeg = Mathf.Atan2(val2.x, val2.z) * 57.29578f;
			foreach (KeyValuePair<string, RectTransform> cardinalMarker in _cardinalMarkers)
			{
				float bearing = ((Component)cardinalMarker.Value).GetComponent<CardinalTag>().Bearing;
				PositionOnStrip(cardinalMarker.Value, bearing, playerYawDeg);
			}
			RemoveDeletedPins();
			ResolvePendingPins();
			List<PinData> circledNow = CircledPins.ToList();
			foreach (PinData item in _compassMarkers.Keys.Where((PinData p) => !circledNow.Contains(p)).ToList())
			{
				if ((Object)(object)_compassMarkers[item].Root != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)_compassMarkers[item].Root).gameObject);
				}
				_compassMarkers.Remove(item);
			}
			foreach (PinData item2 in circledNow)
			{
				if (!_compassMarkers.TryGetValue(item2, out var value))
				{
					value = CreateCompassMarker(item2);
					if (value == null)
					{
						continue;
					}
					_compassMarkers[item2] = value;
				}
				Vector3 val3 = item2.m_pos - position;
				float magnitude = ((Vector3)(ref val3)).magnitude;
				float bearingDeg = Mathf.Atan2(val3.x, val3.z) * 57.29578f;
				bool active = PositionOnStrip(value.Root, bearingDeg, playerYawDeg);
				((Component)value.Root).gameObject.SetActive(active);
				string text = VisiblePinName(item2);
				((TMP_Text)value.DistanceText).text = ((text == null) ? FormatDistance(magnitude) : (text + " " + FormatDistance(magnitude)));
			}
		}

		private string VisiblePinName(PinData pin)
		{
			if (string.IsNullOrEmpty(pin.m_name))
			{
				return null;
			}
			if (!_labelVisibilityResolved)
			{
				_labelVisibilityResolved = true;
				_isPinLabelVisible = ResolveLabelVisibility();
			}
			if (_isPinLabelVisible != null && !_isPinLabelVisible(pin))
			{
				return null;
			}
			if (Localization.instance == null)
			{
				return pin.m_name;
			}
			return Localization.instance.Localize(pin.m_name);
		}

		private static Func<PinData, bool> ResolveLabelVisibility()
		{
			if (!Chainloader.PluginInfos.TryGetValue("com.michal.valheim.autowaypoints", out var value) || (Object)(object)value.Instance == (Object)null)
			{
				return null;
			}
			MethodInfo method = ((object)value.Instance).GetType().GetMethod("IsPinLabelVisible", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(PinData) }, null);
			if (method == null || method.ReturnType != typeof(bool))
			{
				Log.LogWarning((object)"Auto Waypoints nie udostepnia IsPinLabelVisible (starsza wersja?) - nazwy pinow na kompasie pokazywane zawsze.");
				return null;
			}
			Log.LogInfo((object)"Nazwy pinow na kompasie wedlug ustawien podpisow z Auto Waypoints.");
			return (Func<PinData, bool>)Delegate.CreateDelegate(typeof(Func<PinData, bool>), value.Instance, method);
		}

		private PinMarker CreateCompassMarker(PinData pin)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0040: 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_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_0094: 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_00be: 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_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_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("PinMarker_" + pin.m_name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)_stripRect, false);
			GameObject val2 = new GameObject("Icon");
			val2.transform.SetParent(val.transform, false);
			Image obj = val2.AddComponent<Image>();
			obj.sprite = pin.m_icon;
			obj.preserveAspect = true;
			RectTransform component = val2.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 1f);
			component.anchorMax = new Vector2(0.5f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.sizeDelta = new Vector2(18f, 18f);
			component.anchoredPosition = new Vector2(0f, -2f);
			float num = 16f;
			GameObject val3 = new GameObject("Dist");
			val3.transform.SetParent(val.transform, false);
			TextMeshProUGUI val4 = val3.AddComponent<TextMeshProUGUI>();
			TMP_FontAsset font = GetFont();
			if ((Object)(object)font != (Object)null)
			{
				((TMP_Text)val4).font = font;
			}
			((TMP_Text)val4).fontSize = 13f;
			((TMP_Text)val4).enableAutoSizing = true;
			((TMP_Text)val4).fontSizeMin = 10f;
			((TMP_Text)val4).fontSizeMax = 13f;
			((TMP_Text)val4).fontStyle = (FontStyles)1;
			((TMP_Text)val4).alignment = (TextAlignmentOptions)514;
			((Graphic)val4).color = new Color(1f, 0.93f, 0.75f);
			((TMP_Text)val4).outlineWidth = 0.2f;
			((TMP_Text)val4).outlineColor = new Color32((byte)20, (byte)12, (byte)5, byte.MaxValue);
			((TMP_Text)val4).overflowMode = (TextOverflowModes)1;
			((Graphic)val4).raycastTarget = false;
			RectTransform component2 = val3.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0.5f, 0f);
			component2.anchorMax = new Vector2(0.5f, 0f);
			component2.pivot = new Vector2(0.5f, 0f);
			component2.sizeDelta = new Vector2(140f, num);
			component2.anchoredPosition = new Vector2(0f, 1f);
			RectTransform component3 = val.GetComponent<RectTransform>();
			component3.anchorMin = new Vector2(0.5f, 0.5f);
			component3.anchorMax = new Vector2(0.5f, 0.5f);
			component3.pivot = new Vector2(0.5f, 0.5f);
			component3.sizeDelta = new Vector2(140f, 36f);
			return new PinMarker
			{
				Root = component3,
				DistanceText = val4
			};
		}

		private static bool PositionOnStrip(RectTransform rect, float bearingDeg, float playerYawDeg)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.DeltaAngle(playerYawDeg, bearingDeg);
			bool result = Mathf.Abs(num) <= 90f;
			float num2 = num / 90f * 240f;
			rect.anchoredPosition = new Vector2(num2, rect.anchoredPosition.y);
			return result;
		}

		private static string FormatDistance(float meters)
		{
			if (!(meters >= 1000f))
			{
				return $"{Mathf.RoundToInt(meters)}m";
			}
			return $"{meters / 1000f:0.0}km";
		}
	}
}